Universal Feed API
  • 17 Aug 2023
  • 11 Minutes to read
  • Dark
    Light
  • PDF

Universal Feed API

  • Dark
    Light
  • PDF

Article Summary

Like the package format, this was designed with simplicity in mind. Because universal packages are designed to be consumed by any language or platform, the API offers several different ways to do the same thing, as some operations are much more difficult in some languages than others.

The API consists of a few different URL endpoints, accessible over HTTP/S. If configured, they can be secured using Integrated Windows Authentication or Basic Authentication using whatever granular feed- or system-level privileges needed.

In ProGet, all endpoints are prefixed with /upack/«feed-name».

Endpoint Note
Note that the endpoint prefix itself is not a valid API endpoint, and may return some sort of "this is not the endpoint you are looking for" Star Wars memepic, or simply redirect you to this page.


Currently, the API only returns results in JSON format with a standard, 200 (success) status code unless there's an error; future versions (if anyone requests it) may add additional formats, such as XML, which would be specified using a Content-Type request headers and/or an alternate querystring parameter.


All searching and matching is case insensitive. This will most certainly never change, as it's either a mistake or a bad practice to have different packages named SomeThing and someThing.

List Packages Endpoint

GET /upack/«feed-name»/packages?group=«group»&name=«name»&count=«count»

Returns either a JSON object (if name is specified) or a JSON array of objects of package metadata, mostly from the latest package version.

ParameterDescription
groupOptional. If specified without name, returns an array of packages with a matching group name or an empty array.
nameOptional. If specified, returns an object with a matching name and group or a 404 status with an error message in the body.
countOptional. If specified, returns an array with at most as many entries as specified; otherwise, at most 1000 packages are returned. This is ignored if name is specified.

Following are some example request/responses:

 GET /upack/dev-feed/packages?name=hdars

{
 "name": "HDARS",
 "downloads": "1",
 "versions": ["0.0.22", "1.3.9", "1.3.10"]
}

 

GET /upack/dev-feed/packages?count=1000

[
  {
   "name": "HDARS",
   "latestVersion": "1.3.9",
   "downloads": "1",
   "versions": ["0.0.22", "1.3.7", "1.3.9"]
  },
  {
   "group": "initrode/vendors/abl",
   "name": "ABLast",
   "latestVersion": "2.2.1",
   "title": "ast distribution files for ABL",
   "icon": "package://ablast.svg",
   "description": "This contains [ast distro](http://initrode-net.local/ast) files specific to ABL",
   "downloads":"55",
   "versions": ["2.2.1"]
  },
  {
   "group": "virtudyne/simdesk",
   "name": "var-index-service",
   "latestVersion": "5.3.10",
   "_sourceRoot": "$/global/vindex/branches/v5-hotfix"
   "_deployTarget": "/var/vsimdesk/vindex",
   "downloads":"17",
   "versions": ["5.0.0","5.2.1","5.3.10"]
 }
]


GET /upack/dev-feed/packages?group=initrode/vendors/abl

[
  {
   "group": "initrode/vendors/abl",
   "name": "ABLast",
   "latestVersion": "2.2.1",
   "title": "ast distribution files for ABL",
   "icon": "package://ablast.svg",
   "description": "This contains [ast distro](http://initrode-net.local/ast) files specific to ABL",
   "downloads":"55",
   "versions": ["2.2.1"]
  }
]

To return the packages in the empty group, specify the group parameter without a value (e.g. /upack/dev-feed/packages?group=)


Note that specifying the name parameter will cause an object to be returned instead of an array; if you don't specify a group, then packages in the empty group will be searched

Note that the group parameter must be a full match; future versions of this endpoint may allow for a sub-group searching (such as groupName* or something).

List Versions Endpoint

GET /upack/«feed-name»/versions?group=«group»&name=«name» &version=«version»&includeFileList=«includeFileList»&count=«count»

Returns either a JSON object or a JSON array of objects containing metadata about specific package versions.

ParameterDescription
groupOptional. If specified without version, returns an array of packages with a matching group name or an empty array.
nameOptional. If specified without version, returns an array of packages with a matching group name or an empty array.
versionOptional. If specified, returns an object with a matching group, name, and version, or a 404 status with an error message in the body.
includeFileListOptional. If true, then inspects each package returned and includes a list of files in the body.
countOptional. If specified, returns an array with at most as many entries as specified; otherwise, at most 1000 packages are returned. This is ignored if name is specified.

Following are some example request/responses:

 

GET /upack/dev-feed/versions?name=hdars&version=1.3.9

{
 "name": "HDARS",
 "version": "1.3.9",
 "downloads": "1",
 "published": "2016-01-07T06:51:51.403Z",
 "isLocal": true,
 "isCached": false,
 "isVirtual": false
}

 

GET /upack/dev-feed/versions?count=1000

[
  {
   "name": "HDARS",
   "version": "0.0.22",
   "downloads": "133",
   "published": "2016-01-01T06:51:51.403Z",
   "isLocal": true,
   "isCached": false,
   "isVirtual": false
  },
  {
   "name": "HDARS",
   "version": "1.3.7",
   "downloads": "21",
   "published": "2016-01-05T06:51:51.403Z",
   "isLocal": true,
   "isCached": false,
   "isVirtual": false
  },
  {
   "name": "HDARS",
   "version": "1.3.9",
   "downloads": "1",
   "published": "2016-01-07T06:51:51.403Z",
   "isLocal": true,
   "isCached": false,
   "isVirtual": false
  },
  {
   "group": "initrode/vendors/abl",
   "name": "ABLast",
   "version": "2.2.1",
   "title": "ast distribution files for ABL",
   "icon": "package://ablast.svg",
   "description": "This contains [ast distro](http://initrode-net.local/ast) files specific to ABL",
   "dependencies": [ "initrode/vendors-common:ast-common:2.0.0" ]
   "downloads":"55",
   "isLocal": false,
   "isCached": true,
   "isVirtual": false
  },
  {
   "group": "virtudyne/simdesk",
   "name": "var-index-service",
   "version": "5.0.10",
   "_sourceRoot": "$/global/vindex/root"
   "_deployTarget": "/var/vsimdesk/vindex/newv5",
   "downloads":"18",
   "isLocal": true,
   "isCached": false,
   "isVirtual": false
  },
  {
   "group": "virtudyne/simdesk",
   "name": "var-index-service",
   "version": "5.2.1",
   "_sourceRoot": "$/global/vindex/branches/5.2"
   "_deployTarget": "/var/vsimdesk/vindex/2tmp",
   "downloads":"18",
   "isLocal": true,
   "isCached": false,
   "isVirtual": false
  },
  {
   "group": "virtudyne/simdesk",
   "name": "var-index-service",
   "version": "5.3.10",
   "_sourceRoot": "$/global/vindex/branches/v5-hotfix"
   "_deployTarget": "/var/vsimdesk/vindex",
   "downloads":"17",
   "isLocal": true,
   "isCached": false,
   "isVirtual": false
  }
]


GET /upack/dev-feed/versions?name=hdars&version=1.3.9&includeFileList=true

{
 "name": "HDARS",
 "version": "1.3.9",
 "downloads": "1",
 "published": "2016-01-07T06:51:51.403Z",
 "isLocal": true,
 "isCached": false,
 "isVirtual": false
 "fileList": [
    { "name": "assets/muth.png", 
      "date": "2015-01-01T01:52:51.403Z", 
      "size": 68012 },
    { "name": "assets/styles.css", 
      "date": "2015-01-01T01:52:51.403Z", 
      "size": 3021 },
    { "name": "index.htm", 
      "date": "2015-01-01T01:52:51.403Z", 
      "size": 1028 }
 ]
}

 




Note that the group parameter must be a full match; future versions of this endpoint may allow for a sub-group searching (such as groupName* or something), if anyone requests.

Download Package Endpoint

Specific Version

GET /upack/«feed-name»/download/«group-name»/«package-name»/«package-version»?contentOnly=«zip|tgz»

Latest Version

GET /upack/«feed-name»/download/«group-name»/«package-name»?contentOnly=«zip|tgz»&latest

Returns either a package file, the contents of a package, or an error.

ParameterDescription
group-nameOptional. If not specified, the empty group will be searched.
package-nameRequired.
package-versionOptional. If a specific version is not specified, "latest" must be supplied as a query string argument, or a 400 will be returned.
contentOnlyOptional. If specified, the contents of /package directory are returned as either a ZIP archive (default if no value is specified for the parameter) or TGZ archive.

Following are some example request/responses:

GET /upack/dev-feed/download/hdars/1.3.9

Response:

  • Header: Content-Type: application/zip
  • Header: Content-Disposition: attachment; filename=hdars.1.3.9.upack
  • Body: a universal package file for HDARS 1.3.9

GET /upack/dev-feed/download/initrode/vendors/abl/var-index-service?contentOnly=tgz&latest

Response:

  • Header: Content-Type: application/x-compressed
  • Header: Content-Disposition: attachment; filename=var-index-service.4.2.0.tgz
  • Body: a GZipped TAR containing the contents of the /package directory of the latest var-index-service package

Upload Package Endpoint

PUT or POST /upack/«feed-name»/upload«...»

There are quite a few ways to access this endpoint, but the end result is the same: it adds or replaces a package in a feed. Because there are so many permutations of how you can use this, it's easiest to specify the various options and behaviors instead.

First and foremost, consider that a complete package consists of required metadata and content (arbitrary files and directories). This endpoint is designed to allow you to upload a complete, pre-built package, or upload a partial package with content and metadata you specified using path, query, form-encoded, and/or JSON parameters.

No duplicate parameters
That's the second thing to consider. For example, if you specify a different package name in both the query and path... you'll get an error (400).

Content Type

The Content-Type header can be any of the following:

  • application/json - properties on the JSON object will be used for content and metadata parameters
  • application/x-www-form-urlencoded - the key/value pairs will be used for content and metadata parameters
  • application/zip - the request body will treated either as content or a partial package

Using application/zip Content-Type

You must send the raw bytes of a ZIP file as the body of your request. If the archive doesn't conform to the universal package format, ProGet will convert it for you, if you supply the required metadata via query string parameters.

If the archive is already in the .upack format, you can specify additional metadata paramters via the querystring.

Metadata Parameters

Any of the following parameters fields may be specified through querystring or content; the format must follow a valid metadata format specification.

ParameterDescription
content-b64A string representing the contents as a base64-encoded ZIP archive; this is not valid with application/zip Content-Type, and will be considered duplicative if content-url is specified
content-urlA url where content can be downloaded from as a ZIP archive; this is not valid with application/zip Content-Type, and will be considered duplicative if content-b64 is specified
groupThis may also be specified as the first path following the endpoint
nameRThis may also be specified as either the last or second-to-last path
versionRThis may also be specified as either the last path
dependenciesWhen specified in JSON, it should be an array; otherwise (querystring or form format), it should be a comma-separated string of package identifiers
anything elseIf any other parameter is specified (including the well-defined title, icon, description), it will be added as a package metadata property.

A 201 is returned for all valid requests; following are some example requests

 

PUT /upack/dev-feed/upload/initrode/vendors/abl/var-index-service?version=5.3.9

Content-Type: application/json

{
 "content-url": "http://sdbuildsv1/latest-stable?project=vindex&branch=v5-hotfix",
 "_sourceRoot": "$/global/vindex/branches/v5-hotfix",
 "_deployTarget": "/var/vsimdesk/vindex"
}

 

curl PUT http://proget.server/upack/dev-feed/upload --upload-file hdars.upack


# This uses the regular Upload-Http operation
Upload-Http content.zip
(
   Url: http://progetsv/upack/Extensions-Dev/upload?name=$UrlEncode($ExtensionName)&group=${ProductName}&version=$UrlEncode($ReleaseNumber)
);

# There is also an operation specifically for this that allows you to securely specify credentials
ProGet::Push-Package content.upack
(
  Credentials: PGExtensionDev,
  Version: $ReleaseNumber
)


$bytes = [Text.Encoding]::UTF8.GetBytes('USERNAME:PASSWORD')
$creds = 'Basic ' + [Convert]::ToBase64String($bytes)

$query = (`
  '?name = 'PACKAGE_NAME' + `
  '&version = $Version.ToString() + `
  '&title = 'PACKAGE_TITLE' + `
  '&description = [uri]::EscapeDataString('PACKAGE_DESCRIPTION') );


Invoke-RestMethod -Method Put `
   -Uri ('http://PROGET_HOST/upack/FEED_NAME/upload' + $query) `
   -ContentType 'application/zip' `
   -Body ([IO.File]::ReadAllBytes($pathToZipFile)) `
   -Headers @{ Authorization = $creds }


Delete Package Endpoint

DELETE or POST /upack/«feed-name»/delete/«group-name»/«package-name»/«package-version»

Deletes the specified package (if group-name is omitted, then the empty group is used), returning a 200 on success or 404 if not found.

We don't know what else to document here, because this seems quite straightforward of a request, but just let us know if you think we should add anything else.

Download Package File Endpoint

This API endpoint is designed to download a specific file within a package, so that you don't need to download the entire package.

Specific Version

GET /upack/«feed-name»/download-file/«group-name»/«package-name»/«package-version»&path=«path»

Latest Version

GET /upack/«feed-name»/download-file/«group-name»/«package-name»?latest&path=«path»

Returns either a package file or an error.

ParameterDescription
group-nameOptional. If not specified, the empty group will be searched.
package-nameRequired. If not found, a 404 is returned.
package-versionOptional. If not specified, "latest" must be specified as a query string argument. If no version is specified and "latest" is not supplied, a 400 is returned. If no matching versions are found, a 404 is returned.
pathRequired. Relative path to the file within the package. Note, package contents are contained within the "package" directory of the package, so most request paths should start with "package" unless files in the package root are desired, such as the upack.json file. If the file is not found within the package, a 404 is returned. If a directory name is specified, a 403 is returned.

Following are some example request/responses:

GET /upack/dev-feed/download-file/hdars/1.3.9?path=package/example.txt

Response:

  • Header: Content-Type: text/plain
  • Header: Content-Disposition: attachment; filename=example.txt
  • Body: the contents of the example.txt file in the package contents

 

GET /upack/dev-feed/download-file/hdars?latest&path=upack.json

Response:

  • Header: Content-Type: application/json
  • Header: Content-Disposition: attachment; filename=upack.json
  • Body: the contents of the "hdars" package's upack.json file

Download Virtual Package Endpoint

This endpoint is used to download the package.version.vpack file for a virtual package, or throw error if not a virtual package.

Specific Version

GET /upack/«feed-name»/download-vpack/«group-name»/«package-name»/«package-version»

Latest Version

GET /upack/«feed-name»/download-vpack/«group-name»/«package-name»?latest

Returns either a package file or an error.

ParameterDescription
group-nameOptional. If not specified, the empty group will be searched.
package-nameRequired. If not found, a 404 is returned.
package-versionOptional. If not specified, "latest" must be specified as a query string argument. If no version is specified and "latest" is not supplied, a 400 is returned. If no matching versions are found, a 404 is returned.

Feed Metadata Endpoint

GET /upack/«feed-name»/meta

Returns a JSON object that describes the feed using the following properties.

PropertyFormat
apiVersionA string containing the supported Universal Feed Version.
nameA string containing the name of the feed.
descriptionA string containing the description of the feed.
versionA string containing the Universal Feed API version of the feed.
packageCountAn integer containing the number of unique package names in the feed.
packageVersionCountAn integer containing the number of packages in the feed.
servicesAn array of stringscontaining any of the following values.
  • VirtualPackages - supports virtual packages, and injects the isVirtual property in the list endpoints
  • RemotePackages - supports remote packages (e.g. connectors in ProGet), and injects the isLocal and isCached properties in the list endpoints
  • UploadPackage - supports simple uploading (a complete package file only)
  • UploadContents - supports partial uploading (contents, metadata, etc)
  • Delete - supports deleting packages
  • DownloadContents - supports downloading of individual files or "contentOnly" of a pcakge

If a 400 is returned instead, the feed version is less than 1.3.0.

Import Package Endpoint

Adds a package from an asset directory, file share, or local path on the ProGet server.

POST /upack/«feed-name»/import

Content Type

The `Content-Type` header should be `application/json`.

Content Parameters

These properties are specified as properties of the JSON object in the request content body:

ParameterDescription
assetDirectory
Name of the asset directory to import the package from. The asset directory must be in the same ProGet instance as the Unviersal feed.
from (required)
Path of `.upack` file to import. If `assetDirectory` is specified, this refers to the path within the specified asset directory. Otherwise, it is a local/UNC file path relative to the ProGet server.
deleteFromSource
Specifies whether to delete the file from the source after import. The default is true

Remarks

The intended usage of this endpoint is to allow an asset directory to act as a staging area for uploading very large universal packages. For optimal performance, `assetDirectory` should be specified, the asset directory and universal package feed should both be configured for local disk storage, and `deleteFromSource` must be true. In this case, a fast filesystem move operation can be performed. In all other cases, the operation will still complete, but may take longer depending on the size of the package imported.


Search Packages Endpoint (Unsupported)

Note: this is not part of the Universal Feed Specification, and should not be used for anything other than querying ProGet servers in limited cases.

GET /upack/«feed-name»/search?query=«search-query»&count=«max-items»

This is the what the ProGet Web Application uses to show results to users, and returns a list of packages similar to the list packages endpoint.

You're welcome to use it, but it's unsupported because its behavior is not at all documented, and we really can't think of a use-case outside of the ProGet Web Application. Don't hesitate to contact us if this is an endpoint you would find helpful, and we can either document it better or make it more useful outside of the ProGet UI.


Was this article helpful?