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.
Each implementation of DRS can choose its own id scheme, as long as it follows these guidelines:
For convenience, including when passing content references to a WES server, we define a URI scheme 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 for more information on our design motivations for 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://<hostname>/<id>
DRS URIs of this form mean "you can fetch the content with DRS id <id> from the DRS server at <hostname>". For example, here are the client resolution steps if the URI is:
drs://drs.example.org/314159
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 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 use resolver registry services (specifically, identifiers.org and n2t.net (Name-To-Thing)) 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).
For more information, see the document More Background on Compact Identifiers.
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 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.
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.
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
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.)
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 for details.) The URL pattern is a string containing a {$id} parameter, such as:
https://drs.myexample.org/ga4gh/drs/v1/objects/{$id}
GET https://drs.myexample.org/ga4gh/drs/v1/objects/314159
For performance reasons, DRS clients SHOULD cache the URL pattern returned in step 2, with a suggested 24 hour cache life.
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 for more information on resolver registry security.) |
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).
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.
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 for suggested best practices for working with compound objects.
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. 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.
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.
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 standard.
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 or a GA4GH Passport, although they can choose other mechanisms if appropriate.
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:
access_url with a url and no headersaccess_url with a url and no headersaccess_url with a url and headersaccess_idaccess_id to the /access endpointaccess_url with the generated mechanism (e.g. a signed URL in the url field)url (passing auth info from the specified headers, if any)In the approaches above GA4GH Passports 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.
The APIs to fetch DrsObjects and AccessURLs 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 and an associated AccessURL. Implementers should indicate how to authenticate to fetch a DrsObject by implementing the OptionsOjbect API. Implementers should indicate how to authenticate to fetch an AccessURL within a DrsObject.
A valid authorization token must be passed in the 'Authorization' header, e.g. "Basic ${token_string}"
| Security Scheme Type | HTTP |
|---|---|
| HTTP Authorization Scheme | basic |
A valid authorization token must be passed in the 'Authorization' header, e.g. "Bearer ${token_string}"
| Security Scheme Type | HTTP |
|---|---|
| HTTP Authorization Scheme | bearer |
A valid authorization GA4GH Passport token must be passed in the body of a POST request
| Security Scheme Type | HTTP |
|---|---|
| HTTP POST | tokens[] |
Returns a list of Authorizations that can be used to determine how to authorize requests to GetObject or PostObject.
| object_id required | string
|
{- "drs_object_id": "string",
- "supported_types": [
- "None"
], - "passport_auth_issuers": [
- "string"
], - "bearer_auth_issuers": [
- "string"
]
}Returns object metadata, and a list of access methods that can be used to fetch object bytes.
| object_id required | string
|
| expand | boolean 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. |
{- "id": "string",
- "name": "string",
- "self_uri": "drs://drs.example.org/314159",
- "size": 0,
- "created_time": "2019-08-24T14:15:22Z",
- "updated_time": "2019-08-24T14:15:22Z",
- "version": "string",
- "mime_type": "application/json",
- "checksums": [
- {
- "checksum": "string",
- "type": "sha-256"
}
], - "access_methods": [
- {
- "type": "s3",
- "access_url": {
- "url": "string",
- "headers": "Authorization: Basic Z2E0Z2g6ZHJz"
}, - "access_id": "string",
- "cloud": "aws, gcp, or azure",
- "region": "us-east-1",
- "available": true,
- "authorizations": {
- "drs_object_id": "string",
- "supported_types": [
- "None"
], - "passport_auth_issuers": [
- "string"
], - "bearer_auth_issuers": [
- "string"
]
}
}
], - "contents": [
- {
- "name": "string",
- "id": "string",
- "drs_uri": "drs://drs.example.org/314159",
- "contents": [
- { }
]
}
], - "description": "string",
- "aliases": [
- "string"
]
}This endpoint supports two modes of operation based on the request body:
Retrieve Mode (backward compatible): When the "object" field is missing, returns object metadata and a list of access methods that can be used to fetch object bytes.
Register Mode: When the "object" field contains a DRS object, registers the supplied fully formed DRS object using the provided passports for authorization.
Method is a POST to accommodate a JWT GA4GH Passport sent in the request body in order to authorize access.
Note: To upload new files before registering them as DRS objects, use the /uploadrequest endpoint to obtain upload methods and temporary credentials. For registering multiple objects at once, use the bulk POST /objects endpoint. Note that upload functionality is optional and not all DRS servers implement the /uploadrequest endpoint.
| object_id required | string
|
| expand | boolean 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 | Array of strings the encoded JWT GA4GH Passport that contains embedded Visas. The overall JWT is signed as are the individual Passport Visas. |
object (DrsObject) |
Request object metadata with passport authentication - no objects array provided
{- "expand": false,
- "passports": [
- "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM"
]
}{- "id": "string",
- "name": "string",
- "self_uri": "drs://drs.example.org/314159",
- "size": 0,
- "created_time": "2019-08-24T14:15:22Z",
- "updated_time": "2019-08-24T14:15:22Z",
- "version": "string",
- "mime_type": "application/json",
- "checksums": [
- {
- "checksum": "string",
- "type": "sha-256"
}
], - "access_methods": [
- {
- "type": "s3",
- "access_url": {
- "url": "string",
- "headers": "Authorization: Basic Z2E0Z2g6ZHJz"
}, - "access_id": "string",
- "cloud": "aws, gcp, or azure",
- "region": "us-east-1",
- "available": true,
- "authorizations": {
- "drs_object_id": "string",
- "supported_types": [
- "None"
], - "passport_auth_issuers": [
- "string"
], - "bearer_auth_issuers": [
- "string"
]
}
}
], - "contents": [
- {
- "name": "string",
- "id": "string",
- "drs_uri": "drs://drs.example.org/314159",
- "contents": [
- { }
]
}
], - "description": "string",
- "aliases": [
- "string"
]
}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).
| bulk_object_ids | Array of strings An array of ObjectIDs. |
{- "bulk_object_ids": [
- "string"
]
}{- "summary": {
- "requested": 0,
- "resolved": 0,
- "unresolved": 0
}, - "unresolved_drs_objects": [
- {
- "error_code": 0,
- "object_ids": [
- "string"
]
}
], - "resolved_drs_object": [
- {
- "drs_object_id": "string",
- "supported_types": [
- "None"
], - "passport_auth_issuers": [
- "string"
], - "bearer_auth_issuers": [
- "string"
]
}
]
}This endpoint supports two modes of operation based on the request body:
Retrieve Mode (backward compatible): When the request contains bulk_object_ids,
returns an array of object metadata and access methods for the specified object IDs.
Register Mode: When the request contains an objects array with fully formed DRS objects,
registers the supplied DRS objects using the provided passports for authorization.
For retrieve mode, the request 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.
Note: Register mode is typically used after uploading files via the /uploadrequest endpoint to register the uploaded files as DRS objects in bulk.
| expand | boolean 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 | Array of strings the encoded JWT GA4GH Passport that contains embedded Visas. The overall JWT is signed as are the individual Passport Visas. |
| bulk_object_ids | Array of strings An array of ObjectIDs for retrieve mode. When this field is present, the endpoint behaves as a bulk retrieval operation returning metadata for the specified objects. |
Array of objects (DrsObject) An array of fully formed DRS objects for register mode. When this field is present, the endpoint registers the supplied DRS objects using the passports for authorization. This field is mutually exclusive with bulk_object_ids. |
Retrieve metadata for multiple existing DRS objects using their IDs
{- "passports": [
- "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM"
], - "bulk_object_ids": [
- "drs_object_123456",
- "drs_object_789012",
- "drs_object_345678"
]
}{- "summary": {
- "requested": 0,
- "resolved": 0,
- "unresolved": 0
}, - "unresolved_drs_objects": [
- {
- "error_code": 0,
- "object_ids": [
- "string"
]
}
], - "resolved_drs_object": [
- {
- "id": "string",
- "name": "string",
- "self_uri": "drs://drs.example.org/314159",
- "size": 0,
- "created_time": "2019-08-24T14:15:22Z",
- "updated_time": "2019-08-24T14:15:22Z",
- "version": "string",
- "mime_type": "application/json",
- "checksums": [
- {
- "checksum": "string",
- "type": "sha-256"
}
], - "access_methods": [
- {
- "type": "s3",
- "access_url": {
- "url": "string",
- "headers": "Authorization: Basic Z2E0Z2g6ZHJz"
}, - "access_id": "string",
- "cloud": "aws, gcp, or azure",
- "region": "us-east-1",
- "available": true,
- "authorizations": {
- "drs_object_id": "string",
- "supported_types": [
- "None"
], - "passport_auth_issuers": [
- "string"
], - "bearer_auth_issuers": [
- "string"
]
}
}
], - "contents": [
- {
- "name": "string",
- "id": "string",
- "drs_uri": "drs://drs.example.org/314159",
- "contents": [
- { }
]
}
], - "description": "string",
- "aliases": [
- "string"
]
}
]
}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).
| object_id required | string
|
| access_id required | string An |
{- "url": "string",
- "headers": "Authorization: Basic Z2E0Z2g6ZHJz"
}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.
| object_id required | string
|
| access_id required | string An |
| passports | Array of strings the encoded JWT GA4GH Passport that contains embedded Visas. The overall JWT is signed as are the individual Passport Visas. |
{- "passports": [
- "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM"
]
}{- "url": "string",
- "headers": "Authorization: Basic Z2E0Z2g6ZHJz"
}Returns an array of URL objects that can be used to fetch the bytes of multiple DrsObjects.
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.
| passports | Array of strings |
Array of objects |
{- "passports": [
- "string"
], - "bulk_object_access_ids": [
- {
- "bulk_object_id": "string",
- "bulk_access_ids": [
- "string"
]
}
]
}{- "summary": {
- "requested": 0,
- "resolved": 0,
- "unresolved": 0
}, - "unresolved_drs_objects": [
- {
- "error_code": 0,
- "object_ids": [
- "string"
]
}
], - "resolved_drs_object_access_urls": [
- {
- "drs_object_id": "string",
- "drs_access_id": "string",
- "url": "string",
- "headers": "Authorization: Basic Z2E0Z2g6ZHJz"
}
]
}Optional Functionality: Upload operations are optional extensions to the DRS API. Not all DRS servers are required to implement upload functionality. Clients should check for the availability of upload endpoints before attempting to use them.
The DRS API provides optional upload functionality that allows clients to obtain upload methods and temporary credentials for storing files before they are registered as DRS objects. This capability extends the traditional read-only nature of DRS to support data ingestion workflows.
The upload feature is designed as a negotiation mechanism between client and server to identify mutually convenient storage services and access patterns. The DRS specification defines the negotiation protocol and credential exchange, but the details of how data is physically uploaded to the underlying storage systems are outside the scope of the DRS specification and depend on the specific storage service protocols (S3, HTTPS, etc.). DRS does not reinvent existing storage protocols, but rather facilitates their discovery and authorization.
Upload operations in DRS follow a three-phase approach:
/objects endpointThis design separates the concerns of obtaining upload credentials from the actual file transfer and subsequent DRS object registration, providing flexibility in how files are uploaded while maintaining security through temporary, scoped credentials.
Upload operations are entirely optional. Servers implement uploads when they support data ingestion, collaborative workflows, or staging areas. Read-only servers, mirrors, or security-constrained environments typically do not implement uploads.
Clients should implement proper discovery mechanisms to determine upload support:
The most reliable way to discover upload support is through the /service-info endpoint:
{
"drs": {
"uploadSupported": true,
"supportedUploadMethods": ["s3", "https", "gs"],
"maxUploadSize": 5368709120,
"maxUploadRequestLength": 50,
"validateUploadChecksums": true,
"validateUploadFileSizes": false
}
}
Service Info Fields:
uploadSupported: Boolean indicating if upload operations are availablesupportedUploadMethods: Array of upload method types the server supportsmaxUploadSize: Maximum file size in bytes (optional)maxUploadRequestLength: Maximum files per upload request (optional)validateUploadChecksums: Boolean indicating if server validates uploaded file checksums (optional, defaults to false)validateUploadFileSizes: Boolean indicating if server validates uploaded file sizes (optional, defaults to false)/service-info first for uploadSupported, supportedUploadMethods, and validation flagsmaxUploadSize, maxUploadRequestLength)validateUploadChecksums/validateUploadFileSizes flagsThe /uploadrequest endpoint accepts POST requests containing file metadata and returns available upload methods with temporary credentials.
Upload requests must include:
Note: Servers do not validate the provided MIME type against the actual file content. Clients are responsible for providing accurate MIME type information.
Upload Method Selection: Clients must select one or more upload methods from the server response to upload their files. The selected upload methods determine the storage locations, and clients must include corresponding access methods in the DRS object registration that point to these same storage locations.
Upload responses provide:
Note: While servers advertise their supported upload methods in service-info, the actual upload response may include only a subset of these methods. Servers may choose specific upload methods based on file characteristics such as size, type, or internal policies.
Upload operations support GA4GH Passports (embedded in request body), Basic authentication, and Bearer tokens for flexible authorization.
All upload requests must include checksums to ensure data integrity:
Servers MAY validate checksums and/or file sizes (advertised via validateUploadChecksums/validateUploadFileSizes flags) but are not required to do so. Validation increases security but adds computational overhead.
Upload operations are designed to integrate seamlessly with the broader DRS object lifecycle:
/uploadrequest/objects endpoint to register uploaded files as DRS objectsAfter successfully uploading files using the /uploadrequest endpoint, clients must register the uploaded files as DRS objects to make them accessible through the DRS API. This can be accomplished using either:
/objects/{object_id} for registering one object at a time/objects for registering multiple objects at oncePrepare DRS Object Metadata: Create fully formed DRS object structures with:
Choose Registration Method:
/objects/{object_id} with object field containing one DRS object/objects with objects array containing multiple DRS objectsSubmit Registration Request: Include GA4GH Passport tokens for authorization (if required)
Confirm Registration: Server validates and registers the DRS objects, making them available for subsequent queries
The POST /objects/{object_id} endpoint operates in two modes:
object field with a fully formed DRS object, the endpoint registers the provided objectobject field is missing, the endpoint behaves as a GET request with passport authenticationThe POST /objects endpoint operates in two modes:
objects array with fully formed DRS objects, the endpoint registers the provided objectsbulk_object_ids array, the endpoint behaves as a bulk retrieval operation returning metadata for the specified objectsFor successful DRS object registration after upload:
Note: Servers MAY verify that registered object metadata matches uploaded file characteristics, but are not required to do so.
Single Object Registration:
1. Upload file via /uploadrequest
→ Receive object ID: "drs_obj_123"
2. File is uploaded to storage location
→ File available at provided upload URL
3. Register DRS object via POST /objects/drs_obj_123
→ Request body contains object field with fully formed DRS object
→ Server validates and registers the object
4. Query registered object via GET /objects/drs_obj_123
→ Standard DRS object retrieval now works
Bulk Object Registration:
1. Upload files via /uploadrequest
→ Receive object IDs: "drs_obj_123", "drs_obj_456"
2. Files are uploaded to storage locations
→ Files available at provided upload URLs
3. Register DRS objects via POST /objects
→ Request body contains objects array with fully formed DRS objects
→ Server validates and registers all objects in bulk
4. Query registered objects via GET /objects/drs_obj_123
→ Standard DRS object retrieval now works for all registered objects
Upload operations include comprehensive error handling:
Clients: Calculate checksums, handle multiple upload methods, implement retry logic, check service-info for validation behavior.
Servers: Use short-lived credentials, provide multiple upload methods when possible, implement consistent validation (if any), use rate limiting.
Security: Time-limited credentials, single-use URLs, proper logging, input validation.
/service-info to confirm upload support and available methods/uploadrequest/objects/{object_id} with fully formed DRS object metadata/uploadrequest/objects/{object_id} with complete metadata and S3 access methods/uploadrequest/objects with the same passport tokens (bulk registration)/uploadrequest/objects with objects array containing all uploaded filesOptional Endpoint: This endpoint is not required for DRS server implementations. Not all DRS servers support upload functionality.
Discovery: Before using this endpoint, clients should check the /service-info endpoint to determine if upload operations are supported. Look for drs.uploadSupported: true and drs.supportedUploadMethods to understand which upload methods are available. Also check drs.maxUploadSize and drs.maxUploadRequestLength for server limits.
Request upload methods and temporary credentials for uploading one or more files to the underlying storage service. This endpoint allows clients to obtain the necessary information to upload files before they are registered as DRS objects.
Usage Flow:
/service-info endpoint to confirm upload support (drs.uploadSupported: true) and available methods (drs.supportedUploadMethods)/objects with the pre-assigned object IDs, including access methods that correspond to the upload methods usedAuthentication: The endpoint supports multiple authentication methods including GA4GH Passport tokens sent in the request body. Passport tokens enable fine-grained authorization based on data access policies.
Upload Methods: Response may include multiple options (s3, https, gs, ftp/sftp, globus) for flexibility. Note that servers may return a subset of their advertised supportedUploadMethods based on file-specific factors such as file type, size, or server policies.
File Integrity: All requests must include at least one checksum per file (SHA-256, MD5, or other IANA-registered algorithms).
Server Validation: Servers MAY validate checksums/sizes but are not required to. Check service-info for validation behavior. Servers do not validate MIME types against actual file content - clients are responsible for providing accurate MIME type information.
required | Array of objects (UploadRequestObject) non-empty Array of upload requests for files |
| passports | Array of strings Optional array of GA4GH Passport JWTs for authorization |
Request upload methods for a single file
{- "requests": [
- {
- "name": "sample_data.vcf",
- "size": 1048576,
- "mime_type": "text/plain",
- "checksums": [
- {
- "checksum": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "type": "sha-256"
}
], - "description": "Variant call format file for sample analysis",
- "aliases": [
- "sample_001_variants",
- "vcf_batch_2024"
]
}
], - "passports": [
- "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM"
]
}Response with S3 upload method and temporary credentials
{- "responses": [
- {
- "id": "drs_object_123456",
- "self_uri": "drs://drs.example.org/drs_object_123456",
- "name": "sample_data.vcf",
- "size": 1048576,
- "mime_type": "text/plain",
- "checksums": [
- {
- "checksum": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
- "type": "sha-256"
}
], - "description": "Variant call format file for sample analysis",
- "aliases": [
- "sample_001_variants",
- "vcf_batch_2024"
], - "upload_methods": [
- {
- "type": "s3",
- "access_url": {
- "headers": [
- "Authorization: AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20240101/us-east-1/s3/aws4_request"
]
}, - "region": "us-east-1",
- "credentials": {
- "access_key_id": "AKIAIOSFODNN7EXAMPLE",
- "secret_access_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
- "session_token": "AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4OlgkBN9bkUDNCJiBeb/AXlzBBko7b15fjrBs2+cTQtpZ3CYWFXG8C5zqx37wnOE49mRl/+OtkIKGO7fAE"
}
}
]
}
]
}Optional DRS functionality for removing objects and, optionally, data from the underlying storage service. Servers remain fully compliant without implementing delete endpoints.
Check /service-info for delete capabilities:
{
"drs": {
"deleteSupported": true,
"maxBulkDeleteLength": 100,
"deleteStorageDataSupported": true
}
}
deleteSupported: Whether server implements delete endpointsmaxBulkDeleteLength: Maximum objects per bulk delete request deleteStorageDataSupported: Whether server can attempt to delete underlying storage filesWhy POST instead of DELETE? GA4GH Passports require request bodies, which DELETE methods don't reliably support across all HTTP infrastructure. POST ensures broad compatibility.
POST /objects/{object_id}/deletecurl -X POST "https://drs.example.org/objects/drs_object_123456/delete" \
-H "Content-Type: application/json" \
-d '{"passports": ["..."], "delete_storage_data": false}'
# Response: 204 No Content (indicates metadata deletion success only)
Note: HTTP responses indicate metadata deletion status only. Storage deletion (delete_storage_data: true) is a best effort attempt with no guarantee of success.
POST /objects/deletecurl -X POST "https://drs.example.org/objects/delete" \
-H "Content-Type: application/json" \
-d '{
"bulk_object_ids": ["obj_1", "obj_2", "obj_3"],
"passports": ["..."],
"delete_storage_data": false
}'
# Response: 204 No Content (all metadata deleted) or 207 Multi-Status (mixed metadata results)
GA4GH Passports (in request body):
{"passports": ["eyJhbGci..."], "delete_storage_data": false}
Bearer Tokens (in headers):
curl -H "Authorization: Bearer token" -d '{"delete_storage_data": false}' ...
delete_storage_data: false (default): Removes metadata only, preserves storage files
delete_storage_data: true: Removes metadata AND attempts to delete storage files (requires server support, not guaranteed)
Why no native updates? DRS promotes immutability, data safety, and clear audit trails through explicit operations. This approach also makes implementation simpler by reusing existing endpoints.
Safe Update Process:
POST /objects/{id}/delete with delete_storage_data: falsePOST /objects/{id} with updated metadata# Delete metadata (preserves storage)
curl -X POST ".../objects/obj_123/delete" -d '{"delete_storage_data": false}'
# Re-register with updates
curl -X POST ".../objects/obj_123" -d '{"name": "updated.txt", ...}'
Metadata Update:
curl ".../service-info" # Check capabilities
curl -X POST ".../objects/obj_123/delete" -d '{"delete_storage_data": false}'
curl -X POST ".../objects/obj_123" -d '{"name": "updated.vcf", ...}'
Complete Removal:
curl -X POST ".../objects/obj_456/delete" -H "Authorization: Bearer token" \
-d '{"delete_storage_data": true}'
Bulk Delete:
curl -X POST ".../objects/delete" -d '{
"bulk_object_ids": ["obj_1", "obj_2"],
"passports": ["..."],
"delete_storage_data": false
}'
Clients: Check service-info, default to safe deletion, handle errors, respect limits, confirm destructive operations
Servers: Advertise capabilities, validate permissions, implement limits, audit logging, rate limiting
Delete functionality is designed to be 100% backward compatible:
Deletes a DRS object by ID. This operation removes the DRS object metadata and optionally attempts to delete the underlying storage data based on the delete_storage_data parameter and server capabilities. By default, only DRS object metadata is deleted while preserving underlying storage data. To attempt storage data deletion, clients must explicitly set delete_storage_data to true and the server must support storage data deletion (advertised via deleteStorageDataSupported in service-info). Servers will make a best effort attempt to delete storage data, but success is not guaranteed. This endpoint uses POST method to accommodate GA4GH Passport authentication in the request body, ensuring compatibility across all HTTP clients and proxies. Important: HTTP responses (204 No Content) indicate metadata deletion success only, not storage deletion success.
| object_id required | string
|
| passports | Array of strings the encoded JWT GA4GH Passport that contains embedded Visas. The overall JWT is signed as are the individual Passport Visas. |
| delete_storage_data | boolean Default: false If true, delete both DRS object metadata and underlying storage data (follows server's deleteStorageDataSupported capability). If false (default), only delete DRS object metadata while preserving underlying storage data. Clients must explicitly set this to true to enable storage data deletion, ensuring intentional choice for this potentially destructive operation. |
Delete DRS object metadata while preserving underlying storage data. This is the default and safest option.
{- "passports": [
- "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM"
], - "delete_storage_data": false
}Client requested storage data deletion but server doesn't support it
{- "msg": "Server does not support storage data deletion. Set delete_storage_data to false or omit the parameter.",
- "status_code": 400
}Delete multiple DRS objects in a single request. This endpoint supports bulk deletion of objects with optional GA4GH Passport authentication and configurable storage data deletion.
Authentication: GA4GH Passports can be provided in the request body for authorization.
Storage Data Deletion: The delete_storage_data parameter controls whether underlying storage files are deleted along with DRS metadata. Defaults to false for safety. Servers will make a best effort attempt to delete storage data, but success is not guaranteed.
Bulk Limits: Servers may impose limits on the number of objects that can be deleted in a single request. Check the maxBulkDeleteLength field in service-info for limits.
Response Behavior: - Returns 204 No Content if all object metadata is successfully deleted - Returns 207 Multi-Status if some object metadata fails to delete - Returns 413 Request Entity Too Large if bulk limit is exceeded - Returns 404 Not Found if delete operations are not supported by this server - HTTP responses reflect metadata deletion status only, not storage deletion success
| bulk_object_ids required | Array of strings Array of DRS object IDs to delete |
| passports | Array of strings the encoded JWT GA4GH Passport that contains embedded Visas. The overall JWT is signed as are the individual Passport Visas. |
| delete_storage_data | boolean Default: false If true, delete both DRS object metadata and underlying storage data (follows server's deleteStorageDataSupported capability). If false (default), only delete DRS object metadata while preserving underlying storage data. Clients must explicitly set this to true to enable storage data deletion, ensuring intentional choice for this potentially destructive operation. |
Delete multiple DRS objects metadata while preserving underlying storage data (default and safest option)
{- "bulk_object_ids": [
- "drs_object_123456",
- "drs_object_789012",
- "drs_object_345678"
], - "passports": [
- "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM"
], - "delete_storage_data": false
}Some objects deleted successfully, others failed due to various reasons
{- "results": [
- {
- "object_id": "drs_object_123456",
- "status": 204,
- "message": "Successfully deleted"
}, - {
- "object_id": "drs_object_789012",
- "status": 404,
- "message": "Object not found",
- "error": {
- "msg": "DRS object drs_object_789012 does not exist",
- "status_code": 404
}
}, - {
- "object_id": "drs_object_345678",
- "status": 403,
- "message": "Insufficient permissions",
- "error": {
- "msg": "Client lacks delete permission for object drs_object_345678",
- "status_code": 403
}
}
]
}Returns information about the DRS service along with stats pertaning to total object count and cumulative size in bytes. Also indicates whether the server supports optional upload and delete operations and which methods are available.
Extends the v1.0.0 GA4GH Service Info specification as the standardized format for GA4GH web services to self-describe.
According to the service-info type registry maintained by the Technical Alignment Sub Committee (TASC), a DRS service MUST have:
type.group value of org.ga4ghtype.artifact value of drsExample 1: Server with upload and delete capabilities
{
"id": "com.example.drs",
"description": "Serves data according to DRS specification",
...
"type": {
"group": "org.ga4gh",
"artifact": "drs",
"version": "1.5"
}
...
"drs":{
"maxBulkRequestLength": 200,
"objectCount": 774560,
"totalObjectSize": 4018437188907752,
"uploadSupported": true,
"supportedUploadMethods": ["s3", "https", "gs"],
"maxUploadSize": 5368709120,
"maxUploadRequestLength": 50,
"validateUploadChecksums": true,
"validateUploadFileSizes": false,
"deleteSupported": true,
"maxBulkDeleteLength": 100,
"deleteStorageDataSupported": true
}
}
Example 2: Read-only server (no upload or delete)
{
"id": "com.example.readonly-drs",
"description": "Read-only DRS service",
...
"type": {
"group": "org.ga4gh",
"artifact": "drs",
"version": "1.5"
}
...
"drs":{
"maxBulkRequestLength": 500,
"objectCount": 1250000,
"totalObjectSize": 8500000000000000
}
}
Example 3: Server with metadata-only delete capability
{
"id": "com.example.metadata-drs",
"description": "DRS service with metadata-only delete",
...
"type": {
"group": "org.ga4gh",
"artifact": "drs",
"version": "1.5"
}
...
"drs":{
"maxBulkRequestLength": 200,
"objectCount": 500000,
"totalObjectSize": 2500000000000000,
"deleteSupported": true,
"maxBulkDeleteLength": 50,
"deleteStorageDataSupported": false
}
}
See the Service Registry Appendix for more information on how to register a DRS service with a service registry.
{- "id": "org.ga4gh.myservice",
- "name": "My project",
- "type": {
- "group": "org.ga4gh",
- "artifact": "drs",
- "version": "1.0.0"
}, - "description": "This service provides...",
- "contactUrl": "mailto:support@example.com",
- "createdAt": "2019-06-04T12:58:19Z",
- "updatedAt": "2019-06-04T12:58:19Z",
- "environment": "test",
- "version": "1.0.0",
- "maxBulkRequestLength": 0,
- "drs": {
- "maxBulkRequestLength": 0,
- "objectCount": 0,
- "totalObjectSize": 0,
- "uploadSupported": false,
- "supportedUploadMethods": [
- "s3"
], - "maxUploadSize": 0,
- "maxUploadRequestLength": 0,
- "validateUploadChecksums": false,
- "validateUploadFileSizes": false,
- "deleteSupported": false,
- "maxBulkDeleteLength": 0,
- "deleteStorageDataSupported": false
}
}| type required | string Enum: "s3" "gs" "ftp" "gsiftp" "globus" "htsget" "https" "file" Type of the access method. |
object An | |
| access_id | string An arbitrary string to be passed to the |
| cloud | string Name of the cloud service provider that the object belongs to. If the cloud service is Amazon Web Services, Google Cloud Platform or Azure the values should be |
| region | string Name of the region in the cloud service provider that the object belongs to. |
| available | boolean Availablity of file in the cloud. This label defines if this file is immediately accessible via DRS. Any delay or requirement of thawing mechanism if the file is in offline/archival storage is classified as false, meaning it is unavailable. |
object When |
{- "type": "s3",
- "access_url": {
- "url": "string",
- "headers": "Authorization: Basic Z2E0Z2g6ZHJz"
}, - "access_id": "string",
- "cloud": "aws, gcp, or azure",
- "region": "us-east-1",
- "available": true,
- "authorizations": {
- "drs_object_id": "string",
- "supported_types": [
- "None"
], - "passport_auth_issuers": [
- "string"
], - "bearer_auth_issuers": [
- "string"
]
}
}| url required | string A fully resolvable URL that can be used to fetch the actual object bytes. |
| headers | Array of strings An optional list of headers to include in the HTTP request to |
{- "url": "string",
- "headers": "Authorization: Basic Z2E0Z2g6ZHJz"
}| checksum required | string The hex-string encoded checksum for the data |
| type required | string The digest method used to create the checksum.
The value (e.g. |
{- "checksum": "string",
- "type": "sha-256"
}| name required | string 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 | string A DRS identifier of a |
| drs_uri | Array of strings 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. |
| contents | Array of objects (ContentsObject) 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. |
{- "name": "string",
- "id": "string",
- "drs_uri": "drs://drs.example.org/314159",
- "contents": [
- { }
]
}| id required | string An identifier unique to this |
| name | string A string that can be used to name a |
| self_uri required | string 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 |
| size required | integer <int64> For blobs, the blob size in bytes.
For bundles, the cumulative size, in bytes, of items in the |
| created_time required | string <date-time> Timestamp of content creation in RFC3339. (This is the creation time of the underlying content, not of the JSON object.) |
| updated_time | string <date-time> Timestamp of content update in RFC3339, identical to |
| version | string A string representing a version. (Some systems may use checksum, a RFC3339 timestamp, or an incrementing version number.) |
| mime_type | string A string providing the mime-type of the |
required | Array of objects (Checksum) non-empty The checksum of the |
Array of objects (AccessMethod) non-empty The list of access methods that can be used to fetch the | |
Array of objects (ContentsObject) If not set, this | |
| description | string A human readable description of the |
| aliases | Array of strings A list of strings that can be used to find other metadata about this |
{- "id": "string",
- "name": "string",
- "self_uri": "drs://drs.example.org/314159",
- "size": 0,
- "created_time": "2019-08-24T14:15:22Z",
- "updated_time": "2019-08-24T14:15:22Z",
- "version": "string",
- "mime_type": "application/json",
- "checksums": [
- {
- "checksum": "string",
- "type": "sha-256"
}
], - "access_methods": [
- {
- "type": "s3",
- "access_url": {
- "url": "string",
- "headers": "Authorization: Basic Z2E0Z2g6ZHJz"
}, - "access_id": "string",
- "cloud": "aws, gcp, or azure",
- "region": "us-east-1",
- "available": true,
- "authorizations": {
- "drs_object_id": "string",
- "supported_types": [
- "None"
], - "passport_auth_issuers": [
- "string"
], - "bearer_auth_issuers": [
- "string"
]
}
}
], - "contents": [
- {
- "name": "string",
- "id": "string",
- "drs_uri": "drs://drs.example.org/314159",
- "contents": [
- { }
]
}
], - "description": "string",
- "aliases": [
- "string"
]
}| msg | string A detailed error message. |
| status_code | integer The integer representing the HTTP status code (e.g. 200, 404). |
{- "msg": "string",
- "status_code": 0
}required | Array of objects (UploadRequestObject) non-empty Array of upload requests for files |
| passports | Array of strings Optional array of GA4GH Passport JWTs for authorization |
{- "requests": [
- {
- "name": "string",
- "size": 0,
- "mime_type": "string",
- "checksums": [
- {
- "checksum": "string",
- "type": "sha-256"
}
], - "description": "string",
- "aliases": [
- "string"
]
}
], - "passports": [
- "string"
]
}required | Array of objects (UploadResponseObject) List of upload responses for the requested files |
{- "responses": [
- {
- "id": "string",
- "self_uri": "string",
- "name": "string",
- "size": 0,
- "mime_type": "string",
- "checksums": [
- {
- "checksum": "string",
- "type": "sha-256"
}
], - "description": "string",
- "aliases": [
- "string"
], - "upload_methods": [
- {
- "type": "s3",
- "access_url": {
- "url": "string",
- "headers": "Authorization: Basic Z2E0Z2g6ZHJz"
}, - "region": "us-east-1",
- "credentials": {
- "property1": "string",
- "property2": "string"
}
}
]
}
]
}| name required | string The name of the file to upload |
| size required | integer <int64> Size of the file in bytes |
| mime_type required | string MIME type of the file |
required | Array of objects (Checksum) non-empty Array of checksums for file integrity verification |
| description | string Optional description of the file |
| aliases | Array of strings Optional array of alternative names for the file |
{- "name": "string",
- "size": 0,
- "mime_type": "string",
- "checksums": [
- {
- "checksum": "string",
- "type": "sha-256"
}
], - "description": "string",
- "aliases": [
- "string"
]
}| id required | string Unique DRS object identifier |
| self_uri required | string DRS URI for accessing this object |
| name required | string The name of the file |
| size required | integer <int64> Size of the file in bytes |
| mime_type required | string MIME type of the file |
required | Array of objects (Checksum) non-empty Array of checksums for file integrity verification |
| description | string Optional description of the file |
| aliases | Array of strings Optional array of alternative names |
Array of objects (UploadMethod) Available methods for uploading this file |
{- "id": "string",
- "self_uri": "string",
- "name": "string",
- "size": 0,
- "mime_type": "string",
- "checksums": [
- {
- "checksum": "string",
- "type": "sha-256"
}
], - "description": "string",
- "aliases": [
- "string"
], - "upload_methods": [
- {
- "type": "s3",
- "access_url": {
- "url": "string",
- "headers": "Authorization: Basic Z2E0Z2g6ZHJz"
}, - "region": "us-east-1",
- "credentials": {
- "property1": "string",
- "property2": "string"
}
}
]
}| type required | string Enum: "s3" "gs" "https" "ftp" "sftp" "gsiftp" "globus" Type of upload method. Implementations MAY support any subset of these types. The 'https' type can be used to return a presigned POST URL and is expected to be the most common implementation for typical file uploads. This method provides a simple HTTP POST interface that works with standard web clients. The 's3' type is primarily intended to support uploads of large files that want to take advantage of multipart uploads and automatic retries implemented in AWS libraries. This method provides direct access to S3-specific upload capabilities. Other common implementations include 'gs' for Google Cloud Storage and 'sftp' for secure FTP uploads. |
required | object URL and headers for file upload |
| region | string Cloud region for the upload location. Optional for non-cloud storage types. |
object Temporary credentials for authenticated uploads. May be empty for public upload endpoints or contain cloud-specific credential fields. |
{- "type": "s3",
- "access_url": {
- "url": "string",
- "headers": "Authorization: Basic Z2E0Z2g6ZHJz"
}, - "region": "us-east-1",
- "credentials": {
- "property1": "string",
- "property2": "string"
}
}| passports | Array of strings the encoded JWT GA4GH Passport that contains embedded Visas. The overall JWT is signed as are the individual Passport Visas. |
| delete_storage_data | boolean Default: false If true, delete both DRS object metadata and underlying storage data (follows server's deleteStorageDataSupported capability). If false (default), only delete DRS object metadata while preserving underlying storage data. Clients must explicitly set this to true to enable storage data deletion, ensuring intentional choice for this potentially destructive operation. |
{- "passports": [
- "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM"
], - "delete_storage_data": false
}| bulk_object_ids required | Array of strings Array of DRS object IDs to delete |
| passports | Array of strings the encoded JWT GA4GH Passport that contains embedded Visas. The overall JWT is signed as are the individual Passport Visas. |
| delete_storage_data | boolean Default: false If true, delete both DRS object metadata and underlying storage data (follows server's deleteStorageDataSupported capability). If false (default), only delete DRS object metadata while preserving underlying storage data. Clients must explicitly set this to true to enable storage data deletion, ensuring intentional choice for this potentially destructive operation. |
{- "bulk_object_ids": [
- "drs_object_123456",
- "drs_object_789012",
- "drs_object_345678"
], - "passports": [
- "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnYTRnaF9wYXNzcG9ydF92MSI6W119.JJ5rN0ktP0qwyZmIPpxmF_p7JsxAZH6L6brUxtad3CM"
], - "delete_storage_data": false
}| object_id required | string The DRS object ID |
| status required | integer HTTP status code for this object |
| message | string Human-readable status message |
object (Error) An object that can optionally include information about the error. |
{- "object_id": "drs_object_123456",
- "status": 204,
- "message": "Successfully deleted",
- "error": {
- "msg": "string",
- "status_code": 0
}
}Array of objects (DeleteResult) Results for each object in the delete request |
{- "results": [
- {
- "object_id": "drs_object_123456",
- "status": 204,
- "message": "Successfully deleted"
}, - {
- "object_id": "drs_object_789012",
- "status": 404,
- "message": "Object not found",
- "error": {
- "msg": "DRS object drs_object_789012 does not exist",
- "status_code": 404
}
}
]
}| 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:
|
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".
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.
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 DrsObjects. 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:
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:
DRS URIs are aligned with the FAIR data principles and the Joint Declaration of Data Citation Principles — both hostname-based and compact identifier-based URIs provide globally unique, machine-resolvable, persistent identifiers for data.
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.Note: Identifiers.org/n2t.net API Changes
The examples below show the current API interactions with n2t.net and 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.
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. For more information see More Background on Compact Identifiers.
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.
It takes two API calls to get the URL pattern.
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"
}
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}"
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
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.
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.
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.
For additional examples, see the document More Background on Compact Identifiers.
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.
The GA4GH Service Registry API specification 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.
/service-info (i.e. id, name, description, etc.) should have the same values as the registry entry for that service.type object's artifact property should be drs (i.e. the same as it appears in service-info)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:/ga4gh/drs/v1/objects/{object_id} to the registered url will hit the DrsObject endpoint/ga4gh/drs/v1/service-info to the registered url will hit the Service Info endpointExample 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.5.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"
}
]