Using the REST API
AnyVar can be interacted with via HTTP requests.
Swagger UI Docs
An AnyVar server hosts Swagger UI documentation at the server root address (e.g. http://localhost:8000 by default in the context of local service). This shows all API routes, includes schemas describing valid request and response structures, and an easy-to-use interface to test out API calls.
Basic Variant Operations
Send a PUT request to /variation with a payload containing a variant definition using a supported variant definition nomenclature. If translation and registration are successful, the response will include the variant’s identifier and the complete VRS allele object.
>>> import requests
>>> payload = {"definition": "NC_000010.11:g.87894077C>T"}
>>> response = requests.put("http://localhost:8000/variation", json=payload)
>>> allele_id = response.json()["object_id"]
>>> allele_id
'ga4gh:VA.K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU'
>>> response.json()["object"]
{'id': 'ga4gh:VA.K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU', 'type': 'Allele', 'digest': 'K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU', 'location': {'id': 'ga4gh:SL.01EH5o6V6VEyNUq68gpeTwKE7xOo-WAy', 'type': 'SequenceLocation', 'digest': '01EH5o6V6VEyNUq68gpeTwKE7xOo-WAy', 'sequenceReference': {'type': 'SequenceReference', 'refgetAccession': 'SQ.ss8r_wB0-b9r44TQTMmVTI92884QvBiB'}, 'start': 87894076, 'end': 87894077}, 'state': {'type': 'LiteralSequenceExpression', 'sequence': 'T'}}
A GET request to /variation/<ID> can be used to retrieve the same object later.
>>> response = requests.get(f"http://localhost:8000/object/{allele_id}")
>>> response.json()["data"]
{'id': 'ga4gh:VA.K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU', 'type': 'Allele', 'digest': 'K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU', 'location': {'id': 'ga4gh:SL.aCMcqLGKClwMWEDx3QWe4XSiGDlKXdB8', 'type': 'SequenceLocation', 'digest': 'aCMcqLGKClwMWEDx3QWe4XSiGDlKXdB8', 'sequenceReference': {'type': 'SequenceReference', 'refgetAccession': 'SQ.ss8r_wB0-b9r44TQTMmVTI92884QvBiB'}, 'start': 87894076, 'end': 87894077}, 'state': {'type': 'LiteralSequenceExpression', 'sequence': 'T'}}
Variant registration also registered contained VRS objects, like SequenceLocations and SequenceReferences. Those objects can be retrieved in a similar manner.
>>> location_id = "ga4gh:SL.01EH5o6V6VEyNUq68gpeTwKE7xOo-WAy"
>>> response = requests.get(f"http://localhost:8000/object/{location_id}")
>>> response.json()["data"]
{'id': 'ga4gh:SL.01EH5o6V6VEyNUq68gpeTwKE7xOo-WAy', 'type': 'SequenceLocation', 'digest': '01EH5o6V6VEyNUq68gpeTwKE7xOo-WAy', 'sequenceReference': {'type': 'SequenceReference', 'refgetAccession': 'SQ.ss8r_wB0-b9r44TQTMmVTI92884QvBiB'}, 'start': 87894076, 'end': 87894077}
Searching Variants
The /search endpoint enables retrieval of all variants that overlap a provided interval:
>>> sequence_accession_id = "ga4gh:SQ.ss8r_wB0-b9r44TQTMmVTI92884QvBiB"
>>> start, end = 87894070, 87894080
>>> response = requests.get(f"http://localhost:8000/search?accession={sequence_accession_id}&start={start}&end={end}")
>>> response.json()["variations"][0]
{'id': 'ga4gh:VA.K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU',
'type': 'Allele',
'digest': 'K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU',
'location': {'id': 'ga4gh:SL.aCMcqLGKClwMWEDx3QWe4XSiGDlKXdB8',
'type': 'SequenceLocation',
'digest': 'aCMcqLGKClwMWEDx3QWe4XSiGDlKXdB8',
'sequenceReference': {'type': 'SequenceReference',
'refgetAccession': 'SQ.ss8r_wB0-b9r44TQTMmVTI92884QvBiB'},
'start': 87894076,
'end': 87894077},
'state': {'type': 'LiteralSequenceExpression', 'sequence': 'T'}}
Bulk Variant Registration
The /variations endpoint accepts a list of variation definitions for bulk registration. Each input produces a corresponding result in the response, in the same order. Variations that fail translation are not registered and return null for the object and object_id fields.
>>> payload = [
... {"definition": "NC_000010.11:g.87894077C>T"},
... {"definition": "NC_000007.14:g.140753336A>T"},
... ]
>>> response = requests.put("http://localhost:8000/variations", json=payload)
>>> response.status_code
200
>>> len(response.json())
2
>>> response.json()[0]["object_id"]
'ga4gh:VA.K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU'
Asynchronous Bulk Registration
For larger batches of variations, the /variations endpoint supports the same asynchronous request-response pattern used by the /vcf endpoint (see async configuration). Set the run_async query parameter to true to submit the job asynchronously. The server returns a 202 Accepted response containing a run_id, which can be used to poll for the result at GET /variations/{run_id}.
>>> payload = [{"definition": f"NC_000010.11:g.{pos}C>T"} for pos in range(87894070, 87894080)]
>>> response = requests.put("http://localhost:8000/variations?run_async=true", json=payload)
>>> response.status_code
202
>>> run_id = response.json()["run_id"]
>>> print(response.json()["status_message"])
'Run submitted. Check status at /variations/<run_id>'
>>> # poll for status
>>> status_response = requests.get(f"http://localhost:8000/variations/{run_id}")
>>> status_response.status_code # 202 while in progress, 200 when complete
202
>>> # keep requesting until 200 OK
>>> status_response = requests.get(f"http://localhost:8000/variations/{run_id}")
>>> status_response.status_code
200
>>> # the response body is the list of registration results
>>> len(status_response.json())
10
An optional run_id query parameter can be supplied to use a specific identifier for the run instead of a randomly generated UUID:
>>> response = requests.put(
... "http://localhost:8000/variations?run_async=true&run_id=my-custom-run-id",
... json=payload,
... )
>>> response.json()["run_id"]
'my-custom-run-id'
Note
Asynchronous variation registration requires Celery and a message broker (e.g. Redis). The CELERY_BROKER_URL environment variable must be set. See async configuration for details.
Working With Mappings
To add a mapping between previously-registered variation objects issue a PUT request to /object/<vrs_id>/mappings, where vrs_id is the source_id of the mapping object:
>>> payload = {"definition": "NC_000007.14:g.140753336A>T"}
>>> response = requests.put("http://localhost:8000/variation", json=payload)
>>> genomic_id = response.json()["object"]["id"]
>>> payload = {"definition": "NM_004333.6:c.1799T>A"}
>>> response = requests.put("http://localhost:8000/variation", json=payload)
>>> tx_id = response.json()["object"]["id"]
>>> payload = {"dest_id": tx_id, "mapping_type": "transcribe_to"}
>>> requests.put(
... f"http://localhost:8000/object/{genomic_id}/mappings",
... json=payload
... )
Mappings from an object can be retrieved via GET /object/<vrs_id>/mappings?mapping_type=<mapping_type>:
>>> response = requests.get(
... f"http://localhost:8000/object/{genomic_id}/mappings?mapping_type=transcribe_to"
... )
>>> response.json()
{'mappings': [{'source_id': 'ga4gh:VA.Otc5ovrw906Ack087o1fhegB4jDRqCAe',
'dest_id': 'ga4gh:VA.W6xsV-aFm9yT2Bic5cFAV2j0rll6KK5R',
'mapping_type': 'transcribe_to'}]}
By default, when a GRCh37 or GRCh38 variant is registered, the lifted-over equivalent is also registered, and mappings between them are stored.
>>> payload = {"definition": "NC_000010.11:g.87894077C>T"}
>>> response = requests.put("http://localhost:8000/variation", json=payload)
>>> registered_allele_id = response.json()["object_id"]
>>> response = requests.get(
... f"http://localhost:8000/object/{registered_allele_id}/mappings?mapping_type=liftover_to"
... )
>>> response.json()
{'mappings': [{'source_id': 'ga4gh:VA.K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU',
'dest_id': 'ga4gh:VA.rQBlRht2jfsSp6TpX3xhraxtmgXNKvQf',
'mapping_type': 'liftover_to'}]}
Working With Extensions
To add a new extension to a registered variation, send a POST request to /object/<vrs_id>/extensions with a payload containing the extension name and value:
>>> payload = {
... "name": "clinvar_accession",
... "value": "VCV000012345.6",
... }
>>> braf_v600e_id = "ga4gh:VA.K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU"
>>> response = requests.post(f"http://localhost:8000/object/{braf_v600e_id}/extensions", json=payload)
Extensions can be retrieved via a GET request for the VRS ID and extension name:
>>> resp = requests.get(f"http://localhost:8000/object/{braf_v600e_id}/extensions/clinvar_accession")
>>> response.json()
{'object': {'id': 'ga4gh:VA.K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU',
'type': 'Allele',
'digest': 'K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU',
'location': {'id': 'ga4gh:SL.aCMcqLGKClwMWEDx3QWe4XSiGDlKXdB8',
'type': 'SequenceLocation',
'digest': 'aCMcqLGKClwMWEDx3QWe4XSiGDlKXdB8',
'sequenceReference': {'type': 'SequenceReference',
'refgetAccession': 'SQ.ss8r_wB0-b9r44TQTMmVTI92884QvBiB'},
'start': 87894076,
'end': 87894077},
'state': {'type': 'LiteralSequenceExpression', 'sequence': 'T'}},
'object_id': 'ga4gh:VA.K7akyz9PHB0wg8wBNVlWAAdvMbJUJJfU',
'extension_name': 'clinvar_accession',
'extension_value': 'VCV000012345.6'}
VCF Annotation and Ingestion
AnyVar can perform bulk variant ingest operations on Variant Call Format (VCF) files.
Files submitted to the /vcf endpoint will be parsed for variants, which will be translated into VRS objects and stored, and a copy of the file with added VRS ID annotations is returned.
>>> with open("my_vcf.vcf", "rb") as f:
... files = {"vcf": ("my_vcf.vcf", f, "text/plain")}
... response = requests.put("http://localhost:8000/vcf", files=files)
>>> response.raise_for_status()
>>> "VRS_Allele_IDs" in response.text
True
For larger files, a nontrivial amount of processing time may be required before the annotated file is ready to return. Users are advised to use the run_async parameter, which employs an asynchronous request-response pattern to support multiple long-running tasks. The /variations endpoint supports the same pattern for bulk variant registration (see Asynchronous Bulk Registration). In this model, when run requests are submitted, a run ID is returned. This ID can then be used to poll the server for the status of the task, responding with 202 ACCEPTED if the task was submitted successfully, but is still in progress, and then returning the annotated file when it’s ready.
>>> with open("big_vcf.vcf", "rb") as f:
... files = {"vcf": ("big_vcf.vcf", f, "text/plain")}
... response = requests.put("http://localhost:8000/vcf?enable_async=true", files=files)
>>> print(response.json()["status_message"])
'Run submitted. Check status at /vcf/05385087-78e2-44d4-8ecc-3ca74563c4b1'
>>> run_id = response.json()["run_id"]
>>> response = requests.get(f"http://localhost:8000/vcf/{run_id}")
>>> response.status_code
202
>>> # keep requesting until `200 OK`
>>> response = requests.get(f"http://localhost:8000/vcf/{run_id}")
>>> response.status_code
200
>>> # this indicates the task is complete and the request includes the finished file
>>> "VRS_Allele_IDs" in response.text
True
Get Service Info
AnyVar implements the GA4GH Service Info specification. Get information about the AnyVar instance and the data standards it employs at GET /service-info:
>>> response = requests.get("http://localhost:8000/service-info")
>>> response.json()["name"]
'AnyVar'
>>> response.json()["spec_metadata"]
{'vrs_version': '2.0.1'}