From 3d015d3d6ce5da9200ca5691653245bf6d7cf46b Mon Sep 17 00:00:00 2001 From: "Deployment Bot (from Travis CI)" Date: Mon, 25 Sep 2023 21:06:25 +0000 Subject: [PATCH] Deploy ga4gh/data-repository-service-schemas to github.com/ga4gh/data-repository-service-schemas.git:gh-pages --- ...ore-background-on-compact-identifiers.html | 2052 ++++++++++++++++ ...ore-background-on-compact-identifiers.json | 42 + ...ore-background-on-compact-identifiers.yaml | 398 ++++ preview/release/drs-1.4.0/openapi.json | 1351 +++++++++++ preview/release/drs-1.4.0/openapi.yaml | 2074 +++++++++++++++++ 5 files changed, 5917 insertions(+) create mode 100644 preview/release/drs-1.4.0/docs/more-background-on-compact-identifiers.html create mode 100644 preview/release/drs-1.4.0/more-background-on-compact-identifiers.json create mode 100644 preview/release/drs-1.4.0/more-background-on-compact-identifiers.yaml create mode 100644 preview/release/drs-1.4.0/openapi.json create mode 100644 preview/release/drs-1.4.0/openapi.yaml diff --git a/preview/release/drs-1.4.0/docs/more-background-on-compact-identifiers.html b/preview/release/drs-1.4.0/docs/more-background-on-compact-identifiers.html new file mode 100644 index 00000000..2c731990 --- /dev/null +++ b/preview/release/drs-1.4.0/docs/more-background-on-compact-identifiers.html @@ -0,0 +1,2052 @@ + + + + + + More Background on Compact Identifiers + + + + + + + + + +

More Background on Compact Identifiers (1.4.0)

Download OpenAPI specification:Download

GA4GH Cloud Work Stream: ga4gh-cloud@ga4gh.org License: Apache 2.0 Terms of Service

About

This document contains more examples of resolving compact identifier-based DRS URIs than we could fit in the DRS specification or appendix. It’s provided here for your reference as a supplement to the specification.

+

Background on Compact Identifier-Based URIs

Compact identifiers refer to locally-unique persistent identifiers that have been namespaced to provide global uniqueness. See "Uniform resolution of compact identifiers for biomedical data" for an excellent introduction to this topic. By using compact identifiers in DRS URIs, along with a resolver registry (identifiers.org/n2t.net), systems can identify the current resolver when they need to translate a DRS URI into a fetchable URL. This allows a project to issue compact identifiers in DRS URIs and not be concerned if the project name or DRS hostname changes in the future, the current resolver can always be found through the identifiers.org/n2t.net registries. Together the identifiers.org/n2t.net systems support the resolver lookup for over 700 compact identifiers formats used in the research community, making it possible for a DRS server to use any of these as DRS IDs (or to register a new compact identifier type and resolver service of their own).

+

We use a DRS URI scheme rather than Compact URIs (CURIEs) directly since we feel that systems consuming DRS objects will be able to better differentiate a DRS URI. CURIEs are widely used in the research community, and we feel the fact that they can point to a wide variety of entities (HTML documents, PDFs, identities in data models, etc) makes it more difficult for systems to unambiguously identify entities as DRS objects.

+

Still, to make compact identifiers work in DRS URIs we leverage the CURIE format used by identifiers.org/n2t.net. Compact identifiers have the form:

+
prefix:accession
+
+

The prefix can be divided into a provider_code (optional) and namespace. The accession here is an Ark, DOI, Data GUID, or another issuer's local ID for the object being pointed to:

+
[provider_code/]namespace:accession
+
+

Both the provider_code and namespace disallow spaces or punctuation, only lowercase alphanumerical characters, underscores and dots are allowed.

+

Examples include (from n2t.net):

+
PDB:2gc4
+Taxon:9606
+DOI:10.5281/ZENODO.1289856
+ark:/47881/m6g15z54
+IGSN:SSH000SUA
+
+

Tip:

+
+

DRS URIs using compact identifiers with resolvers registered in identifiers.org/n2t.net can be distinguished from the hostname-based DRS URIs below based on the required ":" which is not allowed in hostname-based URI.

+
+

See the documentation on n2t.net and identifiers.org for much more information on the compact identifiers used there and details about the resolution process.

+

Registering a DRS Server on a Meta-Resolver

See the documentation on the n2t.net and identifiers.org meta-resolvers for adding your own compact identifier type and registering your DRS server as a resolver. You can register new prefixes (or mirrors by adding resource provider codes) for free using a simple online form.

+

Keep in mind, while anyone can register prefixes, the identifiers.org/n2t.net sites do basic hand curation to verify new prefix and resource (provider code) requests. See those sites for more details on their security practices. For more information see

+

Starting with the prefix for our new compact identifier, let’s register the namespace mydrsprefix on identifiers.org/n2t.net and use 5-digit numeric IDs as our accessions. We will then link this to the DRS server at https://mydrs.server.org/ga4gh/drs/v1/ by filling in the provider details. Here’s what that the registration for our new namespace looks like on identifiers.org:

+

Prefix Register 1

+

Prefix Register 2

+

Example DRS Client Compact Identifier-Based URI Resolution Process - Existing Compact Identifier Provider

A DRS client identifies the DRS URI compact identifier components using the first occurrence of "/" (optional) and ":" characters. These are not allowed inside the provider_code (optional) or the namespace. The ":" character is not allowed in a Hostname-based DRS URI, providing a convenient mechanism to differentiate them. Once the provider_code (optional) and namespace are extracted from a DRS compact identifier-based URI, a client can use services on identifiers.org to identify available resolvers.

+

Let’s look at a specific example DRS compact identifier-based URI that uses DOIs, a popular compact identifier, and walk through the process that a client would use to resolve it. Keep in mind, the resolution process is the same from the client perspective if a given DRS server is using an existing compact identifier type (DOIs, ARKs, Data GUIDs) or creating their own compact identifier type for their DRS server and registering it on identifiers.org/n2t.net.

+

Starting with the DRS URI:

+
drs://doi:10.5072/FK2805660V
+
+

with a namespace of "doi", the following GET request will return information about the namespace:

+
GET https://registry.api.identifiers.org/restApi/namespaces/search/findByPrefix?prefix=doi
+
+

This information then points to resolvers for the "doi" namespace. This "doi" namespace was assigned a namespace ID of 75 by identifiers.org. This "id" has nothing to do with compact identifier accessions (which are used in the URL pattern as {$id} below) or DRS IDs. This namespace ID (75 below) is purely an identifiers.org internal ID for use with their APIs:

+
GET https://registry.api.identifiers.org/restApi/resources/search/findAllByNamespaceId?id=75
+
+

This returns enough information to, ultimately, identify one or more resolvers and each have a URL pattern that, for DRS-supporting systems, provides a URL template for making a successful DRS GET request. For example, the DOI urlPattern is:

+
urlPattern: "https://doi.org/{$id}"
+
+

And the {$id} here refers to the accession from the compact identifier (in this example the accession is 10.5072/FK2805660V). If applicable, a provider code can be supplied in the above requests to specify a particular mirror if there are multiple resolvers for this namespace. In the case of DOIs, you only get a single resolver.

+

Given this information you now know you can make a GET on the URL:

+
GET https://doi.org/10.5072/FK2805660V
+
+

The URL above is valid for a DOI object but it is not actually a DRS server! Instead, it redirects to a DRS server through a series of HTTPS redirects. This is likely to be common when working with existing compact identifiers like DOIs or ARKs. Regardless, the redirect should eventually lead to a DRS URL that percent-encodes the accession as a DRS ID in a DRS object API call. For a hypothetical example, here’s what a redirect to a DRS API URL might ultimately look like. A client doesn't have to do anything other than follow the HTTPS redirects. The link between the DOI resolver on doi.org and the DRS server URL below is the result of the DRS server registering their data objects with a DOI issuer.

+
GET https://drs.example.org/ga4gh/drs/v1/objects/10.5072%2FFK2805660V
+
+

IDs in DRS hostname-based URIs/URLs are always percent-encoded to eliminate ambiguity even though the DRS compact identifier-based URIs and the identifier.org's API do not percent-encode accessions. This was done in order to 1) follow the CURIE conventions of identifiers.org/n2t.net for compact identifier-based DRS URIs and 2) to aid in readability for users who understand they are working with compact identifiers. The general rule of thumb, when using a compact identifier accession as a DRS ID in a DRS API call, make sure to percent-encode it. An easy way for a DRS client to handle this is to get the initial DRS object JSON response from whatever redirects the compact identifier resolves to, then look for the self_uri in the JSON, which will give you the correctly percent-encoded DRS ID for subsequent DRS API calls such as the access method.

+

Example DRS Client Compact Identifier-Based URI Resolution Process - Registering a new Compact Identifier for Your DRS Server

See the documentation on n2t.net and identifiers.org for adding your own compact identifier type and registering your DRS server as a resolver. We document this in more detail in the main specification document.

+

Now the question is how does a client resolve your newly registered compact identifier for your DRS server? It turns out, whether specific to a DRS implementation or using existing compact identifiers like ARKs or DOIs, the DRS client resolution process for compact identifier-based URIs is exactly the same. We briefly run through process below for a new compact identifier as an example but, again, a client will not need to do anything different from the resolution process documented in "DRS Client Compact Identifier-Based URI Resolution Process - Existing Compact Identifier Provider".

+

Now we can issue DRS URI for our data objects like:

+
drs://mydrsprefix:12345
+
+

This is a little simpler than working with DOIs or other existing compact identifier issuers out there since we can create our own IDs and not have to allocate them through a third-party service (see "Issuing Existing Compact Identifiers for Use with Your DRS Server" below).

+

With a namespace of "mydrsprefix", the following GET request will return information about the namespace:

+
GET https://registry.api.identifiers.org/restApi/namespaces/search/findByPrefix?prefix=mydrsprefix
+
+

Of course, this is a hypothetical example so the actual API call won’t work, but you can see the GET request is identical to "DRS Client Compact Identifier-Based URI Resolution Process - Existing Compact Identifier Provider".

+

This information then points to resolvers for the "mydrsprefix" namespace. Hypothetically, this "mydrsprefix" namespace was assigned a namespace ID of 1829 by identifiers.org. This "id" has nothing to do with compact identifier accessions (which are used in the URL pattern as {$id} below) or DRS IDs. This namespace ID (1829 below) is purely an identifiers.org internal ID for use with their APIs:

+
GET https://registry.api.identifiers.org/restApi/resources/search/findAllByNamespaceId?id=1829
+
+

Like the previous GET request this URL won’t work but you can see the GET request is identical to "DRS Client Compact Identifier-Based URI Resolution Process - Existing Compact Identifier Provider".

+

This returns enough information to, ultimately, identify one or more resolvers and each have a URL pattern that, for DRS-supporting systems, provides a URL template for making a successful DRS GET request. For example, the "mydrsprefix" urlPattern is:

+
urlPattern: "https://mydrs.server.org/ga4gh/drs/v1/objects/{$id}"
+
+

And the {$id} here refers to the accession from the compact identifier (in this example the accession is 12345). If applicable, a provider code can be supplied in the above requests to specify a particular mirror if there are multiple resolvers for this namespace.

+

Given this information you now know you can make a GET on the URL:

+
GET https://mydrs.server.org/ga4gh/drs/v1/objects/12345
+
+

So, compared to using a third party service like DOIs and ARKs, this would be a direct pointer to a DRS server. However, just as with "DRS Client Compact Identifier-Based URI Resolution Process - Existing Compact Identifier Provider", the client should always be prepared to follow HTTPS redirects.

+

To summarize, a client resolving a custom compact identifier registered for a single DRS server is actually the same as resolving using a third-party compact identifier service like ARKs or DOIs with a DRS server, just make sure to follow redirects in all cases.

+

Note: Issuing Existing Compact Identifiers for Use with Your DRS Server

+

See the documentation on n2t.net and identifiers.org for information about all the compact identifiers that are supported. You can choose to use an existing compact identifier provider for your DRS server, as we did in the example above using DOIs ("DRS Client Compact Identifier-Based URI Resolution Process - Existing Compact Identifier Provider"). Just keep in mind, each provider will have their own approach for generating compact identifiers and associating them with a DRS data object URL. Some compact identifier providers, like DOIs, provide a method whereby you can register in their network and get your own prefix, allowing you to mint your own accessions. Other services, like the University of California’s EZID service, provide accounts and a mechanism to mint accessions centrally for each of your data objects. For experimentation we recommend you take a look at the EZID website that allows you to create DOIs and ARKs and associate them with your data object URLs on your DRS server for testing purposes.

+
+ + + + \ No newline at end of file diff --git a/preview/release/drs-1.4.0/more-background-on-compact-identifiers.json b/preview/release/drs-1.4.0/more-background-on-compact-identifiers.json new file mode 100644 index 00000000..d437cfc7 --- /dev/null +++ b/preview/release/drs-1.4.0/more-background-on-compact-identifiers.json @@ -0,0 +1,42 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "More Background on Compact Identifiers", + "version": "1.4.0", + "x-logo": { + "url": "https://www.ga4gh.org/wp-content/themes/ga4gh/dist/assets/svg/logos/logo-full-color.svg" + }, + "termsOfService": "https://www.ga4gh.org/terms-and-conditions/", + "contact": { + "name": "GA4GH Cloud Work Stream", + "email": "ga4gh-cloud@ga4gh.org" + }, + "license": { + "name": "Apache 2.0", + "url": "https://raw.githubusercontent.com/ga4gh/data-repository-service-schemas/master/LICENSE" + } + }, + "tags": [ + { + "name": "About", + "description": "This document contains more examples of resolving compact identifier-based DRS URIs than we could fit in the DRS specification or appendix. It’s provided here for your reference as a supplement to the specification.\n" + }, + { + "name": "Background on Compact Identifier-Based URIs", + "description": "Compact identifiers refer to locally-unique persistent identifiers that have been namespaced to provide global uniqueness. See [\"Uniform resolution of compact identifiers for biomedical data\"](https://www.biorxiv.org/content/10.1101/101279v3) for an excellent introduction to this topic. By using compact identifiers in DRS URIs, along with a resolver registry (identifiers.org/n2t.net), systems can identify the current resolver when they need to translate a DRS URI into a fetchable URL. This allows a project to issue compact identifiers in DRS URIs and not be concerned if the project name or DRS hostname changes in the future, the current resolver can always be found through the identifiers.org/n2t.net registries. Together the identifiers.org/n2t.net systems support the resolver lookup for over 700 compact identifiers formats used in the research community, making it possible for a DRS server to use any of these as DRS IDs (or to register a new compact identifier type and resolver service of their own).\n\nWe use a DRS URI scheme rather than [Compact URIs (CURIEs)](https://en.wikipedia.org/wiki/CURIE) directly since we feel that systems consuming DRS objects will be able to better differentiate a DRS URI. CURIEs are widely used in the research community, and we feel the fact that they can point to a wide variety of entities (HTML documents, PDFs, identities in data models, etc) makes it more difficult for systems to unambiguously identify entities as DRS objects.\n\nStill, to make compact identifiers work in DRS URIs we leverage the CURIE format used by identifiers.org/n2t.net. Compact identifiers have the form:\n\n```\nprefix:accession\n```\n\nThe prefix can be divided into a `provider_code` (optional) and `namespace`. The `accession` here is an Ark, DOI, Data GUID, or another issuer's local ID for the object being pointed to:\n\n```\n[provider_code/]namespace:accession\n```\n\nBoth the `provider_code` and `namespace` disallow spaces or punctuation, only lowercase alphanumerical characters, underscores and dots are allowed.\n\n[Examples](https://n2t.net/e/compact_ids.html) include (from n2t.net):\n\n```\nPDB:2gc4\nTaxon:9606\nDOI:10.5281/ZENODO.1289856\nark:/47881/m6g15z54\nIGSN:SSH000SUA\n```\n\nTip:\n> DRS URIs using compact identifiers with resolvers registered in identifiers.org/n2t.net can be distinguished from the hostname-based DRS URIs below based on the required \":\" which is not allowed in hostname-based URI.\n\nSee the documentation on [n2t.net](https://n2t.net/e/compact_ids.html) and [identifiers.org](https://docs.identifiers.org/) for much more information on the compact identifiers used there and details about the resolution process.\n" + }, + { + "name": "Registering a DRS Server on a Meta-Resolver", + "description": "See the documentation on the [n2t.net](https://n2t.net/e/compact_ids.html) and [identifiers.org](https://docs.identifiers.org/) meta-resolvers for adding your own compact identifier type and registering your DRS server as a resolver. You can register new prefixes (or mirrors by adding resource provider codes) for free using a simple online form.\n\nKeep in mind, while anyone can register prefixes, the identifiers.org/n2t.net sites do basic hand curation to verify new prefix and resource (provider code) requests. See those sites for more details on their security practices. For more information see\n\nStarting with the prefix for our new compact identifier, let’s register the namespace `mydrsprefix` on identifiers.org/n2t.net and use 5-digit numeric IDs as our accessions. We will then link this to the DRS server at https://mydrs.server.org/ga4gh/drs/v1/ by filling in the provider details. Here’s what that the registration for our new namespace looks like on [identifiers.org](https://registry.identifiers.org/prefixregistrationrequest):\n\n![Prefix Register 1](/data-repository-service-schemas/public/img/prefix_register_1.png)\n\n![Prefix Register 2](/data-repository-service-schemas/public/img/prefix_register_2.png)\n" + }, + { + "name": "Example DRS Client Compact Identifier-Based URI Resolution Process - Existing Compact Identifier Provider", + "description": "A DRS client identifies the DRS URI compact identifier components using the first occurrence of \"/\" (optional) and \":\" characters. These are not allowed inside the provider_code (optional) or the namespace. The \":\" character is not allowed in a Hostname-based DRS URI, providing a convenient mechanism to differentiate them. Once the provider_code (optional) and namespace are extracted from a DRS compact identifier-based URI, a client can use services on identifiers.org to identify available resolvers.\n\n*Let’s look at a specific example DRS compact identifier-based URI that uses DOIs, a popular compact identifier, and walk through the process that a client would use to resolve it. Keep in mind, the resolution process is the same from the client perspective if a given DRS server is using an existing compact identifier type (DOIs, ARKs, Data GUIDs) or creating their own compact identifier type for their DRS server and registering it on identifiers.org/n2t.net.*\n\nStarting with the DRS URI:\n\n```\ndrs://doi:10.5072/FK2805660V\n```\n\nwith a namespace of \"doi\", the following GET request will return information about the namespace:\n\n```\nGET https://registry.api.identifiers.org/restApi/namespaces/search/findByPrefix?prefix=doi\n```\n\nThis information then points to resolvers for the \"doi\" namespace. This \"doi\" namespace was assigned a namespace ID of 75 by identifiers.org. This \"id\" has nothing to do with compact identifier accessions (which are used in the URL pattern as `{$id}` below) or DRS IDs. This namespace ID (75 below) is purely an identifiers.org internal ID for use with their APIs:\n\n```\nGET https://registry.api.identifiers.org/restApi/resources/search/findAllByNamespaceId?id=75\n```\n\nThis returns enough information to, ultimately, identify one or more resolvers and each have a URL pattern that, for DRS-supporting systems, provides a URL template for making a successful DRS GET request. For example, the DOI urlPattern is:\n\n```\nurlPattern: \"https://doi.org/{$id}\"\n```\n\nAnd the `{$id}` here refers to the accession from the compact identifier (in this example the accession is `10.5072/FK2805660V`). If applicable, a provider code can be supplied in the above requests to specify a particular mirror if there are multiple resolvers for this namespace. In the case of DOIs, you only get a single resolver.\n\nGiven this information you now know you can make a GET on the URL:\n\n```\nGET https://doi.org/10.5072/FK2805660V\n```\n\n*The URL above is valid for a DOI object but it is not actually a DRS server! Instead, it redirects to a DRS server through a series of HTTPS redirects. This is likely to be common when working with existing compact identifiers like DOIs or ARKs. Regardless, the redirect should eventually lead to a DRS URL that percent-encodes the accession as a DRS ID in a DRS object API call. For a **hypothetical** example, here’s what a redirect to a DRS API URL might ultimately look like. A client doesn't have to do anything other than follow the HTTPS redirects. The link between the DOI resolver on doi.org and the DRS server URL below is the result of the DRS server registering their data objects with a DOI issuer.*\n\n```\nGET https://drs.example.org/ga4gh/drs/v1/objects/10.5072%2FFK2805660V\n```\n\nIDs in DRS hostname-based URIs/URLs are always percent-encoded to eliminate ambiguity even though the DRS compact identifier-based URIs and the identifier.org's API do not percent-encode accessions. This was done in order to 1) follow the CURIE conventions of identifiers.org/n2t.net for compact identifier-based DRS URIs and 2) to aid in readability for users who understand they are working with compact identifiers. **The general rule of thumb, when using a compact identifier accession as a DRS ID in a DRS API call, make sure to percent-encode it. An easy way for a DRS client to handle this is to get the initial DRS object JSON response from whatever redirects the compact identifier resolves to, then look for the** `self_uri` **in the JSON, which will give you the correctly percent-encoded DRS ID for subsequent DRS API calls such as the** `access` **method.**\n" + }, + { + "name": "Example DRS Client Compact Identifier-Based URI Resolution Process - Registering a new Compact Identifier for Your DRS Server", + "description": "See the documentation on [n2t.net](https://n2t.net/e/compact_ids.html) and [identifiers.org](https://docs.identifiers.org/) for adding your own compact identifier type and registering your DRS server as a resolver. We document this in more detail in the [main specification document](./index.html).\n\nNow the question is how does a client resolve your newly registered compact identifier for your DRS server? *It turns out, whether specific to a DRS implementation or using existing compact identifiers like ARKs or DOIs, the DRS client resolution process for compact identifier-based URIs is exactly the same.* We briefly run through process below for a new compact identifier as an example but, again, a client will not need to do anything different from the resolution process documented in \"DRS Client Compact Identifier-Based URI Resolution Process - Existing Compact Identifier Provider\".\n\nNow we can issue DRS URI for our data objects like:\n\n```\ndrs://mydrsprefix:12345\n```\n\nThis is a little simpler than working with DOIs or other existing compact identifier issuers out there since we can create our own IDs and not have to allocate them through a third-party service (see \"Issuing Existing Compact Identifiers for Use with Your DRS Server\" below).\n\nWith a namespace of \"mydrsprefix\", the following GET request will return information about the namespace:\n\n```\nGET https://registry.api.identifiers.org/restApi/namespaces/search/findByPrefix?prefix=mydrsprefix\n```\n\n*Of course, this is a hypothetical example so the actual API call won’t work, but you can see the GET request is identical to \"DRS Client Compact Identifier-Based URI Resolution Process - Existing Compact Identifier Provider\".*\n\nThis information then points to resolvers for the \"mydrsprefix\" namespace. Hypothetically, this \"mydrsprefix\" namespace was assigned a namespace ID of 1829 by identifiers.org. This \"id\" has nothing to do with compact identifier accessions (which are used in the URL pattern as `{$id}` below) or DRS IDs. This namespace ID (1829 below) is purely an identifiers.org internal ID for use with their APIs:\n\n```\nGET https://registry.api.identifiers.org/restApi/resources/search/findAllByNamespaceId?id=1829\n```\n\n*Like the previous GET request this URL won’t work but you can see the GET request is identical to \"DRS Client Compact Identifier-Based URI Resolution Process - Existing Compact Identifier Provider\".*\n\nThis returns enough information to, ultimately, identify one or more resolvers and each have a URL pattern that, for DRS-supporting systems, provides a URL template for making a successful DRS GET request. For example, the \"mydrsprefix\" urlPattern is:\n\n```\nurlPattern: \"https://mydrs.server.org/ga4gh/drs/v1/objects/{$id}\"\n```\n\nAnd the `{$id}` here refers to the accession from the compact identifier (in this example the accession is `12345`). If applicable, a provider code can be supplied in the above requests to specify a particular mirror if there are multiple resolvers for this namespace.\n\nGiven this information you now know you can make a GET on the URL:\n\n```\nGET https://mydrs.server.org/ga4gh/drs/v1/objects/12345\n```\n\nSo, compared to using a third party service like DOIs and ARKs, this would be a direct pointer to a DRS server. However, just as with \"DRS Client Compact Identifier-Based URI Resolution Process - Existing Compact Identifier Provider\", the client should always be prepared to follow HTTPS redirects.\n\n*To summarize, a client resolving a custom compact identifier registered for a single DRS server is actually the same as resolving using a third-party compact identifier service like ARKs or DOIs with a DRS server, just make sure to follow redirects in all cases.*\n\n**Note: Issuing Existing Compact Identifiers for Use with Your DRS Server**\n\nSee the documentation on [n2t.net](https://n2t.net/e/compact_ids.html) and [identifiers.org](https://docs.identifiers.org/) for information about all the compact identifiers that are supported. You can choose to use an existing compact identifier provider for your DRS server, as we did in the example above using DOIs (\"DRS Client Compact Identifier-Based URI Resolution Process - Existing Compact Identifier Provider\"). Just keep in mind, each provider will have their own approach for generating compact identifiers and associating them with a DRS data object URL. Some compact identifier providers, like DOIs, provide a method whereby you can register in their network and get your own prefix, allowing you to mint your own accessions. Other services, like the University of California’s [EZID](https://ezid.cdlib.org/) service, provide accounts and a mechanism to mint accessions centrally for each of your data objects. For experimentation we recommend you take a look at the EZID website that allows you to create DOIs and ARKs and associate them with your data object URLs on your DRS server for testing purposes.\n" + } + ], + "components": {} +} \ No newline at end of file diff --git a/preview/release/drs-1.4.0/more-background-on-compact-identifiers.yaml b/preview/release/drs-1.4.0/more-background-on-compact-identifiers.yaml new file mode 100644 index 00000000..20e5bac4 --- /dev/null +++ b/preview/release/drs-1.4.0/more-background-on-compact-identifiers.yaml @@ -0,0 +1,398 @@ +openapi: 3.0.3 +info: + title: More Background on Compact Identifiers + version: 1.4.0 + x-logo: + url: >- + https://www.ga4gh.org/wp-content/themes/ga4gh/dist/assets/svg/logos/logo-full-color.svg + termsOfService: https://www.ga4gh.org/terms-and-conditions/ + contact: + name: GA4GH Cloud Work Stream + email: ga4gh-cloud@ga4gh.org + license: + name: Apache 2.0 + url: >- + https://raw.githubusercontent.com/ga4gh/data-repository-service-schemas/master/LICENSE +tags: + - name: About + description: > + This document contains more examples of resolving compact identifier-based + DRS URIs than we could fit in the DRS specification or appendix. It’s + provided here for your reference as a supplement to the specification. + - name: Background on Compact Identifier-Based URIs + description: > + Compact identifiers refer to locally-unique persistent identifiers that + have been namespaced to provide global uniqueness. See ["Uniform + resolution of compact identifiers for biomedical + data"](https://www.biorxiv.org/content/10.1101/101279v3) for an excellent + introduction to this topic. By using compact identifiers in DRS URIs, + along with a resolver registry (identifiers.org/n2t.net), systems can + identify the current resolver when they need to translate a DRS URI into a + fetchable URL. This allows a project to issue compact identifiers in DRS + URIs and not be concerned if the project name or DRS hostname changes in + the future, the current resolver can always be found through the + identifiers.org/n2t.net registries. Together the identifiers.org/n2t.net + systems support the resolver lookup for over 700 compact identifiers + formats used in the research community, making it possible for a DRS + server to use any of these as DRS IDs (or to register a new compact + identifier type and resolver service of their own). + + + We use a DRS URI scheme rather than [Compact URIs + (CURIEs)](https://en.wikipedia.org/wiki/CURIE) directly since we feel that + systems consuming DRS objects will be able to better differentiate a DRS + URI. CURIEs are widely used in the research community, and we feel the + fact that they can point to a wide variety of entities (HTML documents, + PDFs, identities in data models, etc) makes it more difficult for systems + to unambiguously identify entities as DRS objects. + + + Still, to make compact identifiers work in DRS URIs we leverage the CURIE + format used by identifiers.org/n2t.net. Compact identifiers have the form: + + + ``` + + prefix:accession + + ``` + + + The prefix can be divided into a `provider_code` (optional) and + `namespace`. The `accession` here is an Ark, DOI, Data GUID, or another + issuer's local ID for the object being pointed to: + + + ``` + + [provider_code/]namespace:accession + + ``` + + + Both the `provider_code` and `namespace` disallow spaces or punctuation, + only lowercase alphanumerical characters, underscores and dots are + allowed. + + + [Examples](https://n2t.net/e/compact_ids.html) include (from n2t.net): + + + ``` + + PDB:2gc4 + + Taxon:9606 + + DOI:10.5281/ZENODO.1289856 + + ark:/47881/m6g15z54 + + IGSN:SSH000SUA + + ``` + + + Tip: + + > DRS URIs using compact identifiers with resolvers registered in + identifiers.org/n2t.net can be distinguished from the hostname-based DRS + URIs below based on the required ":" which is not allowed in + hostname-based URI. + + + See the documentation on [n2t.net](https://n2t.net/e/compact_ids.html) and + [identifiers.org](https://docs.identifiers.org/) for much more information + on the compact identifiers used there and details about the resolution + process. + - name: Registering a DRS Server on a Meta-Resolver + description: > + See the documentation on the [n2t.net](https://n2t.net/e/compact_ids.html) + and [identifiers.org](https://docs.identifiers.org/) meta-resolvers for + adding your own compact identifier type and registering your DRS server as + a resolver. You can register new prefixes (or mirrors by adding resource + provider codes) for free using a simple online form. + + + Keep in mind, while anyone can register prefixes, the + identifiers.org/n2t.net sites do basic hand curation to verify new prefix + and resource (provider code) requests. See those sites for more details on + their security practices. For more information see + + + Starting with the prefix for our new compact identifier, let’s register + the namespace `mydrsprefix` on identifiers.org/n2t.net and use 5-digit + numeric IDs as our accessions. We will then link this to the DRS server at + https://mydrs.server.org/ga4gh/drs/v1/ by filling in the provider details. + Here’s what that the registration for our new namespace looks like on + [identifiers.org](https://registry.identifiers.org/prefixregistrationrequest): + + + ![Prefix Register + 1](/data-repository-service-schemas/public/img/prefix_register_1.png) + + + ![Prefix Register + 2](/data-repository-service-schemas/public/img/prefix_register_2.png) + - name: >- + Example DRS Client Compact Identifier-Based URI Resolution Process - + Existing Compact Identifier Provider + description: > + A DRS client identifies the DRS URI compact identifier components using + the first occurrence of "/" (optional) and ":" characters. These are not + allowed inside the provider_code (optional) or the namespace. The ":" + character is not allowed in a Hostname-based DRS URI, providing a + convenient mechanism to differentiate them. Once the provider_code + (optional) and namespace are extracted from a DRS compact identifier-based + URI, a client can use services on identifiers.org to identify available + resolvers. + + + *Let’s look at a specific example DRS compact identifier-based URI that + uses DOIs, a popular compact identifier, and walk through the process that + a client would use to resolve it. Keep in mind, the resolution process is + the same from the client perspective if a given DRS server is using an + existing compact identifier type (DOIs, ARKs, Data GUIDs) or creating + their own compact identifier type for their DRS server and registering it + on identifiers.org/n2t.net.* + + + Starting with the DRS URI: + + + ``` + + drs://doi:10.5072/FK2805660V + + ``` + + + with a namespace of "doi", the following GET request will return + information about the namespace: + + + ``` + + GET + https://registry.api.identifiers.org/restApi/namespaces/search/findByPrefix?prefix=doi + + ``` + + + This information then points to resolvers for the "doi" namespace. This + "doi" namespace was assigned a namespace ID of 75 by identifiers.org. This + "id" has nothing to do with compact identifier accessions (which are used + in the URL pattern as `{$id}` below) or DRS IDs. This namespace ID (75 + below) is purely an identifiers.org internal ID for use with their APIs: + + + ``` + + GET + https://registry.api.identifiers.org/restApi/resources/search/findAllByNamespaceId?id=75 + + ``` + + + This returns enough information to, ultimately, identify one or more + resolvers and each have a URL pattern that, for DRS-supporting systems, + provides a URL template for making a successful DRS GET request. For + example, the DOI urlPattern is: + + + ``` + + urlPattern: "https://doi.org/{$id}" + + ``` + + + And the `{$id}` here refers to the accession from the compact identifier + (in this example the accession is `10.5072/FK2805660V`). If applicable, a + provider code can be supplied in the above requests to specify a + particular mirror if there are multiple resolvers for this namespace. In + the case of DOIs, you only get a single resolver. + + + Given this information you now know you can make a GET on the URL: + + + ``` + + GET https://doi.org/10.5072/FK2805660V + + ``` + + + *The URL above is valid for a DOI object but it is not actually a DRS + server! Instead, it redirects to a DRS server through a series of HTTPS + redirects. This is likely to be common when working with existing compact + identifiers like DOIs or ARKs. Regardless, the redirect should eventually + lead to a DRS URL that percent-encodes the accession as a DRS ID in a DRS + object API call. For a **hypothetical** example, here’s what a redirect to + a DRS API URL might ultimately look like. A client doesn't have to do + anything other than follow the HTTPS redirects. The link between the DOI + resolver on doi.org and the DRS server URL below is the result of the DRS + server registering their data objects with a DOI issuer.* + + + ``` + + GET https://drs.example.org/ga4gh/drs/v1/objects/10.5072%2FFK2805660V + + ``` + + + IDs in DRS hostname-based URIs/URLs are always percent-encoded to + eliminate ambiguity even though the DRS compact identifier-based URIs and + the identifier.org's API do not percent-encode accessions. This was done + in order to 1) follow the CURIE conventions of identifiers.org/n2t.net for + compact identifier-based DRS URIs and 2) to aid in readability for users + who understand they are working with compact identifiers. **The general + rule of thumb, when using a compact identifier accession as a DRS ID in a + DRS API call, make sure to percent-encode it. An easy way for a DRS client + to handle this is to get the initial DRS object JSON response from + whatever redirects the compact identifier resolves to, then look for the** + `self_uri` **in the JSON, which will give you the correctly + percent-encoded DRS ID for subsequent DRS API calls such as the** `access` + **method.** + - name: >- + Example DRS Client Compact Identifier-Based URI Resolution Process - + Registering a new Compact Identifier for Your DRS Server + description: > + See the documentation on [n2t.net](https://n2t.net/e/compact_ids.html) and + [identifiers.org](https://docs.identifiers.org/) for adding your own + compact identifier type and registering your DRS server as a resolver. We + document this in more detail in the [main specification + document](./index.html). + + + Now the question is how does a client resolve your newly registered + compact identifier for your DRS server? *It turns out, whether specific to + a DRS implementation or using existing compact identifiers like ARKs or + DOIs, the DRS client resolution process for compact identifier-based URIs + is exactly the same.* We briefly run through process below for a new + compact identifier as an example but, again, a client will not need to do + anything different from the resolution process documented in "DRS Client + Compact Identifier-Based URI Resolution Process - Existing Compact + Identifier Provider". + + + Now we can issue DRS URI for our data objects like: + + + ``` + + drs://mydrsprefix:12345 + + ``` + + + This is a little simpler than working with DOIs or other existing compact + identifier issuers out there since we can create our own IDs and not have + to allocate them through a third-party service (see "Issuing Existing + Compact Identifiers for Use with Your DRS Server" below). + + + With a namespace of "mydrsprefix", the following GET request will return + information about the namespace: + + + ``` + + GET + https://registry.api.identifiers.org/restApi/namespaces/search/findByPrefix?prefix=mydrsprefix + + ``` + + + *Of course, this is a hypothetical example so the actual API call won’t + work, but you can see the GET request is identical to "DRS Client Compact + Identifier-Based URI Resolution Process - Existing Compact Identifier + Provider".* + + + This information then points to resolvers for the "mydrsprefix" namespace. + Hypothetically, this "mydrsprefix" namespace was assigned a namespace ID + of 1829 by identifiers.org. This "id" has nothing to do with compact + identifier accessions (which are used in the URL pattern as `{$id}` below) + or DRS IDs. This namespace ID (1829 below) is purely an identifiers.org + internal ID for use with their APIs: + + + ``` + + GET + https://registry.api.identifiers.org/restApi/resources/search/findAllByNamespaceId?id=1829 + + ``` + + + *Like the previous GET request this URL won’t work but you can see the GET + request is identical to "DRS Client Compact Identifier-Based URI + Resolution Process - Existing Compact Identifier Provider".* + + + This returns enough information to, ultimately, identify one or more + resolvers and each have a URL pattern that, for DRS-supporting systems, + provides a URL template for making a successful DRS GET request. For + example, the "mydrsprefix" urlPattern is: + + + ``` + + urlPattern: "https://mydrs.server.org/ga4gh/drs/v1/objects/{$id}" + + ``` + + + And the `{$id}` here refers to the accession from the compact identifier + (in this example the accession is `12345`). If applicable, a provider code + can be supplied in the above requests to specify a particular mirror if + there are multiple resolvers for this namespace. + + + Given this information you now know you can make a GET on the URL: + + + ``` + + GET https://mydrs.server.org/ga4gh/drs/v1/objects/12345 + + ``` + + + So, compared to using a third party service like DOIs and ARKs, this would + be a direct pointer to a DRS server. However, just as with "DRS Client + Compact Identifier-Based URI Resolution Process - Existing Compact + Identifier Provider", the client should always be prepared to follow HTTPS + redirects. + + + *To summarize, a client resolving a custom compact identifier registered + for a single DRS server is actually the same as resolving using a + third-party compact identifier service like ARKs or DOIs with a DRS + server, just make sure to follow redirects in all cases.* + + + **Note: Issuing Existing Compact Identifiers for Use with Your DRS + Server** + + + See the documentation on [n2t.net](https://n2t.net/e/compact_ids.html) and + [identifiers.org](https://docs.identifiers.org/) for information about all + the compact identifiers that are supported. You can choose to use an + existing compact identifier provider for your DRS server, as we did in the + example above using DOIs ("DRS Client Compact Identifier-Based URI + Resolution Process - Existing Compact Identifier Provider"). Just keep in + mind, each provider will have their own approach for generating compact + identifiers and associating them with a DRS data object URL. Some compact + identifier providers, like DOIs, provide a method whereby you can register + in their network and get your own prefix, allowing you to mint your own + accessions. Other services, like the University of California’s + [EZID](https://ezid.cdlib.org/) service, provide accounts and a mechanism + to mint accessions centrally for each of your data objects. For + experimentation we recommend you take a look at the EZID website that + allows you to create DOIs and ARKs and associate them with your data + object URLs on your DRS server for testing purposes. +components: {} diff --git a/preview/release/drs-1.4.0/openapi.json b/preview/release/drs-1.4.0/openapi.json new file mode 100644 index 00000000..068215d8 --- /dev/null +++ b/preview/release/drs-1.4.0/openapi.json @@ -0,0 +1,1351 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Data Repository Service", + "version": "1.4.0", + "x-logo": { + "url": "https://www.ga4gh.org/wp-content/themes/ga4gh/dist/assets/svg/logos/logo-full-color.svg" + }, + "termsOfService": "https://www.ga4gh.org/terms-and-conditions/", + "contact": { + "name": "GA4GH Cloud Work Stream", + "email": "ga4gh-cloud@ga4gh.org" + }, + "license": { + "name": "Apache 2.0", + "url": "https://raw.githubusercontent.com/ga4gh/data-repository-service-schemas/master/LICENSE" + } + }, + "servers": [ + { + "url": "https://{serverURL}/ga4gh/drs/v1", + "variables": { + "serverURL": { + "default": "drs.example.org", + "description": "DRS server endpoints MUST be prefixed by the '/ga4gh/drs/v1' endpoint path\n" + } + } + } + ], + "security": [ + {}, + { + "BasicAuth": [] + }, + { + "BearerAuth": [] + } + ], + "tags": [ + { + "name": "Introduction", + "description": "The Data Repository Service (DRS) API provides a generic interface to data repositories so data consumers, including workflow systems, can access data objects in a single, standard way regardless of where they are stored and how they are managed. The primary functionality of DRS is to map a logical ID to a means for physically retrieving the data represented by the ID. The sections below describe the characteristics of those IDs, the types of data supported, how they can be pointed to using URIs, and how clients can use these URIs to ultimately make successful DRS API requests. This document also describes the DRS API in detail and provides information on the specific endpoints, request formats, and responses. This specification is intended for developers of DRS-compatible services and of clients that will call these DRS services.\n\nThe key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119).\n" + }, + { + "name": "DRS API Principles", + "description": "## DRS IDs\n\nEach implementation of DRS can choose its own id scheme, as long as it follows these guidelines:\n\n* DRS IDs are strings made up of uppercase and lowercase letters, decimal digits, hyphen, period, underscore and tilde [A-Za-z0-9.-_~]. See [RFC 3986 § 2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3).\n* DRS IDs can contain other characters, but they MUST be encoded into valid DRS IDs whenever they are used in API calls. This is because non-encoded IDs may interfere with the interpretation of the objects/{id}/access endpoint. To overcome this limitation use percent-encoding of the ID, see [RFC 3986 § 2.4](https://datatracker.ietf.org/doc/html/rfc3986#section-2.4)\n* One DRS ID MUST always return the same object data (or, in the case of a collection, the same set of objects). This constraint aids with reproducibility.\n* DRS implementations MAY have more than one ID that maps to the same object.\n* DRS version 1.x does NOT support semantics around multiple versions of an object. (For example, there’s no notion of “get latest version” or “list all versions”.) Individual implementations MAY choose an ID scheme that includes version hints.\n\n## DRS URIs\n\nFor convenience, including when passing content references to a [WES server](https://github.com/ga4gh/workflow-execution-service-schemas), we define a [URI scheme](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Generic_syntax) for DRS-accessible content. This section documents the syntax of DRS URIs, and the rules clients follow for translating a DRS URI into a URL that they use for making the DRS API calls described in this spec.\n\nThere are two styles of DRS URIs, Hostname-based and Compact Identifier-based, both using the `drs://` URI scheme. DRS servers may choose either style when exposing references to their content;. DRS clients MUST support resolving both styles.\n\nTip:\n> See [Appendix: Background Notes on DRS URIs](#tag/Background-Notes-on-DRS-URIs) for more information on our design motivations for DRS URIs.\n\n### Hostname-based DRS URIs\n\nHostname-based DRS URIs are simpler than compact identifier-based URIs. They contain the DRS server name and the DRS ID only and can be converted directly into a fetchable URL based on a simple rule. They take the form:\n\n```\ndrs:///\n```\n\nDRS URIs of this form mean *\\\"you can fetch the content with DRS id \\ from the DRS server at \\\\\"*.\nFor example, here are the client resolution steps if the URI is:\n\n```\ndrs://drs.example.org/314159\n```\n\n1. The client parses the string to extract the hostname of “drs.example.org” and the id of “314159”.\n2. The client makes a GET request to the DRS server, using the standard DRS URL syntax:\n\n```\nGET https://drs.example.org/ga4gh/drs/v1/objects/314159\n```\n\nThe protocol is always https and the port is always the standard 443 SSL port. It is invalid to include a different port in a DRS hostname-based URI.\n\nTip:\n> See the [Appendix: Hostname-Based URIs](#tag/Hostname-Based-URIs) for information on how hostname-based DRS URI resolution to URLs is likely to change in the future, when the DRS v2 major release happens.\n\n### Compact Identifier-based DRS URIs\n\nCompact Identifier-based DRS URIs use resolver registry services (specifically, [identifiers.org](https://identifiers.org/) and [n2t.net (Name-To-Thing)](https://n2t.net/)) to provide a layer of indirection between the DRS URI and the DRS server name — the actual DNS name of the DRS server is not present in the URI. This approach is based on the Joint Declaration of Data Citation Principles as detailed by [Wimalaratne et al (2018)](https://www.nature.com/articles/sdata201829).\n\nFor more information, see the document [More Background on Compact Identifiers](./more-background-on-compact-identifiers.html).\n\nCompact Identifiers take the form:\n\n```\ndrs://[provider_code/]namespace:accession\n```\n\nTogether, provider code and the namespace are referred to as the `prefix`. The provider code is optional and is used by identifiers.org/n2t.net for compact identifier resolver mirrors. Both the `provider_code` and `namespace` disallow spaces or punctuation, only lowercase alphanumerical characters, underscores and dots are allowed (e.g. [A-Za-z0-9._]).\n\nTip:\n> See the [Appendix: Compact Identifier-Based URIs](#tag/Compact-Identifier-Based-URIs) for more background on Compact Identifiers and resolver registry services like identifiers.org/n2t.net (aka meta-resolvers), how to register prefixes, possible caching strategies, and security considerations.\n\n#### For DRS Servers\n\nIf your DRS implementation will issue DRS URIs based *on your own* compact identifiers, you MUST first register a new prefix with identifiers.org (which is automatically mirrored to n2t.net). You will also need to include a provider resolver resource in this registration which links the prefix to your DRS server, so that DRS clients can get sufficient information to make a successful DRS GET request. For clarity, we recommend you choose a namespace beginning with `drs`.\n\n#### For DRS Clients\n\nA DRS client parses the DRS URI compact identifier components to extract the prefix and the accession, and then uses meta-resolver APIs to locate the actual DRS server. For example, here are the client resolution steps if the URI is:\n\n```\ndrs://drs.42:314159\n```\n\n1. The client parses the string to extract the prefix of `drs.42` and the accession of `314159`, using the first occurrence of a colon (\":\") character after the initial `drs://` as a delimiter. (The colon character is not allowed in a Hostname-based DRS URI, making it easy to tell them apart.)\n\n2. The client makes API calls to a meta-resolver to look up the URL pattern for the namespace. (See [Calling Meta-Resolver APIs for Compact Identifier-Based DRS URIs](#section/Calling-Meta-Resolver-APIs-for-Compact-Identifier-Based-DRS-URIs) for details.) The URL pattern is a string containing a `{$id}` parameter, such as:\n\n```\nhttps://drs.myexample.org/ga4gh/drs/v1/objects/{$id}\n```\n\n3. The client generates a DRS URL from the URL template by replacing {$id} with the accession it extracted in step 1. It then makes a GET request to the DRS server:\n\n```\nGET https://drs.myexample.org/ga4gh/drs/v1/objects/314159\n```\n\n4. The client follows any HTTP redirects returned in step 3, in case the resolver goes through an extra layer of redirection.\n\nFor performance reasons, DRS clients SHOULD cache the URL pattern returned in step 2, with a suggested 24 hour cache life.\n\n### Choosing a URI Style\n\nDRS servers can choose to issue either hostname-based or compact identifier-based DRS URIs, and can be confident that compliant DRS clients will support both. DRS clients must be able to accommodate both URI types. Tradeoffs that DRS server builders, and third parties who need to cite DRS objects in datasets, workflows or elsewhere, may want to consider include:\n\n*Table 1: Choosing a URI Style*\n\n| | Hostname-based | Compact Identifier-based |\n|-------------------|----------------|--------------------------|\n| URI Durability | URIs are valid for as long as the server operator maintains ownership of the published DNS address. (They can of course point that address at different physical serving infrastructure as often as they would like.) | URIs are valid for as long as the server operator maintains ownership of the published compact identifier resolver namespace. (They also depend on the meta-resolvers like identifiers.org/n2t.net remaining operational, which is intended to be essentially forever.) |\n| Client Efficiency | URIs require minimal client logic, and no network requests, to resolve. | URIs require small client logic, and 1-2 cacheable network requests, to resolve. |\n| Security | Servers have full control over their own security practices. | Server operators, in addition to maintaining their own security practices, should confirm they are comfortable with the resolver registry security practices, including protection against denial of service and namespace-hijacking attacks. (See the [Appendix: Compact Identifier-Based URIs](#tag/Compact-Identifier-Based-URIs) for more information on resolver registry security.) |\n\n## DRS Datatypes\nDRS's job is data access, period. Therefore, the DRS API supports a simple flat content model -- every `DrsObject`, like a file, represents a single opaque blob of bytes. DRS has no understanding of the meaning of objects and only provides simple domain-agnostic metadata. Understanding the semantics of specific object types is the responsibility of the applications that use DRS to fetch those objects (e.g. samtools for BAM files, DICOM viewers for DICOM objects).\n\n### Atomic Objects\nDRS can be used to access individual objects of all kinds, simple or complex, large or small, stored in type-specific formats (e.g. BAM files, VCF files, CSV files). At the API level these are all the same; at the application level, DRS clients and servers are expected to agree on object semantics using non-DRS mechanisms, including but not limited to the GA4GH Data Connect API.\n\n### Compound Objects\nDRS can also be used to access compound objects, consisting of two or more atomic objects related to each other in a well-specified way. See the [Appendix: Compound Objects](#tag/Working-With-Compound-Objects) for suggested best practices for working with compound objects.\n\n### [DEPRECATED] Bundles\nPrevious versions of the DRS API spec included support for a *bundle* content type, which was a folder-like collection of other DRS objects (either blobs or bundles), represented by a `DrsObject` with a `contents` array. As of v1.3, bundles have been deprecated in favor of the best practices documented in the [Appendix: Compound Objects](#tag/Working-With-Compound-Objects). A future version of the API spec may remove bundle support entirely and/or replace bundles with a scalable approach based on the needs of our driver projects.\n\n## Read-only\n\nDRS v1 is a read-only API. We expect that each implementation will define its own mechanisms and interfaces (graphical and/or programmatic) for adding and updating data.\n\n## Standards\n\nThe DRS API specification is written in OpenAPI and embodies a RESTful service philosophy. It uses JSON in requests and responses and standard HTTPS on port 443 for information transport. Optionally, it\nsupports authentication and authorization using the [GA4GH Passport](https://github.com/ga4gh-duri/ga4gh-duri.github.io/tree/master/researcher_ids) standard.\n" + }, + { + "name": "Authorization & Authentication", + "description": "## Making DRS Requests\n\nThe DRS implementation is responsible for defining and enforcing an authorization policy that determines which users are allowed to make which requests. GA4GH recommends that DRS implementations use an OAuth 2.0 [bearer token](https://oauth.net/2/bearer-tokens/) or a [GA4GH Passport](https://github.com/ga4gh-duri/ga4gh-duri.github.io/tree/master/researcher_ids), although they can choose other mechanisms if appropriate.\n\n## Fetching DRS Objects\n\nThe DRS API allows implementers to support a variety of different content access policies, depending on what `AccessMethod` records they return. Implementers have a choice to make the\nGET /objects/{object_id} and GET /objects/{object_id}/access/{access_id} calls open or requiring a Basic, Bearer, or Passport token (Passport requiring a POST). The following describes the\nvarious access approaches following a successful GET/POST /objects/{object_id} request in order to them obtain access to the bytes for a given object ID/access ID:\n\n* public content:\n * server provides an `access_url` with a `url` and no `headers`\n * caller fetches the object bytes without providing any auth info\n* private content that requires the caller to have out-of-band auth knowledge (e.g. service account credentials):\n * server provides an `access_url` with a `url` and no `headers`\n * caller fetches the object bytes, passing the auth info they obtained out-of-band\n* private content that requires the caller to pass an Authorization token:\n * server provides an `access_url` with a `url` and `headers`\n * caller fetches the object bytes, passing auth info via the specified header(s)\n* private content that uses an expensive-to-generate auth mechanism (e.g. a signed URL):\n * server provides an `access_id`\n * caller passes the `access_id` to the `/access` endpoint\n * server provides an `access_url` with the generated mechanism (e.g. a signed URL in the `url` field)\n * caller fetches the object bytes from the `url` (passing auth info from the specified headers, if any)\n\nIn the approaches above [GA4GH Passports](https://github.com/ga4gh-duri/ga4gh-duri.github.io/tree/master/researcher_ids) are not mentioned and that is on purpose. A DRS server may return a Bearer token or other platform-specific token in a header in response to a valid Bearer token or GA4GH Passport (Option 3 above). But it is not the responsibility of a DRS server to return a Passport, that is the responsibility of a Passport Broker and outside the scope of DRS.\n\nDRS implementers should ensure their solutions restrict access to targets as much as possible, detect attempts to exploit through log monitoring, and they are prepared to take action if an exploit in their DRS implementation is detected.\n\n## Authentication\n\n### Discovery\n\nThe APIs to fetch [DrsObjects](#tag/DrsObjectModel) and [AccessURLs](#tag/AccessURLModel) may require authorization. The authorization mode may vary between DRS objects hosted by a service. The authorization mode may vary between the APIs to fetch a [DrsObject](#tag/DrsObjectModel) and an associated [AccessURL](#tag/AccessURLModel). Implementers should indicate how to authenticate to fetch a [DrsObject](#tag/DrsObjectModel) by implementing the [OptionsOjbect](#operation/OptionsObject) API. Implementers should indicate how to authenticate to fetch an [AccessURL](#tag/AccessURLModel) within a [DrsObject](#tag/DrsObjectModel). \n\n### Modes\n\n#### BasicAuth\n\nA valid authorization token must be passed in the 'Authorization' header, e.g. \"Basic ${token_string}\"\n\n| Security Scheme Type | HTTP |\n|----------------------|------|\n| **HTTP Authorization Scheme** | basic |\n\n#### BearerAuth\n\nA valid authorization token must be passed in the 'Authorization' header, e.g. \"Bearer ${token_string}\"\n\n| Security Scheme Type | HTTP |\n|----------------------|------|\n| **HTTP Authorization Scheme** | bearer |\n\n#### PassportAuth\n\nA valid authorization [GA4GH Passport](https://github.com/ga4gh-duri/ga4gh-duri.github.io/tree/master/researcher_ids) token must be passed in the body of a POST request\n\n| Security Scheme Type | HTTP |\n|----------------------|------|\n| **HTTP POST** | tokens[] |\n" + }, + { + "name": "Objects" + }, + { + "name": "Service Info" + }, + { + "name": "AccessMethodModel", + "x-displayName": "AccessMethod", + "description": "\n" + }, + { + "name": "AccessURLModel", + "x-displayName": "AccessURL", + "description": "\n" + }, + { + "name": "ChecksumModel", + "x-displayName": "Checksum", + "description": "\n" + }, + { + "name": "ContentsObjectModel", + "x-displayName": "ContentsObject", + "description": "\n" + }, + { + "name": "DrsObjectModel", + "x-displayName": "DrsObject", + "description": "\n" + }, + { + "name": "ErrorModel", + "x-displayName": "Error", + "description": "\n" + }, + { + "name": "Motivation", + "description": "\n \n \n \n \n
\n Data sharing requires portable data, consistent with the FAIR data principles (findable, accessible, interoperable, reusable). Today’s researchers and clinicians are surrounded by potentially useful data, but often need bespoke tools and processes to work with each dataset. Today’s data publishers don’t have a reliable way to make their data useful to all (and only) the people they choose. And today’s data controllers are tasked with implementing standard controls of non-standard mechanisms for data access.\n \n \n \n Figure 1: there’s an ocean of data, with many different tools to drink from it, but no guarantee that any tool will work with any subset of the data\n \n
\n\n\n \n \n \n \n
\n We need a standard way for data producers to make their data available to data consumers, that supports the control needs of the former and the access needs of the latter. And we need it to be interoperable, so anyone who builds access tools and systems can be confident they’ll work with all the data out there, and anyone who publishes data can be confident it will work with all the tools out there.\n \n \n \n Figure 2: by defining a standard Data Repository API, and adapting tools to use it, every data publisher can now make their data useful to every data consumer\n \n
\n\n\n \n \n \n \n
\n We envision a world where:\n
    \n
  • \n there are many many data consumers, working in research and in care, who can use the tools of their choice to access any and all data that they have permission to see\n
  • \n
  • \n there are many data access tools and platforms, supporting discovery, visualization, analysis, and collaboration\n
  • \n
  • \n there are many data repositories, each with their own policies and characteristics, which can be accessed by a variety of tools\n
  • \n
  • \n there are many data publishing tools and platforms, supporting a variety of data lifecycles and formats\n
  • \n
  • \n there are many many data producers, generating data of all types, who can use the tools of their choice to make their data as widely available as is appropriate\n
  • \n
\n
\n \n \n Figure 3: a standard Data Repository API enables an ecosystem of data producers and consumers\n \n
\n\nThis spec defines a standard **Data Repository Service (DRS) API** (“the yellow box”), to enable that ecosystem of data producers and consumers. Our goal is that the only thing data consumers need to know about a data repo is *\\\"here’s the DRS endpoint to access it\\\"*, and the only thing data publishers need to know to tap into the world of consumption tools is *\\\"here’s how to tell it where my DRS endpoint lives\\\"*.\n\n## Federation\n\nThe world’s biomedical data is controlled by groups with very different policies and restrictions on where their data lives and how it can be accessed. A primary purpose of DRS is to support unified access to disparate and distributed data. (As opposed to the alternative centralized model of \"let’s just bring all the data into one single data repository”, which would be technically easier but is no more realistic than “let’s just bring all the websites into one single web host”.)\n\nIn a DRS-enabled world, tool builders don’t have to worry about where the data their tools operate on lives — they can count on DRS to give them access. And tool users only need to know which DRS server is managing the data they need, and whether they have permission to access it; they don’t have to worry about how to physically get access to, or (worse) make a copy of the data. For example, if I have appropriate permissions, I can run a pooled analysis where I run a single tool across data managed by different DRS servers, potentially in different locations.\n" + }, + { + "name": "Working With Compound Objects", + "description": "## Compound Objects\n\nThe DRS API supports access to data objects, with each `DrsObject` representing a single opaque blob of bytes. Much content (e.g. VCF files) is well represented as a single atomic `DrsObject`. Some content, however (e.g. DICOM images) is best represented as a compound object consisting of a structured collection of atomic `DrsObject`s. In both cases, DRS isn't aware of the semantics of the objects it serves -- understanding those semantics is the responsibility of the applications that call DRS.\n\nCommon examples of compound objects in biomedicine include:\n* BAM+BAI genomic reads, with a small index (the BAI object) to large data (the BAM object), each object using a well-defined file format.\n* DICOM images, with a contents object pointing to one or more raw image objects, each containing pixels from different aspects of a single logical biomedical image (e.g. different z-coordinates)\n* studies, with a single table of contents listing multiple objects of various types that were generated together and are meant to be processed together\n\n## Best Practice: Manifests\n\nAs with atomic objects, DRS applications and servers are expected to agree on the semantics of compound objects using non-DRS mechanisms. The recommended best practice for representing a particular compound object type is:\n1. Define a manifest file syntax, which contains the DRS IDs of the constituent atomic objects, plus type-specific information about the relationship between those constituents.\n * Manifest file syntax isn't prescribed by the spec, but we expect they will often be JSON files.\n * For example, for a BAM+BAI pair the manifest file could contain two key-value pairs mapping the type of each constituent file to its DRS ID.\n3. Make manifest objects and their constituent objects available using standard DRS mechanisms -- each object is referenced via its own DRS ID, just like any other atomic object.\n * For example, for a BAM+BAI pair, there would be three DRS IDs -- one for the manifest, one for the BAM, and one for the BAI.\n5. Document the expected client logic for processing compound objects of interest. This logic typically consists of using standard DRS mechanisms to fetch the manifest, parsing its syntax, extracting the DRS IDs of constituent objects, and using standard DRS mechanisms to fetch the constituents as needed.\n * In some cases the application will always want to fetch all of the constituents; in other cases it may want to initially fetch a subset, and only fetch the others on demand. For example, a DICOM image viewer may only want to fetch the layers that are being rendered.\n" + }, + { + "name": "Background Notes on DRS URIs", + "description": "## Design Motivation\n\nDRS URIs are aligned with the [FAIR data principles](https://www.nature.com/articles/sdata201618) and the [Joint Declaration of Data Citation Principles](https://www.nature.com/articles/sdata20182) — both hostname-based and compact identifier-based URIs provide globally unique, machine-resolvable, persistent identifiers for data.\n\n* We require all URIs to begin with `drs://` as a signal to humans and systems consuming these URIs that the response they will ultimately receive, after transforming the URI to a fetchable URL, will be a DRS JSON packet. This signal differentiates DRS URIs from the wide variety of other entities (HTML documents, PDFs, ontology notes, etc.) that can be represented by compact identifiers.\n* We support hostname-based URIs because of their simplicity and efficiency for server and client implementers.\n* We support compact identifier-based URIs, and the meta-resolver services of identifiers.org and n2t.net (Name-to-Thing), because of the wide adoption of compact identifiers in the research community. as detailed by [Wimalaratne et al (2018)](https://www.nature.com/articles/sdata201829) in \"Uniform resolution of compact identifiers for biomedical data.\"\n" + }, + { + "name": "Compact Identifier-Based URIs", + "description": "**Note: Identifiers.org/n2t.net API Changes**\n\nThe examples below show the current API interactions with [n2t.net](https://n2t.net/e/compact_ids.html) and [identifiers.org](https://docs.identifiers.org/) which may change over time. Please refer to the documentation from each site for the most up-to-date information. We will make best efforts to keep the DRS specification current but DRS clients MUST maintain their ability to use either the identifiers.org or n2t.net APIs to resolve compact identifier-based DRS URIs.\n\n## Registering a DRS Server on a Meta-Resolver\n\nSee the documentation on the [n2t.net](https://n2t.net/e/compact_ids.html) and [identifiers.org](https://docs.identifiers.org/) meta-resolvers for adding your own compact identifier type and registering your DRS server as a resolver. You can register new prefixes (or mirrors by adding resource provider codes) for free using a simple online form. For more information see [More Background on Compact Identifiers](./more-background-on-compact-identifiers.html).\n\n## Calling Meta-Resolver APIs for Compact Identifier-Based DRS URIs\n\nClients resolving Compact Identifier-based URIs need to convert a prefix (e.g. “drs.42”) into a URL pattern. They can do so by calling either the identifiers.org or the n2t.net API, since the two meta-resolvers keep their mapping databases in sync.\n\n### Calling the identifiers.org API as a Client\n\nIt takes two API calls to get the URL pattern.\n\n1. The client makes a GET request to identifiers.org to find information about the prefix:\n\n```\nGET https://registry.api.identifiers.org/restApi/namespaces/search/findByPrefix?prefix=drs.42\n```\n\nThis request returns a JSON structure including various URLs containing an embedded namespace id, such as:\n\n```\n\"namespace\" : {\n \"href\":\"https://registry.api.identifiers.org/restApi/namespaces/1234\"\n}\n```\n\n2. The client extracts the namespace id (in this example 1234), and uses it to make a second GET request to identifiers.org to find information about the namespace:\n\n```\nGET https://registry.api.identifiers.org/restApi/resources/search/findAllByNamespaceId?id=1234\n```\n\nThis request returns a JSON structure including an urlPattern field, whose value is a URL pattern containing a ${id} parameter, such as:\n\n```\n\"urlPattern\" : \"https://drs.myexample.org/ga4gh/drs/v1/objects/{$id}\"\n```\n\n### Calling the n2t.net API as a Client\n\nIt takes one API call to get the URL pattern.\n\nThe client makes a GET request to n2t.net to find information about the namespace. (Note the trailing colon.)\n\n```\nGET https://n2t.net/drs.42:\n```\n\nThis request returns a text structure including a redirect field, whose value is a URL pattern containing an `$id` parameter, such as:\n\n```\nredirect: https://drs.myexample.org/ga4gh/drs/v1/objects/$id\n```\n\n## Caching with Compact Identifiers\n\nIdentifiers.org/n2t.net compact identifier resolver records do not change frequently. This reality is useful for caching resolver records and their URL patterns for performance reasons. Builders of systems that use compact identifier-based DRS URIs should cache prefix resolver records from identifiers.org/n2t.net and occasionally refresh the records (such as every 24 hours). This approach will reduce the burden on these community services since we anticipate many DRS URIs will be regularly resolved in workflow systems. Alternatively, system builders may decide to directly mirror the registries themselves, instructions are provided on the identifiers.org/n2t.net websites.\n\n## Security with Compact Identifiers\n\nAs mentioned earlier, identifiers.org/n2t.net performs some basic verification of new prefixes and provider code mirror registrations on their sites. However, builders of systems that consume and resolve DRS URIs may have certain security compliance requirements and regulations that prohibit relying on an external site for resolving compact identifiers. In this case, systems under these security and compliance constraints may wish to whitelist certain compact identifier resolvers and/or vet records from identifiers.org/n2t.net before enabling in their systems.\n\n## Accession Encoding to Valid DRS IDs\n\nThe compact identifier format used by identifiers.org/n2t.net does not percent-encode reserved URI characters but, instead, relies on the first \":\" character to separate prefix from accession. Since these accessions can contain any characters, and characters like \"/\" will interfere with DRS API calls, you *must* percent encode the accessions extracted from DRS compact identifier-based URIs when using as DRS IDs in subsequent DRS GET requests. An easy way for a DRS client to handle this is to get the initial DRS object JSON response from whatever redirects the compact identifier resolves to, then look for the `self_uri` in the JSON, which will give you the correctly percent-encoded DRS ID for subsequent DRS API calls such as the `access` method.\n\n## Additional Examples\n\nFor additional examples, see the document [More Background on Compact Identifiers](./more-background-on-compact-identifiers.html).\n" + }, + { + "name": "Hostname-Based URIs", + "description": "## Encoding DRS IDs\n\nIn hostname-based DRS URIs, the ID is always percent-encoded to ensure special characters do not interfere with subsequent DRS endpoint calls. As such, \":\" is not allowed in the URI and is a convenient way of differentiating from a compact identifier-based DRS URI. Also, if a given DRS service implementation uses compact identifier accessions as their DRS IDs, they must be percent encoded before using them as DRS IDs in hostname-based DRS URIs and subsequent GET requests to a DRS service endpoint.\n" + }, + { + "name": "GA4GH Service Registry", + "description": "The [GA4GH Service Registry API specification](https://github.com/ga4gh-discovery/ga4gh-service-registry) allows information about GA4GH-compliant web services, including DRS services, to be aggregated into registries and made available via a standard API. The following considerations should be followed when registering DRS services within a service registry.\n\n* The DRS service attributes returned by `/service-info` (i.e. `id`, `name`, `description`, etc.) should have the same values as the registry entry for that service.\n* The value of the `type` object's `artifact` property should be `drs` (i.e. the same as it appears in `service-info`)\n* Each entry in a Service Registry must have a `url`, indicating the base URL to the web service. For DRS services, the registered `url` must include everything up to\nthe standardized `/ga4gh/drs/v1` path. Clients should be able to assume that:\n + Adding `/ga4gh/drs/v1/objects/{object_id}` to the registered `url` will hit the `DrsObject` endpoint\n + Adding `/ga4gh/drs/v1/service-info` to the registered `url` will hit the Service Info endpoint\n\nExample listing of a DRS API registration from a service registry's `/services` endpoint:\n\n```\n[\n {\n \"id\": \"com.example.drs\",\n \"name\": \"Example DRS API\",\n \"type\": {\n \"group\": \"org.ga4gh\",\n \"artifact\": \"drs\",\n \"version\": \"1.4.0\"\n },\n \"description\": \"The Data Repository Service (DRS) API ...\",\n \"organization\": {\n \"id\": \"com.example\",\n \"name\": \"Example Company\"\n },\n \"contactUrl\": \"mailto:support@example.com\",\n \"documentationUrl\": \"https://docs.example.com/docs/drs\",\n \"createdAt\": \"2021-08-09T00:00:00Z\",\n \"updatedAt\": \"2021-08-09T12:30:00Z\",\n \"environment\": \"production\",\n \"version\": \"1.13.4\",\n \"url\": \"https://drs-service.example.com\"\n }\n]\n```\n" + } + ], + "x-tagGroups": [ + { + "name": "Overview", + "tags": [ + "Introduction", + "DRS API Principles", + "Authorization & Authentication" + ] + }, + { + "name": "Operations", + "tags": [ + "Objects", + "Service Info" + ] + }, + { + "name": "Models", + "tags": [ + "AccessMethodModel", + "AccessURLModel", + "ChecksumModel", + "ContentsObjectModel", + "DrsObjectModel", + "ErrorModel" + ] + }, + { + "name": "Appendices", + "tags": [ + "Motivation", + "Working With Compound Objects", + "Background Notes on DRS URIs", + "Compact Identifier-Based URIs", + "Hostname-Based URIs", + "GA4GH Service Registry" + ] + } + ], + "paths": { + "/service-info": { + "get": { + "summary": "Retrieve information about this service", + "description": "Returns information about the DRS service\n\nExtends the\n[v1.0.0 GA4GH Service Info specification](https://github.com/ga4gh-discovery/ga4gh-service-info)\nas the standardized format for GA4GH web services to self-describe.\n\nAccording to the \n[service-info type registry](https://github.com/ga4gh/TASC/blob/master/service-info/ga4gh-service-info.json)\nmaintained by the [Technical Alignment Sub Committee (TASC)](https://github.com/ga4gh/TASC),\na DRS service MUST have:\n * a `type.group` value of `org.ga4gh`\n * a `type.artifact` value of `drs`\n\ne.g.\n```\n{\n \"id\": \"com.example.drs\",\n \"description\": \"Serves data according to DRS specification\",\n ...\n \"type\": {\n \"group\": \"org.ga4gh\",\n \"artifact\": \"drs\"\n }\n ...\n}\n```\n\nSee the [Service Registry Appendix](#tag/GA4GH-Service-Registry) for more information on how to register a DRS service with a service registry.", + "operationId": "GetServiceInfo", + "responses": { + "200": { + "$ref": "#/components/responses/200ServiceInfo" + }, + "500": { + "$ref": "#/components/responses/500InternalServerError" + } + }, + "tags": [ + "Service Info" + ] + } + }, + "/objects/{object_id}": { + "options": { + "summary": "Get Authorization info about a DrsObject.", + "security": [ + {} + ], + "description": "Returns a list of `Authorizations` that can be used to determine how to authorize requests to `GetObject` or `PostObject`.", + "operationId": "OptionsObject", + "parameters": [ + { + "$ref": "#/components/parameters/ObjectId" + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/200OkAuthorizations" + }, + "204": { + "$ref": "#/components/responses/AuthorizationsNotSupported" + }, + "400": { + "$ref": "#/components/responses/400BadRequest" + }, + "404": { + "$ref": "#/components/responses/404NotFoundDrsObject" + }, + "405": { + "$ref": "#/components/responses/AuthorizationsNotSupported" + }, + "500": { + "$ref": "#/components/responses/500InternalServerError" + } + }, + "tags": [ + "Objects" + ], + "x-swagger-router-controller": "ga4gh.drs.server" + }, + "get": { + "summary": "Get info about a DrsObject.", + "description": "Returns object metadata, and a list of access methods that can be used to fetch object bytes.", + "operationId": "GetObject", + "parameters": [ + { + "$ref": "#/components/parameters/ObjectId" + }, + { + "$ref": "#/components/parameters/Expand" + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/200OkDrsObject" + }, + "202": { + "$ref": "#/components/responses/202Accepted" + }, + "400": { + "$ref": "#/components/responses/400BadRequest" + }, + "401": { + "$ref": "#/components/responses/401Unauthorized" + }, + "403": { + "$ref": "#/components/responses/403Forbidden" + }, + "404": { + "$ref": "#/components/responses/404NotFoundDrsObject" + }, + "500": { + "$ref": "#/components/responses/500InternalServerError" + } + }, + "tags": [ + "Objects" + ], + "x-swagger-router-controller": "ga4gh.drs.server" + }, + "post": { + "summary": "Get info about a DrsObject through POST'ing a Passport.", + "description": "Returns object metadata, and a list of access methods that can be used to fetch object bytes.\nMethod is a POST to accommodate a JWT GA4GH Passport sent in the formData in order to authorize access.", + "operationId": "PostObject", + "security": [ + { + "PassportAuth": [] + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/200OkDrsObject" + }, + "202": { + "$ref": "#/components/responses/202Accepted" + }, + "400": { + "$ref": "#/components/responses/400BadRequest" + }, + "401": { + "$ref": "#/components/responses/401Unauthorized" + }, + "403": { + "$ref": "#/components/responses/403Forbidden" + }, + "404": { + "$ref": "#/components/responses/404NotFoundAccess" + }, + "500": { + "$ref": "#/components/responses/500InternalServerError" + } + }, + "tags": [ + "Objects" + ], + "x-swagger-router-controller": "ga4gh.drs.server", + "parameters": [ + { + "$ref": "#/components/parameters/ObjectId" + } + ], + "requestBody": { + "$ref": "#/components/requestBodies/PostObjectBody" + } + } + }, + "/objects": { + "options": { + "summary": "Get Authorization info about multiple DrsObjects.", + "security": [ + {} + ], + "description": "Returns a structure that contains for each DrsObjects a list of `Authorizations` that can be used to determine how to authorize requests to `GetObject` or `PostObject` (or bulk equivalents).", + "operationId": "OptionsBulkObject", + "responses": { + "200": { + "$ref": "#/components/responses/200OkBulkAuthorizations" + }, + "204": { + "$ref": "#/components/responses/AuthorizationsNotSupported" + }, + "400": { + "$ref": "#/components/responses/400BadRequest" + }, + "404": { + "$ref": "#/components/responses/404NotFoundDrsObject" + }, + "405": { + "$ref": "#/components/responses/AuthorizationsNotSupported" + }, + "413": { + "$ref": "#/components/responses/413RequestTooLarge" + }, + "500": { + "$ref": "#/components/responses/500InternalServerError" + } + }, + "tags": [ + "Objects" + ], + "x-swagger-router-controller": "ga4gh.drs.server", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "../components/parameters/BulkObjectIdNoPassport.yaml" + } + } + } + } + }, + "post": { + "summary": "Get info about multiple DrsObjects with an optional Passport(s).", + "description": "Returns an array of object metadata, and a list of access methods that can be used to fetch objects' bytes. Currently this is limited to use passports (one or more) or a single bearer token, so make sure your bulk request is for objects that all use the same passports/token.", + "operationId": "GetBulkObjects", + "security": [ + { + "PassportAuth": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Expand" + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/200OkDrsObjects" + }, + "202": { + "$ref": "#/components/responses/202Accepted" + }, + "400": { + "$ref": "#/components/responses/400BadRequest" + }, + "401": { + "$ref": "#/components/responses/401Unauthorized" + }, + "403": { + "$ref": "#/components/responses/403Forbidden" + }, + "404": { + "$ref": "#/components/responses/404NotFoundDrsObject" + }, + "413": { + "$ref": "#/components/responses/413RequestTooLarge" + }, + "500": { + "$ref": "#/components/responses/500InternalServerError" + } + }, + "tags": [ + "Objects" + ], + "x-swagger-router-controller": "ga4gh.drs.server", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BulkObjectId" + } + } + } + } + } + }, + "/objects/{object_id}/access/{access_id}": { + "get": { + "summary": "Get a URL for fetching bytes", + "description": "Returns a URL that can be used to fetch the bytes of a `DrsObject`.\nThis method only needs to be called when using an `AccessMethod` that contains an `access_id` (e.g., for servers that use signed URLs for fetching object bytes).", + "operationId": "GetAccessURL", + "responses": { + "200": { + "$ref": "#/components/responses/200OkAccess" + }, + "202": { + "$ref": "#/components/responses/202Accepted" + }, + "400": { + "$ref": "#/components/responses/400BadRequest" + }, + "401": { + "$ref": "#/components/responses/401Unauthorized" + }, + "403": { + "$ref": "#/components/responses/403Forbidden" + }, + "404": { + "$ref": "#/components/responses/404NotFoundAccess" + }, + "500": { + "$ref": "#/components/responses/500InternalServerError" + } + }, + "tags": [ + "Objects" + ], + "x-swagger-router-controller": "ga4gh.drs.server", + "parameters": [ + { + "$ref": "#/components/parameters/ObjectId" + }, + { + "$ref": "#/components/parameters/AccessId" + } + ] + }, + "post": { + "summary": "Get a URL for fetching bytes through POST'ing a Passport", + "description": "Returns a URL that can be used to fetch the bytes of a `DrsObject`.\nThis method only needs to be called when using an `AccessMethod` that contains an `access_id` (e.g., for servers that use signed URLs for fetching object bytes).\nMethod is a POST to accommodate a JWT GA4GH Passport sent in the formData in order to authorize access.", + "operationId": "PostAccessURL", + "security": [ + { + "PassportAuth": [] + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/200OkAccess" + }, + "202": { + "$ref": "#/components/responses/202Accepted" + }, + "400": { + "$ref": "#/components/responses/400BadRequest" + }, + "401": { + "$ref": "#/components/responses/401Unauthorized" + }, + "403": { + "$ref": "#/components/responses/403Forbidden" + }, + "404": { + "$ref": "#/components/responses/404NotFoundAccess" + }, + "500": { + "$ref": "#/components/responses/500InternalServerError" + } + }, + "tags": [ + "Objects" + ], + "x-swagger-router-controller": "ga4gh.drs.server", + "parameters": [ + { + "$ref": "#/components/parameters/ObjectId" + }, + { + "$ref": "#/components/parameters/AccessId" + } + ], + "requestBody": { + "$ref": "#/components/requestBodies/Passports" + } + } + }, + "/objects/access": { + "post": { + "summary": "Get URLs for fetching bytes from multiple objects with an optional Passport(s).", + "description": "Returns an array of URL objects that can be used to fetch the bytes of multiple `DrsObject`s.\nThis method only needs to be called when using an `AccessMethod` that contains an `access_id` (e.g., for servers that use signed URLs for fetching object bytes).\nCurrently this is limited to use passports (one or more) or a single bearer token, so make sure your bulk request is for objects that all use the same passports/token.", + "operationId": "GetBulkAccessURL", + "security": [ + { + "PassportAuth": [] + } + ], + "responses": { + "200": { + "$ref": "#/components/responses/200OkAccesses" + }, + "202": { + "$ref": "#/components/responses/202Accepted" + }, + "400": { + "$ref": "#/components/responses/400BadRequest" + }, + "401": { + "$ref": "#/components/responses/401Unauthorized" + }, + "403": { + "$ref": "#/components/responses/403Forbidden" + }, + "404": { + "$ref": "#/components/responses/404NotFoundAccess" + }, + "413": { + "$ref": "#/components/responses/413RequestTooLarge" + }, + "500": { + "$ref": "#/components/responses/500InternalServerError" + } + }, + "tags": [ + "Objects" + ], + "x-swagger-router-controller": "ga4gh.drs.server", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BulkObjectAccessId" + } + } + } + } + } + } + }, + "components": { + "securitySchemes": { + "BasicAuth": { + "type": "http", + "scheme": "basic", + "description": "A valid authorization token must be passed in the 'Authorization' header,\ne.g. \"Basic ${token_string}\"\n" + }, + "BearerAuth": { + "type": "http", + "scheme": "bearer", + "description": "A valid authorization token must be passed in the 'Authorization' header, e.g. \"Bearer ${token_string}\"" + }, + "PassportAuth": { + "type": "http", + "scheme": "bearer", + "x-in": "body", + "bearerFormat": "JWT", + "description": "A valid GA4GH Passport must be passed in the body of an HTTP POST request as a tokens[] array." + } + }, + "schemas": { + "ServiceType": { + "description": "Type of a GA4GH service", + "type": "object", + "required": [ + "group", + "artifact", + "version" + ], + "properties": { + "group": { + "type": "string", + "description": "Namespace in reverse domain name format. Use `org.ga4gh` for implementations compliant with official GA4GH specifications. For services with custom APIs not standardized by GA4GH, or implementations diverging from official GA4GH specifications, use a different namespace (e.g. your organization's reverse domain name).", + "example": "org.ga4gh" + }, + "artifact": { + "type": "string", + "description": "Name of the API or GA4GH specification implemented. Official GA4GH types should be assigned as part of standards approval process. Custom artifacts are supported.", + "example": "beacon" + }, + "version": { + "type": "string", + "description": "Version of the API or specification. GA4GH specifications use semantic versioning.", + "example": "1.0.0" + } + } + }, + "Service": { + "description": "GA4GH service", + "type": "object", + "required": [ + "id", + "name", + "type", + "organization", + "version" + ], + "properties": { + "id": { + "type": "string", + "description": "Unique ID of this service. Reverse domain name notation is recommended, though not required. The identifier should attempt to be globally unique so it can be used in downstream aggregator services e.g. Service Registry.", + "example": "org.ga4gh.myservice" + }, + "name": { + "type": "string", + "description": "Name of this service. Should be human readable.", + "example": "My project" + }, + "type": { + "$ref": "#/components/schemas/ServiceType" + }, + "description": { + "type": "string", + "description": "Description of the service. Should be human readable and provide information about the service.", + "example": "This service provides..." + }, + "organization": { + "type": "object", + "description": "Organization providing the service", + "required": [ + "name", + "url" + ], + "properties": { + "name": { + "type": "string", + "description": "Name of the organization responsible for the service", + "example": "My organization" + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL of the website of the organization (RFC 3986 format)", + "example": "https://example.com" + } + } + }, + "contactUrl": { + "type": "string", + "format": "uri", + "description": "URL of the contact for the provider of this service, e.g. a link to a contact form (RFC 3986 format), or an email (RFC 2368 format).", + "example": "mailto:support@example.com" + }, + "documentationUrl": { + "type": "string", + "format": "uri", + "description": "URL of the documentation of this service (RFC 3986 format). This should help someone learn how to use your service, including any specifics required to access data, e.g. authentication.", + "example": "https://docs.myservice.example.com" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "Timestamp describing when the service was first deployed and available (RFC 3339 format)", + "example": "2019-06-04T12:58:19Z" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "Timestamp describing when the service was last updated (RFC 3339 format)", + "example": "2019-06-04T12:58:19Z" + }, + "environment": { + "type": "string", + "description": "Environment the service is running in. Use this to distinguish between production, development and testing/staging deployments. Suggested values are prod, test, dev, staging. However this is advised and not enforced.", + "example": "test" + }, + "version": { + "type": "string", + "description": "Version of the service being described. Semantic versioning is recommended, but other identifiers, such as dates or commit hashes, are also allowed. The version should be changed whenever the service is updated.", + "example": "1.0.0" + } + } + }, + "DrsService": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "maxBulkRequestLength": { + "type": "integer", + "required": true, + "description": "The max length the bullk request endpoints can handle (>= 1) before generating a 413 error e.g. how long can the arrays bulk_object_ids and bulk_object_access_ids be for this server." + }, + "type": { + "type": "object", + "required": [ + "artifact" + ], + "properties": { + "artifact": { + "type": "string", + "enum": [ + "drs" + ], + "example": "drs" + } + } + } + } + }, + "Error": { + "type": "object", + "description": "An object that can optionally include information about the error.", + "properties": { + "msg": { + "type": "string", + "description": "A detailed error message." + }, + "status_code": { + "type": "integer", + "description": "The integer representing the HTTP status code (e.g. 200, 404)." + } + } + }, + "Checksum": { + "type": "object", + "required": [ + "checksum", + "type" + ], + "properties": { + "checksum": { + "type": "string", + "description": "The hex-string encoded checksum for the data" + }, + "type": { + "type": "string", + "description": "The digest method used to create the checksum.\nThe value (e.g. `sha-256`) SHOULD be listed as `Hash Name String` in the https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg[IANA Named Information Hash Algorithm Registry]. Other values MAY be used, as long as implementors are aware of the issues discussed in https://tools.ietf.org/html/rfc6920#section-9.4[RFC6920].\nGA4GH may provide more explicit guidance for use of non-IANA-registered algorithms in the future. Until then, if implementers do choose such an algorithm (e.g. because it's implemented by their storage provider), they SHOULD use an existing standard `type` value such as `md5`, `etag`, `crc32c`, `trunc512`, or `sha1`.", + "example": "sha-256" + } + } + }, + "AccessURL": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "type": "string", + "description": "A fully resolvable URL that can be used to fetch the actual object bytes." + }, + "headers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "An optional list of headers to include in the HTTP request to `url`. These headers can be used to provide auth tokens required to fetch the object bytes.", + "example": "Authorization: Basic Z2E0Z2g6ZHJz" + } + } + }, + "Authorizations": { + "type": "object", + "properties": { + "drs_object_id": { + "type": "string" + }, + "supported_types": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "None", + "BasicAuth", + "BearerAuth", + "PassportAuth" + ] + }, + "description": "An Optional list of support authorization types. More than one can be supported and tried in sequence. Defaults to `None` if empty or missing." + }, + "passport_auth_issuers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "If authorizations contain `PassportAuth` this is a required list of visa issuers (as found in a visa's `iss` claim) that may authorize access to this object. The caller must only provide passports that contain visas from this list. It is strongly recommended that the caller validate that it is appropriate to send the requested passport/visa to the DRS server to mitigate attacks by malicious DRS servers requesting credentials they should not have." + }, + "bearer_auth_issuers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "If authorizations contain `BearerAuth` this is an optional list of issuers that may authorize access to this object. The caller must provide a token from one of these issuers. If this is empty or missing it assumed the caller knows which token to send via other means. It is strongly recommended that the caller validate that it is appropriate to send the requested token to the DRS server to mitigate attacks by malicious DRS servers requesting credentials they should not have." + } + } + }, + "AccessMethod": { + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "s3", + "gs", + "ftp", + "gsiftp", + "globus", + "htsget", + "https", + "file" + ], + "description": "Type of the access method." + }, + "access_url": { + "allOf": [ + { + "$ref": "#/components/schemas/AccessURL" + }, + { + "description": "An `AccessURL` that can be used to fetch the actual object bytes. Note that at least one of `access_url` and `access_id` must be provided." + } + ] + }, + "access_id": { + "type": "string", + "description": "An arbitrary string to be passed to the `/access` method to get an `AccessURL`. This string must be unique within the scope of a single object. Note that at least one of `access_url` and `access_id` must be provided." + }, + "region": { + "type": "string", + "description": "Name of the region in the cloud service provider that the object belongs to.", + "example": "us-east-1" + }, + "authorizations": { + "allOf": [ + { + "$ref": "#/components/schemas/Authorizations" + }, + { + "description": "When `access_id` is provided, `authorizations` provides information about how to authorize the `/access` method." + } + ] + } + } + }, + "ContentsObject": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "A name declared by the bundle author that must be used when materialising this object, overriding any name directly associated with the object itself. The name must be unique within the containing bundle. This string is made up of uppercase and lowercase letters, decimal digits, hyphen, period, and underscore [A-Za-z0-9.-_]. See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_282[portable filenames]." + }, + "id": { + "type": "string", + "description": "A DRS identifier of a `DrsObject` (either a single blob or a nested bundle). If this ContentsObject is an object within a nested bundle, then the id is optional. Otherwise, the id is required." + }, + "drs_uri": { + "type": "array", + "description": "A list of full DRS identifier URI paths that may be used to obtain the object. These URIs may be external to this DRS instance.", + "example": "drs://drs.example.org/314159", + "items": { + "type": "string" + } + }, + "contents": { + "type": "array", + "description": "If this ContentsObject describes a nested bundle and the caller specified \"?expand=true\" on the request, then this contents array must be present and describe the objects within the nested bundle.", + "items": { + "$ref": "#/components/schemas/ContentsObject" + } + } + } + }, + "DrsObject": { + "type": "object", + "required": [ + "id", + "self_uri", + "size", + "created_time", + "checksums" + ], + "properties": { + "id": { + "type": "string", + "description": "An identifier unique to this `DrsObject`" + }, + "name": { + "type": "string", + "description": "A string that can be used to name a `DrsObject`.\nThis string is made up of uppercase and lowercase letters, decimal digits, hyphen, period, and underscore [A-Za-z0-9.-_]. See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_282[portable filenames]." + }, + "self_uri": { + "type": "string", + "description": "A drs:// hostname-based URI, as defined in the DRS documentation, that tells clients how to access this object.\nThe intent of this field is to make DRS objects self-contained, and therefore easier for clients to store and pass around. For example, if you arrive at this DRS JSON by resolving a compact identifier-based DRS URI, the `self_uri` presents you with a hostname and properly encoded DRS ID for use in subsequent `access` endpoint calls.", + "example": "drs://drs.example.org/314159" + }, + "size": { + "type": "integer", + "format": "int64", + "description": "For blobs, the blob size in bytes.\nFor bundles, the cumulative size, in bytes, of items in the `contents` field." + }, + "created_time": { + "type": "string", + "format": "date-time", + "description": "Timestamp of content creation in RFC3339.\n(This is the creation time of the underlying content, not of the JSON object.)" + }, + "updated_time": { + "type": "string", + "format": "date-time", + "description": "Timestamp of content update in RFC3339, identical to `created_time` in systems that do not support updates. (This is the update time of the underlying content, not of the JSON object.)" + }, + "version": { + "type": "string", + "description": "A string representing a version.\n(Some systems may use checksum, a RFC3339 timestamp, or an incrementing version number.)" + }, + "mime_type": { + "type": "string", + "description": "A string providing the mime-type of the `DrsObject`.", + "example": "application/json" + }, + "checksums": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/components/schemas/Checksum" + }, + "description": "The checksum of the `DrsObject`. At least one checksum must be provided.\nFor blobs, the checksum is computed over the bytes in the blob.\nFor bundles, the checksum is computed over a sorted concatenation of the checksums of its top-level contained objects (not recursive, names not included). The list of checksums is sorted alphabetically (hex-code) before concatenation and a further checksum is performed on the concatenated checksum value.\nFor example, if a bundle contains blobs with the following checksums:\nmd5(blob1) = 72794b6d\nmd5(blob2) = 5e089d29\nThen the checksum of the bundle is:\nmd5( concat( sort( md5(blob1), md5(blob2) ) ) )\n= md5( concat( sort( 72794b6d, 5e089d29 ) ) )\n= md5( concat( 5e089d29, 72794b6d ) )\n= md5( 5e089d2972794b6d )\n= f7a29a04" + }, + "access_methods": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/components/schemas/AccessMethod" + }, + "description": "The list of access methods that can be used to fetch the `DrsObject`.\nRequired for single blobs; optional for bundles." + }, + "contents": { + "type": "array", + "description": "If not set, this `DrsObject` is a single blob.\nIf set, this `DrsObject` is a bundle containing the listed `ContentsObject` s (some of which may be further nested).", + "items": { + "$ref": "#/components/schemas/ContentsObject" + } + }, + "description": { + "type": "string", + "description": "A human readable description of the `DrsObject`." + }, + "aliases": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A list of strings that can be used to find other metadata about this `DrsObject` from external metadata sources. These aliases can be used to represent secondary accession numbers or external GUIDs." + } + } + }, + "BulkObjectId": { + "type": "object", + "description": "The object that contains the DRS object IDs array", + "properties": { + "passports": { + "type": "array", + "items": { + "type": "string", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM" + }, + "description": "the encoded JWT GA4GH Passport that contains embedded Visas. The overall JWT is signed as are the individual Passport Visas." + }, + "bulk_object_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "An array of ObjectIDs." + } + } + }, + "summary": { + "type": "object", + "description": "A summary of what was resolved.", + "properties": { + "requested": { + "type": "integer", + "description": "Number of items requested." + }, + "resolved": { + "type": "integer", + "description": "Number of objects resolved." + }, + "unresolved": { + "type": "integer", + "description": "Number of objects not resolved." + } + } + }, + "unresolved": { + "type": "array", + "description": "Error codes for each unresolved drs objects.", + "items": { + "type": "object", + "properties": { + "error_code": { + "type": "integer" + }, + "object_ids": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "BulkObjectAccessId": { + "type": "object", + "description": "The object that contains object_id/access_id tuples", + "properties": { + "passports": { + "type": "array", + "items": { + "type": "string" + } + }, + "bulk_object_access_ids": { + "type": "array", + "items": { + "type": "object", + "properties": { + "bulk_object_id": { + "type": "string", + "description": "DRS object ID" + }, + "bulk_access_ids": { + "type": "array", + "description": "DRS object access ID", + "items": { + "type": "string" + } + } + } + } + } + } + }, + "BulkAccessURL": { + "type": "object", + "required": [ + "url" + ], + "properties": { + "drs_object_id": { + "type": "string" + }, + "drs_access_id": { + "type": "string" + }, + "url": { + "type": "string", + "description": "A fully resolvable URL that can be used to fetch the actual object bytes." + }, + "headers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "An optional list of headers to include in the HTTP request to `url`. These headers can be used to provide auth tokens required to fetch the object bytes.", + "example": "Authorization: Basic Z2E0Z2g6ZHJz" + } + } + } + }, + "responses": { + "200ServiceInfo": { + "description": "Retrieve info about the DRS service", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/Service" + }, + { + "$ref": "#/components/schemas/DrsService" + } + ] + } + } + } + }, + "500InternalServerError": { + "description": "An unexpected error occurred.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "200OkDrsObject": { + "description": "The `DrsObject` was found successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DrsObject" + } + } + } + }, + "202Accepted": { + "description": "The operation is delayed and will continue asynchronously. The client should retry this same request after the delay specified by Retry-After header.\n", + "headers": { + "Retry-After": { + "description": "Delay in seconds. The client should retry this same request after waiting for this duration. To simplify client response processing, this must be an integral relative time in seconds. This value SHOULD represent the minimum duration the client should wait before attempting the operation again with a reasonable expectation of success. When it is not feasible for the server to determine the actual expected delay, the server may return a brief, fixed value instead.\n", + "schema": { + "type": "integer", + "format": "int64" + } + } + } + }, + "400BadRequest": { + "description": "The request is malformed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "401Unauthorized": { + "description": "The request is unauthorized.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "403Forbidden": { + "description": "The requester is not authorized to perform this action.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404NotFoundDrsObject": { + "description": "The requested `DrsObject` wasn't found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "404NotFoundAccess": { + "description": "The requested `AccessURL` wasn't found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "200OkAuthorizations": { + "description": "`Authorizations` were found successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Authorizations" + } + } + } + }, + "AuthorizationsNotSupported": { + "description": "`Authorizations` are not supported for this object. Default to `None`." + }, + "200OkDrsObjects": { + "description": "The `DrsObjects` were found successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "summary": { + "$ref": "#/components/schemas/summary" + }, + "unresolved_drs_objects": { + "$ref": "#/components/schemas/unresolved" + }, + "resolved_drs_object": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DrsObject" + } + } + } + } + } + } + }, + "413RequestTooLarge": { + "description": "The bulk request is too large.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + }, + "200OkBulkAuthorizations": { + "description": "`Authorizations` were found successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "summary": { + "$ref": "#/components/schemas/summary" + }, + "unresolved_drs_objects": { + "$ref": "#/components/schemas/unresolved" + }, + "resolved_drs_object": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Authorizations" + } + } + } + } + } + } + }, + "200OkAccess": { + "description": "The `AccessURL` was found successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccessURL" + } + } + } + }, + "200OkAccesses": { + "description": "The `AccessURL` was found successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "summary": { + "$ref": "#/components/schemas/summary" + }, + "unresolved_drs_objects": { + "$ref": "#/components/schemas/unresolved" + }, + "resolved_drs_object_access_urls": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BulkAccessURL" + } + } + } + } + } + } + } + }, + "parameters": { + "ObjectId": { + "in": "path", + "name": "object_id", + "required": true, + "description": "`DrsObject` identifier", + "schema": { + "type": "string" + } + }, + "Expand": { + "in": "query", + "name": "expand", + "schema": { + "type": "boolean" + }, + "example": false, + "description": "If false and the object_id refers to a bundle, then the ContentsObject array contains only those objects directly contained in the bundle. That is, if the bundle contains other bundles, those other bundles are not recursively included in the result.\nIf true and the object_id refers to a bundle, then the entire set of objects in the bundle is expanded. That is, if the bundle contains other bundles, then those other bundles are recursively expanded and included in the result. Recursion continues through the entire sub-tree of the bundle.\nIf the object_id refers to a blob, then the query parameter is ignored." + }, + "AccessId": { + "in": "path", + "name": "access_id", + "required": true, + "description": "An `access_id` from the `access_methods` list of a `DrsObject`", + "schema": { + "type": "string" + } + } + }, + "requestBodies": { + "PostObjectBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "expand": { + "type": "boolean", + "example": false, + "description": "If false and the object_id refers to a bundle, then the ContentsObject array contains only those objects directly contained in the bundle. That is, if the bundle contains other bundles, those other bundles are not recursively included in the result.\nIf true and the object_id refers to a bundle, then the entire set of objects in the bundle is expanded. That is, if the bundle contains other bundles, then those other bundles are recursively expanded and included in the result. Recursion continues through the entire sub-tree of the bundle.\nIf the object_id refers to a blob, then the query parameter is ignored." + }, + "passports": { + "type": "array", + "items": { + "type": "string", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM" + }, + "description": "the encoded JWT GA4GH Passport that contains embedded Visas. The overall JWT is signed as are the individual Passport Visas." + } + } + } + } + } + }, + "Passports": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "passports": { + "type": "array", + "items": { + "type": "string", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM" + }, + "description": "the encoded JWT GA4GH Passport that contains embedded Visas. The overall JWT is signed as are the individual Passport Visas." + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/preview/release/drs-1.4.0/openapi.yaml b/preview/release/drs-1.4.0/openapi.yaml new file mode 100644 index 00000000..3b38085e --- /dev/null +++ b/preview/release/drs-1.4.0/openapi.yaml @@ -0,0 +1,2074 @@ +openapi: 3.0.3 +info: + title: Data Repository Service + version: 1.4.0 + x-logo: + url: >- + https://www.ga4gh.org/wp-content/themes/ga4gh/dist/assets/svg/logos/logo-full-color.svg + termsOfService: https://www.ga4gh.org/terms-and-conditions/ + contact: + name: GA4GH Cloud Work Stream + email: ga4gh-cloud@ga4gh.org + license: + name: Apache 2.0 + url: >- + https://raw.githubusercontent.com/ga4gh/data-repository-service-schemas/master/LICENSE +servers: + - url: https://{serverURL}/ga4gh/drs/v1 + variables: + serverURL: + default: drs.example.org + description: > + DRS server endpoints MUST be prefixed by the '/ga4gh/drs/v1' endpoint + path +security: + - {} + - BasicAuth: [] + - BearerAuth: [] +tags: + - name: Introduction + description: > + The Data Repository Service (DRS) API provides a generic interface to data + repositories so data consumers, including workflow systems, can access + data objects in a single, standard way regardless of where they are stored + and how they are managed. The primary functionality of DRS is to map a + logical ID to a means for physically retrieving the data represented by + the ID. The sections below describe the characteristics of those IDs, the + types of data supported, how they can be pointed to using URIs, and how + clients can use these URIs to ultimately make successful DRS API requests. + This document also describes the DRS API in detail and provides + information on the specific endpoints, request formats, and responses. + This specification is intended for developers of DRS-compatible services + and of clients that will call these DRS services. + + + The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD + NOT, RECOMMENDED, MAY, and OPTIONAL in this document are to be interpreted + as described in [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119). + - name: DRS API Principles + description: > + ## DRS IDs + + + Each implementation of DRS can choose its own id scheme, as long as it + follows these guidelines: + + + * DRS IDs are strings made up of uppercase and lowercase letters, decimal + digits, hyphen, period, underscore and tilde [A-Za-z0-9.-_~]. See [RFC + 3986 § 2.3](https://datatracker.ietf.org/doc/html/rfc3986#section-2.3). + + * DRS IDs can contain other characters, but they MUST be encoded into + valid DRS IDs whenever they are used in API calls. This is because + non-encoded IDs may interfere with the interpretation of the + objects/{id}/access endpoint. To overcome this limitation use + percent-encoding of the ID, see [RFC 3986 § + 2.4](https://datatracker.ietf.org/doc/html/rfc3986#section-2.4) + + * One DRS ID MUST always return the same object data (or, in the case of a + collection, the same set of objects). This constraint aids with + reproducibility. + + * DRS implementations MAY have more than one ID that maps to the same + object. + + * DRS version 1.x does NOT support semantics around multiple versions of + an object. (For example, there’s no notion of “get latest version” or + “list all versions”.) Individual implementations MAY choose an ID scheme + that includes version hints. + + + ## DRS URIs + + + For convenience, including when passing content references to a [WES + server](https://github.com/ga4gh/workflow-execution-service-schemas), we + define a [URI + scheme](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Generic_syntax) + for DRS-accessible content. This section documents the syntax of DRS URIs, + and the rules clients follow for translating a DRS URI into a URL that + they use for making the DRS API calls described in this spec. + + + There are two styles of DRS URIs, Hostname-based and Compact + Identifier-based, both using the `drs://` URI scheme. DRS servers may + choose either style when exposing references to their content;. DRS + clients MUST support resolving both styles. + + + Tip: + + > See [Appendix: Background Notes on DRS + URIs](#tag/Background-Notes-on-DRS-URIs) for more information on our + design motivations for DRS URIs. + + + ### Hostname-based DRS URIs + + + Hostname-based DRS URIs are simpler than compact identifier-based URIs. + They contain the DRS server name and the DRS ID only and can be converted + directly into a fetchable URL based on a simple rule. They take the form: + + + ``` + + drs:/// + + ``` + + + DRS URIs of this form mean *\"you can fetch the content with DRS id \ + from the DRS server at \\"*. + + For example, here are the client resolution steps if the URI is: + + + ``` + + drs://drs.example.org/314159 + + ``` + + + 1. The client parses the string to extract the hostname of + “drs.example.org” and the id of “314159”. + + 2. The client makes a GET request to the DRS server, using the standard + DRS URL syntax: + + + ``` + + GET https://drs.example.org/ga4gh/drs/v1/objects/314159 + + ``` + + + The protocol is always https and the port is always the standard 443 SSL + port. It is invalid to include a different port in a DRS hostname-based + URI. + + + Tip: + + > See the [Appendix: Hostname-Based URIs](#tag/Hostname-Based-URIs) for + information on how hostname-based DRS URI resolution to URLs is likely to + change in the future, when the DRS v2 major release happens. + + + ### Compact Identifier-based DRS URIs + + + Compact Identifier-based DRS URIs use resolver registry services + (specifically, [identifiers.org](https://identifiers.org/) and [n2t.net + (Name-To-Thing)](https://n2t.net/)) to provide a layer of indirection + between the DRS URI and the DRS server name — the actual DNS name of the + DRS server is not present in the URI. This approach is based on the Joint + Declaration of Data Citation Principles as detailed by [Wimalaratne et al + (2018)](https://www.nature.com/articles/sdata201829). + + + For more information, see the document [More Background on Compact + Identifiers](./more-background-on-compact-identifiers.html). + + + Compact Identifiers take the form: + + + ``` + + drs://[provider_code/]namespace:accession + + ``` + + + Together, provider code and the namespace are referred to as the `prefix`. + The provider code is optional and is used by identifiers.org/n2t.net for + compact identifier resolver mirrors. Both the `provider_code` and + `namespace` disallow spaces or punctuation, only lowercase alphanumerical + characters, underscores and dots are allowed (e.g. [A-Za-z0-9._]). + + + Tip: + + > See the [Appendix: Compact Identifier-Based + URIs](#tag/Compact-Identifier-Based-URIs) for more background on Compact + Identifiers and resolver registry services like identifiers.org/n2t.net + (aka meta-resolvers), how to register prefixes, possible caching + strategies, and security considerations. + + + #### For DRS Servers + + + If your DRS implementation will issue DRS URIs based *on your own* compact + identifiers, you MUST first register a new prefix with identifiers.org + (which is automatically mirrored to n2t.net). You will also need to + include a provider resolver resource in this registration which links the + prefix to your DRS server, so that DRS clients can get sufficient + information to make a successful DRS GET request. For clarity, we + recommend you choose a namespace beginning with `drs`. + + + #### For DRS Clients + + + A DRS client parses the DRS URI compact identifier components to extract + the prefix and the accession, and then uses meta-resolver APIs to locate + the actual DRS server. For example, here are the client resolution steps + if the URI is: + + + ``` + + drs://drs.42:314159 + + ``` + + + 1. The client parses the string to extract the prefix of `drs.42` and the + accession of `314159`, using the first occurrence of a colon (":") + character after the initial `drs://` as a delimiter. (The colon character + is not allowed in a Hostname-based DRS URI, making it easy to tell them + apart.) + + + 2. The client makes API calls to a meta-resolver to look up the URL + pattern for the namespace. (See [Calling Meta-Resolver APIs for Compact + Identifier-Based DRS + URIs](#section/Calling-Meta-Resolver-APIs-for-Compact-Identifier-Based-DRS-URIs) + for details.) The URL pattern is a string containing a `{$id}` parameter, + such as: + + + ``` + + https://drs.myexample.org/ga4gh/drs/v1/objects/{$id} + + ``` + + + 3. The client generates a DRS URL from the URL template by replacing {$id} + with the accession it extracted in step 1. It then makes a GET request to + the DRS server: + + + ``` + + GET https://drs.myexample.org/ga4gh/drs/v1/objects/314159 + + ``` + + + 4. The client follows any HTTP redirects returned in step 3, in case the + resolver goes through an extra layer of redirection. + + + For performance reasons, DRS clients SHOULD cache the URL pattern returned + in step 2, with a suggested 24 hour cache life. + + + ### Choosing a URI Style + + + DRS servers can choose to issue either hostname-based or compact + identifier-based DRS URIs, and can be confident that compliant DRS clients + will support both. DRS clients must be able to accommodate both URI types. + Tradeoffs that DRS server builders, and third parties who need to cite DRS + objects in datasets, workflows or elsewhere, may want to consider include: + + + *Table 1: Choosing a URI Style* + + + | | Hostname-based | Compact Identifier-based | + + |-------------------|----------------|--------------------------| + + | URI Durability | URIs are valid for as long as the server operator + maintains ownership of the published DNS address. (They can of course + point that address at different physical serving infrastructure as often + as they would like.) | URIs are valid for as long as the server operator + maintains ownership of the published compact identifier resolver + namespace. (They also depend on the meta-resolvers like + identifiers.org/n2t.net remaining operational, which is intended to be + essentially forever.) | + + | Client Efficiency | URIs require minimal client logic, and no network + requests, to resolve. | URIs require small client logic, and 1-2 cacheable + network requests, to resolve. | + + | Security | Servers have full control over their own security + practices. | Server operators, in addition to maintaining their own + security practices, should confirm they are comfortable with the resolver + registry security practices, including protection against denial of + service and namespace-hijacking attacks. (See the [Appendix: Compact + Identifier-Based URIs](#tag/Compact-Identifier-Based-URIs) for more + information on resolver registry security.) | + + + ## DRS Datatypes + + DRS's job is data access, period. Therefore, the DRS API supports a simple + flat content model -- every `DrsObject`, like a file, represents a single + opaque blob of bytes. DRS has no understanding of the meaning of objects + and only provides simple domain-agnostic metadata. Understanding the + semantics of specific object types is the responsibility of the + applications that use DRS to fetch those objects (e.g. samtools for BAM + files, DICOM viewers for DICOM objects). + + + ### Atomic Objects + + DRS can be used to access individual objects of all kinds, simple or + complex, large or small, stored in type-specific formats (e.g. BAM files, + VCF files, CSV files). At the API level these are all the same; at the + application level, DRS clients and servers are expected to agree on object + semantics using non-DRS mechanisms, including but not limited to the GA4GH + Data Connect API. + + + ### Compound Objects + + DRS can also be used to access compound objects, consisting of two or more + atomic objects related to each other in a well-specified way. See the + [Appendix: Compound Objects](#tag/Working-With-Compound-Objects) for + suggested best practices for working with compound objects. + + + ### [DEPRECATED] Bundles + + Previous versions of the DRS API spec included support for a *bundle* + content type, which was a folder-like collection of other DRS objects + (either blobs or bundles), represented by a `DrsObject` with a `contents` + array. As of v1.3, bundles have been deprecated in favor of the best + practices documented in the [Appendix: Compound + Objects](#tag/Working-With-Compound-Objects). A future version of the API + spec may remove bundle support entirely and/or replace bundles with a + scalable approach based on the needs of our driver projects. + + + ## Read-only + + + DRS v1 is a read-only API. We expect that each implementation will define + its own mechanisms and interfaces (graphical and/or programmatic) for + adding and updating data. + + + ## Standards + + + The DRS API specification is written in OpenAPI and embodies a RESTful + service philosophy. It uses JSON in requests and responses and standard + HTTPS on port 443 for information transport. Optionally, it + + supports authentication and authorization using the [GA4GH + Passport](https://github.com/ga4gh-duri/ga4gh-duri.github.io/tree/master/researcher_ids) + standard. + - name: Authorization & Authentication + description: > + ## Making DRS Requests + + + The DRS implementation is responsible for defining and enforcing an + authorization policy that determines which users are allowed to make which + requests. GA4GH recommends that DRS implementations use an OAuth 2.0 + [bearer token](https://oauth.net/2/bearer-tokens/) or a [GA4GH + Passport](https://github.com/ga4gh-duri/ga4gh-duri.github.io/tree/master/researcher_ids), + although they can choose other mechanisms if appropriate. + + + ## Fetching DRS Objects + + + The DRS API allows implementers to support a variety of different content + access policies, depending on what `AccessMethod` records they return. + Implementers have a choice to make the + + GET /objects/{object_id} and GET /objects/{object_id}/access/{access_id} + calls open or requiring a Basic, Bearer, or Passport token (Passport + requiring a POST). The following describes the + + various access approaches following a successful GET/POST + /objects/{object_id} request in order to them obtain access to the bytes + for a given object ID/access ID: + + + * public content: + * server provides an `access_url` with a `url` and no `headers` + * caller fetches the object bytes without providing any auth info + * private content that requires the caller to have out-of-band auth + knowledge (e.g. service account credentials): + * server provides an `access_url` with a `url` and no `headers` + * caller fetches the object bytes, passing the auth info they obtained out-of-band + * private content that requires the caller to pass an Authorization token: + * server provides an `access_url` with a `url` and `headers` + * caller fetches the object bytes, passing auth info via the specified header(s) + * private content that uses an expensive-to-generate auth mechanism (e.g. + a signed URL): + * server provides an `access_id` + * caller passes the `access_id` to the `/access` endpoint + * server provides an `access_url` with the generated mechanism (e.g. a signed URL in the `url` field) + * caller fetches the object bytes from the `url` (passing auth info from the specified headers, if any) + + In the approaches above [GA4GH + Passports](https://github.com/ga4gh-duri/ga4gh-duri.github.io/tree/master/researcher_ids) + are not mentioned and that is on purpose. A DRS server may return a + Bearer token or other platform-specific token in a header in response to a + valid Bearer token or GA4GH Passport (Option 3 above). But it is not the + responsibility of a DRS server to return a Passport, that is the + responsibility of a Passport Broker and outside the scope of DRS. + + + DRS implementers should ensure their solutions restrict access to targets + as much as possible, detect attempts to exploit through log monitoring, + and they are prepared to take action if an exploit in their DRS + implementation is detected. + + + ## Authentication + + + ### Discovery + + + The APIs to fetch [DrsObjects](#tag/DrsObjectModel) and + [AccessURLs](#tag/AccessURLModel) may require authorization. The + authorization mode may vary between DRS objects hosted by a service. The + authorization mode may vary between the APIs to fetch a + [DrsObject](#tag/DrsObjectModel) and an associated + [AccessURL](#tag/AccessURLModel). Implementers should indicate how to + authenticate to fetch a [DrsObject](#tag/DrsObjectModel) by implementing + the [OptionsOjbect](#operation/OptionsObject) API. Implementers should + indicate how to authenticate to fetch an [AccessURL](#tag/AccessURLModel) + within a [DrsObject](#tag/DrsObjectModel). + + + ### Modes + + + #### BasicAuth + + + A valid authorization token must be passed in the 'Authorization' header, + e.g. "Basic ${token_string}" + + + | Security Scheme Type | HTTP | + + |----------------------|------| + + | **HTTP Authorization Scheme** | basic | + + + #### BearerAuth + + + A valid authorization token must be passed in the 'Authorization' header, + e.g. "Bearer ${token_string}" + + + | Security Scheme Type | HTTP | + + |----------------------|------| + + | **HTTP Authorization Scheme** | bearer | + + + #### PassportAuth + + + A valid authorization [GA4GH + Passport](https://github.com/ga4gh-duri/ga4gh-duri.github.io/tree/master/researcher_ids) + token must be passed in the body of a POST request + + + | Security Scheme Type | HTTP | + + |----------------------|------| + + | **HTTP POST** | tokens[] | + - name: Objects + - name: Service Info + - name: AccessMethodModel + x-displayName: AccessMethod + description: | + + - name: AccessURLModel + x-displayName: AccessURL + description: | + + - name: ChecksumModel + x-displayName: Checksum + description: | + + - name: ContentsObjectModel + x-displayName: ContentsObject + description: | + + - name: DrsObjectModel + x-displayName: DrsObject + description: | + + - name: ErrorModel + x-displayName: Error + description: | + + - name: Motivation + description: > + + + + + +
+ Data sharing requires portable data, consistent with the FAIR data principles (findable, accessible, interoperable, reusable). Today’s researchers and clinicians are surrounded by potentially useful data, but often need bespoke tools and processes to work with each dataset. Today’s data publishers don’t have a reliable way to make their data useful to all (and only) the people they choose. And today’s data controllers are tasked with implementing standard controls of non-standard mechanisms for data access. + + + + Figure 1: there’s an ocean of data, with many different tools to drink from it, but no guarantee that any tool will work with any subset of the data + +
+ + + + + + + +
+ We need a standard way for data producers to make their data available to data consumers, that supports the control needs of the former and the access needs of the latter. And we need it to be interoperable, so anyone who builds access tools and systems can be confident they’ll work with all the data out there, and anyone who publishes data can be confident it will work with all the tools out there. + + + + Figure 2: by defining a standard Data Repository API, and adapting tools to use it, every data publisher can now make their data useful to every data consumer + +
+ + + + + + + +
+ We envision a world where: +
    +
  • + there are many many data consumers, working in research and in care, who can use the tools of their choice to access any and all data that they have permission to see +
  • +
  • + there are many data access tools and platforms, supporting discovery, visualization, analysis, and collaboration +
  • +
  • + there are many data repositories, each with their own policies and characteristics, which can be accessed by a variety of tools +
  • +
  • + there are many data publishing tools and platforms, supporting a variety of data lifecycles and formats +
  • +
  • + there are many many data producers, generating data of all types, who can use the tools of their choice to make their data as widely available as is appropriate +
  • +
+
+ + + Figure 3: a standard Data Repository API enables an ecosystem of data producers and consumers + +
+ + + This spec defines a standard **Data Repository Service (DRS) API** (“the + yellow box”), to enable that ecosystem of data producers and consumers. + Our goal is that the only thing data consumers need to know about a data + repo is *\"here’s the DRS endpoint to access it\"*, and the only thing + data publishers need to know to tap into the world of consumption tools is + *\"here’s how to tell it where my DRS endpoint lives\"*. + + + ## Federation + + + The world’s biomedical data is controlled by groups with very different + policies and restrictions on where their data lives and how it can be + accessed. A primary purpose of DRS is to support unified access to + disparate and distributed data. (As opposed to the alternative centralized + model of "let’s just bring all the data into one single data repository”, + which would be technically easier but is no more realistic than “let’s + just bring all the websites into one single web host”.) + + + In a DRS-enabled world, tool builders don’t have to worry about where the + data their tools operate on lives — they can count on DRS to give them + access. And tool users only need to know which DRS server is managing the + data they need, and whether they have permission to access it; they don’t + have to worry about how to physically get access to, or (worse) make a + copy of the data. For example, if I have appropriate permissions, I can + run a pooled analysis where I run a single tool across data managed by + different DRS servers, potentially in different locations. + - name: Working With Compound Objects + description: > + ## Compound Objects + + + The DRS API supports access to data objects, with each `DrsObject` + representing a single opaque blob of bytes. Much content (e.g. VCF files) + is well represented as a single atomic `DrsObject`. Some content, however + (e.g. DICOM images) is best represented as a compound object consisting of + a structured collection of atomic `DrsObject`s. In both cases, DRS isn't + aware of the semantics of the objects it serves -- understanding those + semantics is the responsibility of the applications that call DRS. + + + Common examples of compound objects in biomedicine include: + + * BAM+BAI genomic reads, with a small index (the BAI object) to large data + (the BAM object), each object using a well-defined file format. + + * DICOM images, with a contents object pointing to one or more raw image + objects, each containing pixels from different aspects of a single logical + biomedical image (e.g. different z-coordinates) + + * studies, with a single table of contents listing multiple objects of + various types that were generated together and are meant to be processed + together + + + ## Best Practice: Manifests + + + As with atomic objects, DRS applications and servers are expected to agree + on the semantics of compound objects using non-DRS mechanisms. The + recommended best practice for representing a particular compound object + type is: + + 1. Define a manifest file syntax, which contains the DRS IDs of the + constituent atomic objects, plus type-specific information about the + relationship between those constituents. + * Manifest file syntax isn't prescribed by the spec, but we expect they will often be JSON files. + * For example, for a BAM+BAI pair the manifest file could contain two key-value pairs mapping the type of each constituent file to its DRS ID. + 3. Make manifest objects and their constituent objects available using + standard DRS mechanisms -- each object is referenced via its own DRS ID, + just like any other atomic object. + * For example, for a BAM+BAI pair, there would be three DRS IDs -- one for the manifest, one for the BAM, and one for the BAI. + 5. Document the expected client logic for processing compound objects of + interest. This logic typically consists of using standard DRS mechanisms + to fetch the manifest, parsing its syntax, extracting the DRS IDs of + constituent objects, and using standard DRS mechanisms to fetch the + constituents as needed. + * In some cases the application will always want to fetch all of the constituents; in other cases it may want to initially fetch a subset, and only fetch the others on demand. For example, a DICOM image viewer may only want to fetch the layers that are being rendered. + - name: Background Notes on DRS URIs + description: > + ## Design Motivation + + + DRS URIs are aligned with the [FAIR data + principles](https://www.nature.com/articles/sdata201618) and the [Joint + Declaration of Data Citation + Principles](https://www.nature.com/articles/sdata20182) — both + hostname-based and compact identifier-based URIs provide globally unique, + machine-resolvable, persistent identifiers for data. + + + * We require all URIs to begin with `drs://` as a signal to humans and + systems consuming these URIs that the response they will ultimately + receive, after transforming the URI to a fetchable URL, will be a DRS JSON + packet. This signal differentiates DRS URIs from the wide variety of other + entities (HTML documents, PDFs, ontology notes, etc.) that can be + represented by compact identifiers. + + * We support hostname-based URIs because of their simplicity and + efficiency for server and client implementers. + + * We support compact identifier-based URIs, and the meta-resolver services + of identifiers.org and n2t.net (Name-to-Thing), because of the wide + adoption of compact identifiers in the research community. as detailed by + [Wimalaratne et al (2018)](https://www.nature.com/articles/sdata201829) in + "Uniform resolution of compact identifiers for biomedical data." + - name: Compact Identifier-Based URIs + description: > + **Note: Identifiers.org/n2t.net API Changes** + + + The examples below show the current API interactions with + [n2t.net](https://n2t.net/e/compact_ids.html) and + [identifiers.org](https://docs.identifiers.org/) which may change over + time. Please refer to the documentation from each site for the most + up-to-date information. We will make best efforts to keep the DRS + specification current but DRS clients MUST maintain their ability to use + either the identifiers.org or n2t.net APIs to resolve compact + identifier-based DRS URIs. + + + ## Registering a DRS Server on a Meta-Resolver + + + See the documentation on the [n2t.net](https://n2t.net/e/compact_ids.html) + and [identifiers.org](https://docs.identifiers.org/) meta-resolvers for + adding your own compact identifier type and registering your DRS server as + a resolver. You can register new prefixes (or mirrors by adding resource + provider codes) for free using a simple online form. For more information + see [More Background on Compact + Identifiers](./more-background-on-compact-identifiers.html). + + + ## Calling Meta-Resolver APIs for Compact Identifier-Based DRS URIs + + + Clients resolving Compact Identifier-based URIs need to convert a prefix + (e.g. “drs.42”) into a URL pattern. They can do so by calling either the + identifiers.org or the n2t.net API, since the two meta-resolvers keep + their mapping databases in sync. + + + ### Calling the identifiers.org API as a Client + + + It takes two API calls to get the URL pattern. + + + 1. The client makes a GET request to identifiers.org to find information + about the prefix: + + + ``` + + GET + https://registry.api.identifiers.org/restApi/namespaces/search/findByPrefix?prefix=drs.42 + + ``` + + + This request returns a JSON structure including various URLs containing an + embedded namespace id, such as: + + + ``` + + "namespace" : { + "href":"https://registry.api.identifiers.org/restApi/namespaces/1234" + } + + ``` + + + 2. The client extracts the namespace id (in this example 1234), and uses + it to make a second GET request to identifiers.org to find information + about the namespace: + + + ``` + + GET + https://registry.api.identifiers.org/restApi/resources/search/findAllByNamespaceId?id=1234 + + ``` + + + This request returns a JSON structure including an urlPattern field, whose + value is a URL pattern containing a ${id} parameter, such as: + + + ``` + + "urlPattern" : "https://drs.myexample.org/ga4gh/drs/v1/objects/{$id}" + + ``` + + + ### Calling the n2t.net API as a Client + + + It takes one API call to get the URL pattern. + + + The client makes a GET request to n2t.net to find information about the + namespace. (Note the trailing colon.) + + + ``` + + GET https://n2t.net/drs.42: + + ``` + + + This request returns a text structure including a redirect field, whose + value is a URL pattern containing an `$id` parameter, such as: + + + ``` + + redirect: https://drs.myexample.org/ga4gh/drs/v1/objects/$id + + ``` + + + ## Caching with Compact Identifiers + + + Identifiers.org/n2t.net compact identifier resolver records do not change + frequently. This reality is useful for caching resolver records and their + URL patterns for performance reasons. Builders of systems that use compact + identifier-based DRS URIs should cache prefix resolver records from + identifiers.org/n2t.net and occasionally refresh the records (such as + every 24 hours). This approach will reduce the burden on these community + services since we anticipate many DRS URIs will be regularly resolved in + workflow systems. Alternatively, system builders may decide to directly + mirror the registries themselves, instructions are provided on the + identifiers.org/n2t.net websites. + + + ## Security with Compact Identifiers + + + As mentioned earlier, identifiers.org/n2t.net performs some basic + verification of new prefixes and provider code mirror registrations on + their sites. However, builders of systems that consume and resolve DRS + URIs may have certain security compliance requirements and regulations + that prohibit relying on an external site for resolving compact + identifiers. In this case, systems under these security and compliance + constraints may wish to whitelist certain compact identifier resolvers + and/or vet records from identifiers.org/n2t.net before enabling in their + systems. + + + ## Accession Encoding to Valid DRS IDs + + + The compact identifier format used by identifiers.org/n2t.net does not + percent-encode reserved URI characters but, instead, relies on the first + ":" character to separate prefix from accession. Since these accessions + can contain any characters, and characters like "/" will interfere with + DRS API calls, you *must* percent encode the accessions extracted from DRS + compact identifier-based URIs when using as DRS IDs in subsequent DRS GET + requests. An easy way for a DRS client to handle this is to get the + initial DRS object JSON response from whatever redirects the compact + identifier resolves to, then look for the `self_uri` in the JSON, which + will give you the correctly percent-encoded DRS ID for subsequent DRS API + calls such as the `access` method. + + + ## Additional Examples + + + For additional examples, see the document [More Background on Compact + Identifiers](./more-background-on-compact-identifiers.html). + - name: Hostname-Based URIs + description: > + ## Encoding DRS IDs + + + In hostname-based DRS URIs, the ID is always percent-encoded to ensure + special characters do not interfere with subsequent DRS endpoint calls. As + such, ":" is not allowed in the URI and is a convenient way of + differentiating from a compact identifier-based DRS URI. Also, if a given + DRS service implementation uses compact identifier accessions as their DRS + IDs, they must be percent encoded before using them as DRS IDs in + hostname-based DRS URIs and subsequent GET requests to a DRS service + endpoint. + - name: GA4GH Service Registry + description: > + The [GA4GH Service Registry API + specification](https://github.com/ga4gh-discovery/ga4gh-service-registry) + allows information about GA4GH-compliant web services, including DRS + services, to be aggregated into registries and made available via a + standard API. The following considerations should be followed when + registering DRS services within a service registry. + + + * The DRS service attributes returned by `/service-info` (i.e. `id`, + `name`, `description`, etc.) should have the same values as the registry + entry for that service. + + * The value of the `type` object's `artifact` property should be `drs` + (i.e. the same as it appears in `service-info`) + + * Each entry in a Service Registry must have a `url`, indicating the base + URL to the web service. For DRS services, the registered `url` must + include everything up to + + the standardized `/ga4gh/drs/v1` path. Clients should be able to assume + that: + + Adding `/ga4gh/drs/v1/objects/{object_id}` to the registered `url` will hit the `DrsObject` endpoint + + Adding `/ga4gh/drs/v1/service-info` to the registered `url` will hit the Service Info endpoint + + Example listing of a DRS API registration from a service registry's + `/services` endpoint: + + + ``` + + [ + { + "id": "com.example.drs", + "name": "Example DRS API", + "type": { + "group": "org.ga4gh", + "artifact": "drs", + "version": "1.4.0" + }, + "description": "The Data Repository Service (DRS) API ...", + "organization": { + "id": "com.example", + "name": "Example Company" + }, + "contactUrl": "mailto:support@example.com", + "documentationUrl": "https://docs.example.com/docs/drs", + "createdAt": "2021-08-09T00:00:00Z", + "updatedAt": "2021-08-09T12:30:00Z", + "environment": "production", + "version": "1.13.4", + "url": "https://drs-service.example.com" + } + ] + + ``` +x-tagGroups: + - name: Overview + tags: + - Introduction + - DRS API Principles + - Authorization & Authentication + - name: Operations + tags: + - Objects + - Service Info + - name: Models + tags: + - AccessMethodModel + - AccessURLModel + - ChecksumModel + - ContentsObjectModel + - DrsObjectModel + - ErrorModel + - name: Appendices + tags: + - Motivation + - Working With Compound Objects + - Background Notes on DRS URIs + - Compact Identifier-Based URIs + - Hostname-Based URIs + - GA4GH Service Registry +paths: + /service-info: + get: + summary: Retrieve information about this service + description: >- + Returns information about the DRS service + + + Extends the + + [v1.0.0 GA4GH Service Info + specification](https://github.com/ga4gh-discovery/ga4gh-service-info) + + as the standardized format for GA4GH web services to self-describe. + + + According to the + + [service-info type + registry](https://github.com/ga4gh/TASC/blob/master/service-info/ga4gh-service-info.json) + + maintained by the [Technical Alignment Sub Committee + (TASC)](https://github.com/ga4gh/TASC), + + a DRS service MUST have: + * a `type.group` value of `org.ga4gh` + * a `type.artifact` value of `drs` + + e.g. + + ``` + + { + "id": "com.example.drs", + "description": "Serves data according to DRS specification", + ... + "type": { + "group": "org.ga4gh", + "artifact": "drs" + } + ... + } + + ``` + + + See the [Service Registry Appendix](#tag/GA4GH-Service-Registry) for + more information on how to register a DRS service with a service + registry. + operationId: GetServiceInfo + responses: + '200': + $ref: '#/components/responses/200ServiceInfo' + '500': + $ref: '#/components/responses/500InternalServerError' + tags: + - Service Info + /objects/{object_id}: + options: + summary: Get Authorization info about a DrsObject. + security: + - {} + description: >- + Returns a list of `Authorizations` that can be used to determine how to + authorize requests to `GetObject` or `PostObject`. + operationId: OptionsObject + parameters: + - $ref: '#/components/parameters/ObjectId' + responses: + '200': + $ref: '#/components/responses/200OkAuthorizations' + '204': + $ref: '#/components/responses/AuthorizationsNotSupported' + '400': + $ref: '#/components/responses/400BadRequest' + '404': + $ref: '#/components/responses/404NotFoundDrsObject' + '405': + $ref: '#/components/responses/AuthorizationsNotSupported' + '500': + $ref: '#/components/responses/500InternalServerError' + tags: + - Objects + x-swagger-router-controller: ga4gh.drs.server + get: + summary: Get info about a DrsObject. + description: >- + Returns object metadata, and a list of access methods that can be used + to fetch object bytes. + operationId: GetObject + parameters: + - $ref: '#/components/parameters/ObjectId' + - $ref: '#/components/parameters/Expand' + responses: + '200': + $ref: '#/components/responses/200OkDrsObject' + '202': + $ref: '#/components/responses/202Accepted' + '400': + $ref: '#/components/responses/400BadRequest' + '401': + $ref: '#/components/responses/401Unauthorized' + '403': + $ref: '#/components/responses/403Forbidden' + '404': + $ref: '#/components/responses/404NotFoundDrsObject' + '500': + $ref: '#/components/responses/500InternalServerError' + tags: + - Objects + x-swagger-router-controller: ga4gh.drs.server + post: + summary: Get info about a DrsObject through POST'ing a Passport. + description: >- + Returns object metadata, and a list of access methods that can be used + to fetch object bytes. + + Method is a POST to accommodate a JWT GA4GH Passport sent in the + formData in order to authorize access. + operationId: PostObject + security: + - PassportAuth: [] + responses: + '200': + $ref: '#/components/responses/200OkDrsObject' + '202': + $ref: '#/components/responses/202Accepted' + '400': + $ref: '#/components/responses/400BadRequest' + '401': + $ref: '#/components/responses/401Unauthorized' + '403': + $ref: '#/components/responses/403Forbidden' + '404': + $ref: '#/components/responses/404NotFoundAccess' + '500': + $ref: '#/components/responses/500InternalServerError' + tags: + - Objects + x-swagger-router-controller: ga4gh.drs.server + parameters: + - $ref: '#/components/parameters/ObjectId' + requestBody: + $ref: '#/components/requestBodies/PostObjectBody' + /objects: + options: + summary: Get Authorization info about multiple DrsObjects. + security: + - {} + description: >- + Returns a structure that contains for each DrsObjects a list of + `Authorizations` that can be used to determine how to authorize requests + to `GetObject` or `PostObject` (or bulk equivalents). + operationId: OptionsBulkObject + responses: + '200': + $ref: '#/components/responses/200OkBulkAuthorizations' + '204': + $ref: '#/components/responses/AuthorizationsNotSupported' + '400': + $ref: '#/components/responses/400BadRequest' + '404': + $ref: '#/components/responses/404NotFoundDrsObject' + '405': + $ref: '#/components/responses/AuthorizationsNotSupported' + '413': + $ref: '#/components/responses/413RequestTooLarge' + '500': + $ref: '#/components/responses/500InternalServerError' + tags: + - Objects + x-swagger-router-controller: ga4gh.drs.server + requestBody: + required: true + content: + application/json: + schema: + $ref: ../components/parameters/BulkObjectIdNoPassport.yaml + post: + summary: Get info about multiple DrsObjects with an optional Passport(s). + description: >- + Returns an array of object metadata, and a list of access methods that + can be used to fetch objects' bytes. Currently this is limited to use + passports (one or more) or a single bearer token, so make sure your bulk + request is for objects that all use the same passports/token. + operationId: GetBulkObjects + security: + - PassportAuth: [] + parameters: + - $ref: '#/components/parameters/Expand' + responses: + '200': + $ref: '#/components/responses/200OkDrsObjects' + '202': + $ref: '#/components/responses/202Accepted' + '400': + $ref: '#/components/responses/400BadRequest' + '401': + $ref: '#/components/responses/401Unauthorized' + '403': + $ref: '#/components/responses/403Forbidden' + '404': + $ref: '#/components/responses/404NotFoundDrsObject' + '413': + $ref: '#/components/responses/413RequestTooLarge' + '500': + $ref: '#/components/responses/500InternalServerError' + tags: + - Objects + x-swagger-router-controller: ga4gh.drs.server + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkObjectId' + /objects/{object_id}/access/{access_id}: + get: + summary: Get a URL for fetching bytes + description: >- + Returns a URL that can be used to fetch the bytes of a `DrsObject`. + + This method only needs to be called when using an `AccessMethod` that + contains an `access_id` (e.g., for servers that use signed URLs for + fetching object bytes). + operationId: GetAccessURL + responses: + '200': + $ref: '#/components/responses/200OkAccess' + '202': + $ref: '#/components/responses/202Accepted' + '400': + $ref: '#/components/responses/400BadRequest' + '401': + $ref: '#/components/responses/401Unauthorized' + '403': + $ref: '#/components/responses/403Forbidden' + '404': + $ref: '#/components/responses/404NotFoundAccess' + '500': + $ref: '#/components/responses/500InternalServerError' + tags: + - Objects + x-swagger-router-controller: ga4gh.drs.server + parameters: + - $ref: '#/components/parameters/ObjectId' + - $ref: '#/components/parameters/AccessId' + post: + summary: Get a URL for fetching bytes through POST'ing a Passport + description: >- + Returns a URL that can be used to fetch the bytes of a `DrsObject`. + + This method only needs to be called when using an `AccessMethod` that + contains an `access_id` (e.g., for servers that use signed URLs for + fetching object bytes). + + Method is a POST to accommodate a JWT GA4GH Passport sent in the + formData in order to authorize access. + operationId: PostAccessURL + security: + - PassportAuth: [] + responses: + '200': + $ref: '#/components/responses/200OkAccess' + '202': + $ref: '#/components/responses/202Accepted' + '400': + $ref: '#/components/responses/400BadRequest' + '401': + $ref: '#/components/responses/401Unauthorized' + '403': + $ref: '#/components/responses/403Forbidden' + '404': + $ref: '#/components/responses/404NotFoundAccess' + '500': + $ref: '#/components/responses/500InternalServerError' + tags: + - Objects + x-swagger-router-controller: ga4gh.drs.server + parameters: + - $ref: '#/components/parameters/ObjectId' + - $ref: '#/components/parameters/AccessId' + requestBody: + $ref: '#/components/requestBodies/Passports' + /objects/access: + post: + summary: >- + Get URLs for fetching bytes from multiple objects with an optional + Passport(s). + description: >- + Returns an array of URL objects that can be used to fetch the bytes of + multiple `DrsObject`s. + + This method only needs to be called when using an `AccessMethod` that + contains an `access_id` (e.g., for servers that use signed URLs for + fetching object bytes). + + Currently this is limited to use passports (one or more) or a single + bearer token, so make sure your bulk request is for objects that all use + the same passports/token. + operationId: GetBulkAccessURL + security: + - PassportAuth: [] + responses: + '200': + $ref: '#/components/responses/200OkAccesses' + '202': + $ref: '#/components/responses/202Accepted' + '400': + $ref: '#/components/responses/400BadRequest' + '401': + $ref: '#/components/responses/401Unauthorized' + '403': + $ref: '#/components/responses/403Forbidden' + '404': + $ref: '#/components/responses/404NotFoundAccess' + '413': + $ref: '#/components/responses/413RequestTooLarge' + '500': + $ref: '#/components/responses/500InternalServerError' + tags: + - Objects + x-swagger-router-controller: ga4gh.drs.server + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BulkObjectAccessId' +components: + securitySchemes: + BasicAuth: + type: http + scheme: basic + description: > + A valid authorization token must be passed in the 'Authorization' + header, + + e.g. "Basic ${token_string}" + BearerAuth: + type: http + scheme: bearer + description: >- + A valid authorization token must be passed in the 'Authorization' + header, e.g. "Bearer ${token_string}" + PassportAuth: + type: http + scheme: bearer + x-in: body + bearerFormat: JWT + description: >- + A valid GA4GH Passport must be passed in the body of an HTTP POST + request as a tokens[] array. + schemas: + ServiceType: + description: Type of a GA4GH service + type: object + required: + - group + - artifact + - version + properties: + group: + type: string + description: >- + Namespace in reverse domain name format. Use `org.ga4gh` for + implementations compliant with official GA4GH specifications. For + services with custom APIs not standardized by GA4GH, or + implementations diverging from official GA4GH specifications, use a + different namespace (e.g. your organization's reverse domain name). + example: org.ga4gh + artifact: + type: string + description: >- + Name of the API or GA4GH specification implemented. Official GA4GH + types should be assigned as part of standards approval process. + Custom artifacts are supported. + example: beacon + version: + type: string + description: >- + Version of the API or specification. GA4GH specifications use + semantic versioning. + example: 1.0.0 + Service: + description: GA4GH service + type: object + required: + - id + - name + - type + - organization + - version + properties: + id: + type: string + description: >- + Unique ID of this service. Reverse domain name notation is + recommended, though not required. The identifier should attempt to + be globally unique so it can be used in downstream aggregator + services e.g. Service Registry. + example: org.ga4gh.myservice + name: + type: string + description: Name of this service. Should be human readable. + example: My project + type: + $ref: '#/components/schemas/ServiceType' + description: + type: string + description: >- + Description of the service. Should be human readable and provide + information about the service. + example: This service provides... + organization: + type: object + description: Organization providing the service + required: + - name + - url + properties: + name: + type: string + description: Name of the organization responsible for the service + example: My organization + url: + type: string + format: uri + description: URL of the website of the organization (RFC 3986 format) + example: https://example.com + contactUrl: + type: string + format: uri + description: >- + URL of the contact for the provider of this service, e.g. a link to + a contact form (RFC 3986 format), or an email (RFC 2368 format). + example: mailto:support@example.com + documentationUrl: + type: string + format: uri + description: >- + URL of the documentation of this service (RFC 3986 format). This + should help someone learn how to use your service, including any + specifics required to access data, e.g. authentication. + example: https://docs.myservice.example.com + createdAt: + type: string + format: date-time + description: >- + Timestamp describing when the service was first deployed and + available (RFC 3339 format) + example: '2019-06-04T12:58:19Z' + updatedAt: + type: string + format: date-time + description: >- + Timestamp describing when the service was last updated (RFC 3339 + format) + example: '2019-06-04T12:58:19Z' + environment: + type: string + description: >- + Environment the service is running in. Use this to distinguish + between production, development and testing/staging deployments. + Suggested values are prod, test, dev, staging. However this is + advised and not enforced. + example: test + version: + type: string + description: >- + Version of the service being described. Semantic versioning is + recommended, but other identifiers, such as dates or commit hashes, + are also allowed. The version should be changed whenever the service + is updated. + example: 1.0.0 + DrsService: + type: object + required: + - type + properties: + maxBulkRequestLength: + type: integer + required: true + description: >- + The max length the bullk request endpoints can handle (>= 1) before + generating a 413 error e.g. how long can the arrays bulk_object_ids + and bulk_object_access_ids be for this server. + type: + type: object + required: + - artifact + properties: + artifact: + type: string + enum: + - drs + example: drs + Error: + type: object + description: An object that can optionally include information about the error. + properties: + msg: + type: string + description: A detailed error message. + status_code: + type: integer + description: The integer representing the HTTP status code (e.g. 200, 404). + Checksum: + type: object + required: + - checksum + - type + properties: + checksum: + type: string + description: The hex-string encoded checksum for the data + type: + type: string + description: >- + The digest method used to create the checksum. + + The value (e.g. `sha-256`) SHOULD be listed as `Hash Name String` in + the + https://www.iana.org/assignments/named-information/named-information.xhtml#hash-alg[IANA + Named Information Hash Algorithm Registry]. Other values MAY be + used, as long as implementors are aware of the issues discussed in + https://tools.ietf.org/html/rfc6920#section-9.4[RFC6920]. + + GA4GH may provide more explicit guidance for use of + non-IANA-registered algorithms in the future. Until then, if + implementers do choose such an algorithm (e.g. because it's + implemented by their storage provider), they SHOULD use an existing + standard `type` value such as `md5`, `etag`, `crc32c`, `trunc512`, + or `sha1`. + example: sha-256 + AccessURL: + type: object + required: + - url + properties: + url: + type: string + description: >- + A fully resolvable URL that can be used to fetch the actual object + bytes. + headers: + type: array + items: + type: string + description: >- + An optional list of headers to include in the HTTP request to `url`. + These headers can be used to provide auth tokens required to fetch + the object bytes. + example: 'Authorization: Basic Z2E0Z2g6ZHJz' + Authorizations: + type: object + properties: + drs_object_id: + type: string + supported_types: + type: array + items: + type: string + enum: + - None + - BasicAuth + - BearerAuth + - PassportAuth + description: >- + An Optional list of support authorization types. More than one can + be supported and tried in sequence. Defaults to `None` if empty or + missing. + passport_auth_issuers: + type: array + items: + type: string + description: >- + If authorizations contain `PassportAuth` this is a required list of + visa issuers (as found in a visa's `iss` claim) that may authorize + access to this object. The caller must only provide passports that + contain visas from this list. It is strongly recommended that the + caller validate that it is appropriate to send the requested + passport/visa to the DRS server to mitigate attacks by malicious DRS + servers requesting credentials they should not have. + bearer_auth_issuers: + type: array + items: + type: string + description: >- + If authorizations contain `BearerAuth` this is an optional list of + issuers that may authorize access to this object. The caller must + provide a token from one of these issuers. If this is empty or + missing it assumed the caller knows which token to send via other + means. It is strongly recommended that the caller validate that it + is appropriate to send the requested token to the DRS server to + mitigate attacks by malicious DRS servers requesting credentials + they should not have. + AccessMethod: + type: object + required: + - type + properties: + type: + type: string + enum: + - s3 + - gs + - ftp + - gsiftp + - globus + - htsget + - https + - file + description: Type of the access method. + access_url: + allOf: + - $ref: '#/components/schemas/AccessURL' + - description: >- + An `AccessURL` that can be used to fetch the actual object + bytes. Note that at least one of `access_url` and `access_id` + must be provided. + access_id: + type: string + description: >- + An arbitrary string to be passed to the `/access` method to get an + `AccessURL`. This string must be unique within the scope of a single + object. Note that at least one of `access_url` and `access_id` must + be provided. + region: + type: string + description: >- + Name of the region in the cloud service provider that the object + belongs to. + example: us-east-1 + authorizations: + allOf: + - $ref: '#/components/schemas/Authorizations' + - description: >- + When `access_id` is provided, `authorizations` provides + information about how to authorize the `/access` method. + ContentsObject: + type: object + required: + - name + properties: + name: + type: string + description: >- + A name declared by the bundle author that must be used when + materialising this object, overriding any name directly associated + with the object itself. The name must be unique within the + containing bundle. This string is made up of uppercase and lowercase + letters, decimal digits, hyphen, period, and underscore + [A-Za-z0-9.-_]. See + http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_282[portable + filenames]. + id: + type: string + description: >- + A DRS identifier of a `DrsObject` (either a single blob or a nested + bundle). If this ContentsObject is an object within a nested bundle, + then the id is optional. Otherwise, the id is required. + drs_uri: + type: array + description: >- + A list of full DRS identifier URI paths that may be used to obtain + the object. These URIs may be external to this DRS instance. + example: drs://drs.example.org/314159 + items: + type: string + contents: + type: array + description: >- + If this ContentsObject describes a nested bundle and the caller + specified "?expand=true" on the request, then this contents array + must be present and describe the objects within the nested bundle. + items: + $ref: '#/components/schemas/ContentsObject' + DrsObject: + type: object + required: + - id + - self_uri + - size + - created_time + - checksums + properties: + id: + type: string + description: An identifier unique to this `DrsObject` + name: + type: string + description: >- + A string that can be used to name a `DrsObject`. + + This string is made up of uppercase and lowercase letters, decimal + digits, hyphen, period, and underscore [A-Za-z0-9.-_]. See + http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_282[portable + filenames]. + self_uri: + type: string + description: >- + A drs:// hostname-based URI, as defined in the DRS documentation, + that tells clients how to access this object. + + The intent of this field is to make DRS objects self-contained, and + therefore easier for clients to store and pass around. For example, + if you arrive at this DRS JSON by resolving a compact + identifier-based DRS URI, the `self_uri` presents you with a + hostname and properly encoded DRS ID for use in subsequent `access` + endpoint calls. + example: drs://drs.example.org/314159 + size: + type: integer + format: int64 + description: >- + For blobs, the blob size in bytes. + + For bundles, the cumulative size, in bytes, of items in the + `contents` field. + created_time: + type: string + format: date-time + description: >- + Timestamp of content creation in RFC3339. + + (This is the creation time of the underlying content, not of the + JSON object.) + updated_time: + type: string + format: date-time + description: >- + Timestamp of content update in RFC3339, identical to `created_time` + in systems that do not support updates. (This is the update time of + the underlying content, not of the JSON object.) + version: + type: string + description: >- + A string representing a version. + + (Some systems may use checksum, a RFC3339 timestamp, or an + incrementing version number.) + mime_type: + type: string + description: A string providing the mime-type of the `DrsObject`. + example: application/json + checksums: + type: array + minItems: 1 + items: + $ref: '#/components/schemas/Checksum' + description: >- + The checksum of the `DrsObject`. At least one checksum must be + provided. + + For blobs, the checksum is computed over the bytes in the blob. + + For bundles, the checksum is computed over a sorted concatenation of + the checksums of its top-level contained objects (not recursive, + names not included). The list of checksums is sorted alphabetically + (hex-code) before concatenation and a further checksum is performed + on the concatenated checksum value. + + For example, if a bundle contains blobs with the following + checksums: + + md5(blob1) = 72794b6d + + md5(blob2) = 5e089d29 + + Then the checksum of the bundle is: + + md5( concat( sort( md5(blob1), md5(blob2) ) ) ) + + = md5( concat( sort( 72794b6d, 5e089d29 ) ) ) + + = md5( concat( 5e089d29, 72794b6d ) ) + + = md5( 5e089d2972794b6d ) + + = f7a29a04 + access_methods: + type: array + minItems: 1 + items: + $ref: '#/components/schemas/AccessMethod' + description: >- + The list of access methods that can be used to fetch the + `DrsObject`. + + Required for single blobs; optional for bundles. + contents: + type: array + description: >- + If not set, this `DrsObject` is a single blob. + + If set, this `DrsObject` is a bundle containing the listed + `ContentsObject` s (some of which may be further nested). + items: + $ref: '#/components/schemas/ContentsObject' + description: + type: string + description: A human readable description of the `DrsObject`. + aliases: + type: array + items: + type: string + description: >- + A list of strings that can be used to find other metadata about this + `DrsObject` from external metadata sources. These aliases can be + used to represent secondary accession numbers or external GUIDs. + BulkObjectId: + type: object + description: The object that contains the DRS object IDs array + properties: + passports: + type: array + items: + type: string + example: >- + eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM + description: >- + the encoded JWT GA4GH Passport that contains embedded Visas. The + overall JWT is signed as are the individual Passport Visas. + bulk_object_ids: + type: array + items: + type: string + description: An array of ObjectIDs. + summary: + type: object + description: A summary of what was resolved. + properties: + requested: + type: integer + description: Number of items requested. + resolved: + type: integer + description: Number of objects resolved. + unresolved: + type: integer + description: Number of objects not resolved. + unresolved: + type: array + description: Error codes for each unresolved drs objects. + items: + type: object + properties: + error_code: + type: integer + object_ids: + type: array + items: + type: string + BulkObjectAccessId: + type: object + description: The object that contains object_id/access_id tuples + properties: + passports: + type: array + items: + type: string + bulk_object_access_ids: + type: array + items: + type: object + properties: + bulk_object_id: + type: string + description: DRS object ID + bulk_access_ids: + type: array + description: DRS object access ID + items: + type: string + BulkAccessURL: + type: object + required: + - url + properties: + drs_object_id: + type: string + drs_access_id: + type: string + url: + type: string + description: >- + A fully resolvable URL that can be used to fetch the actual object + bytes. + headers: + type: array + items: + type: string + description: >- + An optional list of headers to include in the HTTP request to `url`. + These headers can be used to provide auth tokens required to fetch + the object bytes. + example: 'Authorization: Basic Z2E0Z2g6ZHJz' + responses: + 200ServiceInfo: + description: Retrieve info about the DRS service + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/Service' + - $ref: '#/components/schemas/DrsService' + 500InternalServerError: + description: An unexpected error occurred. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + 200OkDrsObject: + description: The `DrsObject` was found successfully + content: + application/json: + schema: + $ref: '#/components/schemas/DrsObject' + 202Accepted: + description: > + The operation is delayed and will continue asynchronously. The client + should retry this same request after the delay specified by Retry-After + header. + headers: + Retry-After: + description: > + Delay in seconds. The client should retry this same request after + waiting for this duration. To simplify client response processing, + this must be an integral relative time in seconds. This value SHOULD + represent the minimum duration the client should wait before + attempting the operation again with a reasonable expectation of + success. When it is not feasible for the server to determine the + actual expected delay, the server may return a brief, fixed value + instead. + schema: + type: integer + format: int64 + 400BadRequest: + description: The request is malformed. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + 401Unauthorized: + description: The request is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + 403Forbidden: + description: The requester is not authorized to perform this action. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + 404NotFoundDrsObject: + description: The requested `DrsObject` wasn't found. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + 404NotFoundAccess: + description: The requested `AccessURL` wasn't found. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + 200OkAuthorizations: + description: '`Authorizations` were found successfully' + content: + application/json: + schema: + $ref: '#/components/schemas/Authorizations' + AuthorizationsNotSupported: + description: '`Authorizations` are not supported for this object. Default to `None`.' + 200OkDrsObjects: + description: The `DrsObjects` were found successfully + content: + application/json: + schema: + type: object + properties: + summary: + $ref: '#/components/schemas/summary' + unresolved_drs_objects: + $ref: '#/components/schemas/unresolved' + resolved_drs_object: + type: array + items: + $ref: '#/components/schemas/DrsObject' + 413RequestTooLarge: + description: The bulk request is too large. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + 200OkBulkAuthorizations: + description: '`Authorizations` were found successfully' + content: + application/json: + schema: + type: object + properties: + summary: + $ref: '#/components/schemas/summary' + unresolved_drs_objects: + $ref: '#/components/schemas/unresolved' + resolved_drs_object: + type: array + items: + $ref: '#/components/schemas/Authorizations' + 200OkAccess: + description: The `AccessURL` was found successfully + content: + application/json: + schema: + $ref: '#/components/schemas/AccessURL' + 200OkAccesses: + description: The `AccessURL` was found successfully + content: + application/json: + schema: + type: object + properties: + summary: + $ref: '#/components/schemas/summary' + unresolved_drs_objects: + $ref: '#/components/schemas/unresolved' + resolved_drs_object_access_urls: + type: array + items: + $ref: '#/components/schemas/BulkAccessURL' + parameters: + ObjectId: + in: path + name: object_id + required: true + description: '`DrsObject` identifier' + schema: + type: string + Expand: + in: query + name: expand + schema: + type: boolean + example: false + description: >- + If false and the object_id refers to a bundle, then the ContentsObject + array contains only those objects directly contained in the bundle. That + is, if the bundle contains other bundles, those other bundles are not + recursively included in the result. + + If true and the object_id refers to a bundle, then the entire set of + objects in the bundle is expanded. That is, if the bundle contains other + bundles, then those other bundles are recursively expanded and included + in the result. Recursion continues through the entire sub-tree of the + bundle. + + If the object_id refers to a blob, then the query parameter is ignored. + AccessId: + in: path + name: access_id + required: true + description: An `access_id` from the `access_methods` list of a `DrsObject` + schema: + type: string + requestBodies: + PostObjectBody: + required: true + content: + application/json: + schema: + type: object + properties: + expand: + type: boolean + example: false + description: >- + If false and the object_id refers to a bundle, then the + ContentsObject array contains only those objects directly + contained in the bundle. That is, if the bundle contains other + bundles, those other bundles are not recursively included in + the result. + + If true and the object_id refers to a bundle, then the entire + set of objects in the bundle is expanded. That is, if the + bundle contains other bundles, then those other bundles are + recursively expanded and included in the result. Recursion + continues through the entire sub-tree of the bundle. + + If the object_id refers to a blob, then the query parameter is + ignored. + passports: + type: array + items: + type: string + example: >- + eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM + description: >- + the encoded JWT GA4GH Passport that contains embedded Visas. + The overall JWT is signed as are the individual Passport + Visas. + Passports: + required: true + content: + application/json: + schema: + type: object + properties: + passports: + type: array + items: + type: string + example: >- + eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM + description: >- + the encoded JWT GA4GH Passport that contains embedded Visas. + The overall JWT is signed as are the individual Passport + Visas.