UNPKG

hra-api

Version:

The Human Reference Atlas (HRA) API deployed to https://apps.humanatlas.io/api/

1,380 lines (1,359 loc) 296 kB
#!/usr/bin/env node // src/server/server.js import { schedule } from "node-cron"; // src/library/shared/utils/add-to-endpoint.js import toNT from "@rdfjs/to-ntriples"; import stream from "stream-browserify"; function toTripleString(quad) { const subject = toNT(quad.subject).replace("_:_:", "_:"); const predicate = toNT(quad.predicate).replace("_:_:", "_:"); const object = toNT(quad.object).replace("_:_:", "_:"); return `${subject} ${predicate} ${object} . `; } function* sparqlUpdateIterator(graph, quads) { yield ` INSERT DATA { GRAPH <${graph}> { `; for (const quad of quads) { yield toTripleString(quad); } yield "}}\n"; } async function addToEndpoint(graph, quads, endpoint) { return fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/sparql-update" }, body: stream.Readable.from(sparqlUpdateIterator(graph, quads)) }); } // src/library/shared/utils/fetch-linked-data.js import formats from "@rdfjs/formats-common"; import { isReadableStream } from "is-stream"; import jsonld from "jsonld"; import patchResponse from "nodeify-fetch/lib/patchResponse.browser.js"; var EXTENSION_MAPPING = { "json-ld": "application/ld+json", jsonld: "application/ld+json", json: "application/ld+json", nt: "application/n-triples", nq: "application/n-quads", n3: "text/n3", owl: "application/rdf+xml", rdf: "application/rdf+xml", xml: "application/rdf+xml", trig: "application/trig", turtle: "text/turtle", ttl: "text/turtle", html: "text/html", htm: "text/html" }; async function getQuads(url, preferredFormat = "text/turtle") { if (typeof url === "string" && url.startsWith("http")) { const parsers = formats.parsers; const otherFormats = Array.from(parsers.keys()).filter((k) => k !== preferredFormat).sort().reverse(); const res = await fetch(url, { headers: new Headers({ accept: [preferredFormat, ...otherFormats].join(", ") }) }); const type2 = res.headers.get("content-type").split(";")[0]; const extension = EXTENSION_MAPPING[url.split(".").slice(-1)[0]]; const guessedType = parsers.has(type2) ? type2 : parsers.has(extension) ? extension : void 0; if (type2 === "application/json" || guessedType === "application/ld+json") { const json = await res.json(); const quads = await jsonld.toRDF(json); return quads; } else if (guessedType) { let body = res.body; if (!isReadableStream(body)) { body = patchResponse(res).body; } const stream2 = parsers.import(guessedType, body, { baseIRI: url }); const quads = []; for await (const quad of stream2) { quads.push(quad); } return quads; } else { try { const json = JSON.parse(await res.text()); const quads = await jsonld.toRDF(json); return quads; } catch (err) { console.log(err); return Promise.reject(new Error(`unknown content type: ${type2}`)); } } } else { try { const json = typeof url === "string" ? JSON.parse(url) : url; const quads = await jsonld.toRDF(json); return quads; } catch (err) { return Promise.reject(new Error(`unknown content type: ${type}`)); } } } // src/library/shared/utils/sparql.js import jsonld2 from "jsonld"; import Papa from "papaparse"; jsonld2.documentLoader = async (documentUrl) => { const document = await fetch(documentUrl).then((r) => r.json()); return { contextUrl: null, document, documentUrl }; }; function fetchSparql(query, endpoint, mimetype) { const body = new URLSearchParams({ query }); return fetch(endpoint, { method: "POST", headers: { Accept: mimetype, "Content-Type": "application/x-www-form-urlencoded", "Content-Length": body.toString().length.toString() }, body }); } async function select(query, endpoint) { const resp = await fetchSparql(query, endpoint, "text/csv"); const text = await resp.text(); const { data } = Papa.parse(text, { header: true, skipEmptyLines: true, dynamicTyping: true }); return data || []; } async function construct(query, endpoint, frame = void 0) { const resp = await fetchSparql(query, endpoint, "application/ld+json"); const json = await resp.json(); if (frame) { return await jsonld2.frame(json, frame); } else { return json; } } async function update(updateQuery, endpoint) { return fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/sparql-update" }, body: updateQuery }); } async function deleteGraphs(graphs, endpoint) { const updateQuery = graphs.map((graph) => `CLEAR GRAPH <${graph}>;`).join("\n"); return update(updateQuery, endpoint); } // src/library/shared/utils/named-graphs.js var QUERY = "SELECT DISTINCT ?g WHERE { GRAPH ?g { ?s ?p ?o . } }"; async function namedGraphs(endpoint) { const graphs = await select(QUERY, endpoint); return new Set(graphs.map((graph) => graph.g)); } // src/library/shared/utils/ensure-named-graphs.js async function ensureNamedGraphs(graphsToCheck, endpoint) { const graphs = new Set(await namedGraphs(endpoint)); let updateQuery = ""; for (const graphAndUrl of graphsToCheck) { const graph = graphAndUrl.split("@@")[0]; const url = graphAndUrl.split("@@").slice(-1)[0]; if (!graphs.has(graph)) { console.log((/* @__PURE__ */ new Date()).toISOString(), "Adding named graph:", graph); updateQuery += ` CLEAR GRAPH <${graph}>; LOAD <${url}> INTO GRAPH <${graph}>; `; graphs.add(graph); } } await update(updateQuery, endpoint); return graphs; } // src/library/v1/queries/ds-graph-enrichment.rq var ds_graph_enrichment_default = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\nPREFIX rdfs: <http://www.w3\ .org/2000/01/rdf-schema#>\nPREFIX owl: <http://www.w3.org/2002/07/owl#>\nPREFIX ccf: <http://purl.org/ccf/>\nPREFIX HRA: <h\ ttps://purl.humanatlas.io/collection/hra-api>\nPREFIX DSGraphs: <https://purl.humanatlas.io/collection/ds-graphs>\nPREFIX \ DSGraphsExtra: <https://purl.humanatlas.io/graph/ds-graphs-enrichments>\nPREFIX has_characterizing_biomarker_set: <http:/\ /purl.obolibrary.org/obo/RO_0015004>\n\nINSERT {\n GRAPH DSGraphsExtra: {\n ?rui_location ccf:collides_with ?anatomical_\ structure ;\n ccf:collides_with ?as_parent ;\n ccf:collides_with_ct ?cell_type ;\n ccf:collides_with_bm ?bio\ marker .\n }\n}\nUSING HRA:\nUSING DSGraphs:\nUSING NAMED DSGraphsExtra:\nWHERE {\n {\n [] ccf:has_registration_location ?r\ ui_location .\n ?rui_location rdf:type ccf:SpatialEntity .\n\n FILTER NOT EXISTS {\n GRAPH DSGraphsExtra: {\n \ ?rui_location ccf:collides_with [] .\n }\n }\n }\n\n {\n ?rui_location ccf:collides_with ?anatomical_structure\ .\n }\n UNION\n {\n [] rdf:type ccf:SpatialPlacement ;\n ccf:placement_relative_to ?refOrgan ;\n ccf:plac\ ement_for ?rui_location .\n\n {\n ?refOrgan ccf:representation_of ?anatomical_structure .\n }\n UNION\n {\n \ ?refOrgan owl:sameAs [\n ccf:representation_of ?anatomical_structure ;\n ] .\n }\n }\n\n # Manually add pa\ ired organ parents\n OPTIONAL {\n VALUES (?as_parent ?anatomical_structure) {\n # Lymph Node\n (<http://purl.o\ bolibrary.org/obo/UBERON_0000029> <http://purl.obolibrary.org/obo/UBERON_0002509>)\n # Eye\n (<http://purl.oboli\ brary.org/obo/UBERON_0000970> <http://purl.obolibrary.org/obo/UBERON_0004548>)\n (<http://purl.obolibrary.org/obo/UB\ ERON_0000970> <http://purl.obolibrary.org/obo/UBERON_0004549>)\n # Fallopian Tube\n (<http://purl.obolibrary.org\ /obo/UBERON_0003889> <http://purl.obolibrary.org/obo/UBERON_0001303>)\n (<http://purl.obolibrary.org/obo/UBERON_0003\ 889> <http://purl.obolibrary.org/obo/UBERON_0001302>)\n # Kidney\n (<http://purl.obolibrary.org/obo/UBERON_00021\ 13> <http://purl.obolibrary.org/obo/UBERON_0004538>)\n (<http://purl.obolibrary.org/obo/UBERON_0002113> <http://purl\ .obolibrary.org/obo/UBERON_0004539>)\n # Knee\n (<http://purl.obolibrary.org/obo/UBERON_0001465> <http://purl.or\ g/sig/ont/fma/fma24978>)\n (<http://purl.obolibrary.org/obo/UBERON_0001465> <http://purl.org/sig/ont/fma/fma24977>)\n\ # Mammary Gland\n (<http://purl.obolibrary.org/obo/UBERON_0001911> <http://purl.org/sig/ont/fma/fma57991>)\n \ (<http://purl.obolibrary.org/obo/UBERON_0001911> <http://purl.org/sig/ont/fma/fma57987>)\n # Ovary\n (<http:/\ /purl.obolibrary.org/obo/UBERON_0000992> <http://purl.obolibrary.org/obo/UBERON_0002119>)\n (<http://purl.obolibrary\ .org/obo/UBERON_0000992> <http://purl.obolibrary.org/obo/UBERON_0002118>)\n # Palatine Tonsil\n (<http://purl.ob\ olibrary.org/obo/UBERON_0002373> <http://purl.org/sig/ont/fma/fma54974>)\n (<http://purl.obolibrary.org/obo/UBERON_0\ 002373> <http://purl.org/sig/ont/fma/fma54973>)\n # Renal Pelvis\n (<http://purl.obolibrary.org/obo/UBERON_00012\ 24> <http://purl.obolibrary.org/obo/UBERON_0018116>)\n (<http://purl.obolibrary.org/obo/UBERON_0001224> <http://purl\ .obolibrary.org/obo/UBERON_0018115>)\n # Ureter\n (<http://purl.obolibrary.org/obo/UBERON_0000056> <http://purl.\ obolibrary.org/obo/UBERON_0001223>)\n (<http://purl.obolibrary.org/obo/UBERON_0000056> <http://purl.obolibrary.org/o\ bo/UBERON_0001222>)\n # Lung (Edge case: we have reversed the relationship between lung and respiratory system for r\ easons)\n (<http://purl.obolibrary.org/obo/UBERON_0002048> <http://purl.obolibrary.org/obo/UBERON_0001004>)\n (<\ http://purl.obolibrary.org/obo/UBERON_0001004> <http://purl.obolibrary.org/obo/UBERON_0002048>)\n }\n \n OPTIONAL \ {\n ?parent_descriptor rdf:type ccf:CellMarkerDescriptor ;\n ccf:primary_anatomical_structure\ ?as_parent ;\n ccf:primary_cell_type ?cell_type .\n OPTIONAL {\n ?parent_descriptor cc\ f:biomarker ?biomarker .\n }\n }\n }\n\n OPTIONAL {\n ?descriptor rdf:type ccf:CellMarkerDescriptor ;\n \ ccf:primary_anatomical_structure ?anatomical_structure ;\n ccf:primary_cell_type ?cell_type .\n OPT\ IONAL {\n ?descriptor ccf:biomarker ?biomarker .\n }\n }\n}\n"; // src/library/v1/queries/get-dataset-info.rq var get_dataset_info_default = "PREFIX hraApi: <urn:hra-api#>\nPREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n\ PREFIX schema: <http://schema.org/>\nPREFIX xsd: <http://www.w3.org/2001/XMLSchema#>\nPREFIX DSGraphs: <urn:hra-api:TOKEN:\ ds-info>\n\nSELECT ?status ?message ?checkback ?loadTime ?timestamp ?startTime\nFROM DSGraphs:\nWHERE {\n DSGraphs: a hraApi\ :Dataset ;\n hraApi:status ?status ;\n hraApi:message ?message ;\n hraApi:startTime ?startTime ;\n hraApi:update\ Time ?updateTime ;\n\n BIND(IF(?status = 'Ready' || ?status = 'Error', 60 * 60 * 1000, 2000) as ?checkback)\n BIND(STR(?u\ pdateTime) as ?timestamp)\n}\n"; // src/library/v1/queries/prunable-datasets.rq var prunable_datasets_default = `PREFIX hraApi: <urn:hra-api#> PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> SELECT DISTINCT ?age ?maxAge ?dsInfo ?dsGraph ?status ?updateTime WHERE { GRAPH ?dsInfo { ?dsInfo a hraApi:Dataset ; hraApi:namedGraph ?dsGraph ; hraApi:status ?status ; hraApi:updateTime ?updateTime . # Max dataset age is currently set to 24 hours BIND((xsd:dateTime("2001-01-02T00:00:00Z") - xsd:dateTime("2001-01-01T00:00:00Z")) as ?maxAge) BIND(NOW() - ?updateTime as ?age) FILTER((NOW() - ?updateTime) > ?maxAge || ?status = 'Error') } } `; // src/library/v1/queries/start-dataset-info.rq var start_dataset_info_default = 'PREFIX hraApi: <urn:hra-api#>\nPREFIX schema: <http://schema.org/>\nPREFIX DSGraphInfo: \ <urn:hra-api:TOKEN:ds-info>\nPREFIX DSGraph: <urn:hra-api:TOKEN:ds-graph>\n\nWITH DSGraphInfo:\nDELETE {\n DSGraphInfo: a hr\ aApi:Dataset ;\n ?key ?value .\n}\nINSERT {\n DSGraphInfo: a hraApi:Dataset ;\n hraApi:status "Loading" ;\n hraApi:m\ essage "Job is queued to be run..." ;\n hraApi:namedGraph DSGraph: ;\n hraApi:startTime ?startTime ;\n hraApi:upda\ teTime ?startTime ;\n}\nWHERE {\n OPTIONAL {\n DSGraphInfo: a hraApi:Dataset ;\n ?key ?value .\n }\n BIND(NOW() as ?\ startTime)\n}\n'; // src/library/v1/queries/update-dataset-info.rq var update_dataset_info_default = 'PREFIX hraApi: <urn:hra-api#>\nPREFIX schema: <http://schema.org/>\nPREFIX DSGraphs: <u\ rn:hra-api:TOKEN:ds-info>\n\nWITH DSGraphs:\nDELETE {\n DSGraphs: a hraApi:Dataset ;\n hraApi:status ?status ;\n hraApi\ :message ?message ;\n hraApi:updateTime ?updateTime .\n}\nINSERT {\n DSGraphs: a hraApi:Dataset ;\n hraApi:status ?new\ Status ;\n hraApi:message ?newMessage ;\n hraApi:updateTime ?newUpdateTime .\n}\nWHERE {\n OPTIONAL {\n DSGraphs: a \ hraApi:Dataset ;\n hraApi:status ?status ;\n hraApi:message ?message ;\n hraApi:updateTime ?updateTime .\n }\ \n\n BIND("{{STATUS}}" as ?newStatus)\n BIND("{{MESSAGE}}" as ?newMessage)\n BIND(NOW() as ?newUpdateTime)\n}\n'; // src/library/v1/utils/dataset-graph.js var DEFAULT_GRAPHS = [ "https://purl.humanatlas.io/collection/hra-api@@https://cdn.humanatlas.io/digital-objects/collection/hra-api/latest/gr\ aph.ttl", "https://purl.humanatlas.io/graph/hra-ccf-patches@@https://cdn.humanatlas.io/digital-objects/graph/hra-ccf-patches/lat\ est/graph.ttl", "https://purl.humanatlas.io/graph/hra-pop@@https://cdn.humanatlas.io/digital-objects/graph/hra-pop/latest/graph.ttl", "https://purl.humanatlas.io/collection/ds-graphs@@https://cdn.humanatlas.io/digital-objects/collection/ds-graphs/lates\ t/graph.ttl", "https://purl.humanatlas.io/graph/ds-graphs-enrichments@@https://cdn.humanatlas.io/digital-objects/graph/ds-graphs-enr\ ichments/latest/graph.ttl" ]; async function initializeDatasetGraph(token, _request, endpoint) { const updateQuery = start_dataset_info_default.replace("urn:hra-api:TOKEN:ds-info", `urn:hra-api:${token}:ds-info`).replace( "urn:hra-api:TOKEN:ds-graph", `urn:hra-api:${token}:ds-graph`); await update(updateQuery, endpoint); } async function updateDatasetInfo(status, message, token, endpoint) { console.log((/* @__PURE__ */ new Date()).toISOString(), token, status, message); const updateQuery = update_dataset_info_default.replace("urn:hra-api:TOKEN:ds-info", `urn:hra-api:${token}:ds-info`).replace( "{{STATUS}}", status).replace("{{MESSAGE}}", message); return update(updateQuery, endpoint); } async function getDatasetInfo(token, endpoint) { const infoQuery = get_dataset_info_default.replace("urn:hra-api:TOKEN:ds-info", `urn:hra-api:${token}:ds-info`); const status = await select(infoQuery, endpoint); const results = status.length > 0 ? status[0] : { status: "Error", message: "Unknown error while loading database", checkback: 36e5, loadTime: 22594, timestamp: (/* @__PURE__ */ new Date()).toISOString() }; results.loadTime = results.loadTime || (results.status === "Loading" ? /* @__PURE__ */ new Date() : new Date(results.timestamp)) - new Date(results.startTime); return results; } async function createDatasetGraph(token, request, endpoint) { try { const graphs = await ensureNamedGraphs(DEFAULT_GRAPHS, endpoint); const dsGraph = `urn:hra-api:${token}:ds-graph`; const dsGraphEnrichments = `urn:hra-api:${token}:ds-graph-enrichments`; if (!graphs.has(dsGraph)) { for (const source of request.dataSources) { await updateDatasetInfo("Loading", `Adding dataset`, token, endpoint); const quads = await getQuads(source); await addToEndpoint(dsGraph, quads, endpoint); } await updateDatasetInfo("Loading", `Enriching dataset`, token, endpoint); await enrichDatasetGraph(dsGraph, dsGraphEnrichments, endpoint); } await updateDatasetInfo("Ready", `Dataset ready`, token, endpoint); } catch (err) { console.error("ERROR", token, request, endpoint, err); await updateDatasetInfo("Error", `Error processing dataset`, token, endpoint); } } async function enrichDatasetGraph(dsGraph, dsGraphEnrichments, endpoint) { const updateQuery = ds_graph_enrichment_default.replace("PREFIX DSGraphs: <https://purl.humanatlas.io/collection/ds-gr\ aphs>", `PREFIX DSGraphs: <${dsGraph}>`).replace( "PREFIX DSGraphsExtra: <https://purl.humanatlas.io/graph/ds-graphs-enrichments>", `PREFIX DSGraphsExtra: <${dsGraphEnrichments}>` ); const result = await update(updateQuery, endpoint); if (!result.ok) { console.log("error enriching", dsGraph, "code:", result.status); console.error(await result.text()); } return result; } async function pruneDatasetGraphs(endpoint) { const datasets = await select(prunable_datasets_default, endpoint); console.log(datasets.length, "datasets to prune"); if (datasets.length > 0) { const graphs = datasets.reduce((acc, row) => acc.concat([row.dsInfo, row.dsGraph]), []); console.log("deleting", graphs); for (const graph of graphs) { await deleteGraphs([graph], endpoint); } } } // src/server/app.js import cors from "cors"; import express from "express"; import queue from "express-queue"; import helmet from "helmet"; import qs from "qs"; // src/server/cache-middleware.js import { existsSync } from "fs"; import { resolve } from "path"; // src/server/environment.js var DEFAULT_SPARQL_ENDPOINT = "https://lod.humanatlas.io/sparql"; function sparqlEndpoint() { return process.env.SPARQL_ENDPOINT ?? DEFAULT_SPARQL_ENDPOINT; } function isWritable() { return process.env.SPARQL_WRITABLE === "true"; } function exposedSparqlEndpoint() { return process.env.EXPOSED_SPARQL_ENDPOINT ?? (isWritable() ? DEFAULT_SPARQL_ENDPOINT : sparqlEndpoint()); } function port() { return process.env.PORT || 3e3; } function shortCacheTimeout() { return process.env.CACHE_TIMEOUT || 3600; } function pruningSchedule() { return process.env.PRUNING_SCHEDULE || "0 6 * * *"; } function longCacheTimeout() { return process.env.LONG_CACHE_TIMEOUT || shortCacheTimeout() * 24; } function activeQueryLimit() { return process.env.ACTIVE_QUERIES || 4; } function cacheDir() { return process.env.FILE_CACHE_DIR || "./file-cache"; } // src/server/cache-middleware.js function cache(ttl = shortCacheTimeout(), revalidateTtl = 600, errorTtl = 600) { return (_req, res, next) => { res.setHeader( "Cache-Control", `public, max-age=${ttl}, stale-while-revalidate=${revalidateTtl}, stale-if-error=${errorTtl}` ); next(); }; } var longCache = cache(longCacheTimeout()); var shortCache = cache(shortCacheTimeout()); function noCache(_req, res, next) { res.setHeader("Cache-Control", "no-cache"); next(); } function fileCache(filename) { const filepath = resolve(cacheDir(), filename); return async (_req, res, next) => { if (existsSync(filepath)) { res.sendFile(filepath, { cacheControl: false }); } else { next(); } }; } // src/server/fetch-polyfill.js import fetch2, { Headers as Headers2, Request, Response } from "node-fetch"; globalThis.fetch = fetch2; globalThis.Headers = Headers2; globalThis.Request = Request; globalThis.Response = Response; // src/server/routes/browser.js import { Router } from "express"; // hra-api-spec.yaml var hra_api_spec_default = `openapi: 3.0.3 info: title: HRA-API description: | This API provides programmatic access to data registered to the Human Reference Atlas (HRA). See the [HuBMAP HRA Portal](https://humanatlas.io/) for details. version: 0.15.0 contact: name: HuBMAP Help Desk email: help@hubmapconsortium.org license: name: MIT License url: https://spdx.org/licenses/MIT.html servers: - description: HRA-API Production url: https://apps.humanatlas.io/api - description: HRA-API Staging url: https://apps.humanatlas.io/api--staging - description: CCF-API (deprecated) Production url: https://apps.humanatlas.io/hra-api - description: Local Server url: / security: [] tags: - name: v1 description: HRA-API v1 Routes - name: ds-graph description: Dataset Graph Routes - name: hra-kg description: HRA KG Routes - name: hra-pop description: HRApop Routes externalDocs: description: API Documentation url: https://github.com/x-atlas-consortia/hra-api#readme paths: /v1/aggregate-results: get: summary: Get aggregate results / statistics operationId: aggregate-results tags: - v1 parameters: - $ref: '#/components/parameters/Age' - $ref: '#/components/parameters/AgeRange' - $ref: '#/components/parameters/Bmi' - $ref: '#/components/parameters/BmiRange' - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/OntologyTerms' - $ref: '#/components/parameters/CellTypeTerms' - $ref: '#/components/parameters/BiomarkerTerms' - $ref: '#/components/parameters/Consortiums' - $ref: '#/components/parameters/Providers' - $ref: '#/components/parameters/Sex' - $ref: '#/components/parameters/SpatialSearches' - $ref: '#/components/parameters/Technologies' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/AggregateResults' '404': $ref: '#/components/responses/ErrorMessage' /v1/anatomical-systems-tree-model: get: summary: Get anatomical systems partonomy tree nodes operationId: anatomical-systems-tree-model tags: - v1 parameters: - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/OntologyTree' '404': $ref: '#/components/responses/ErrorMessage' /v1/asctb-omap-sheet-config: get: summary: Get OMAP sheet config data for the ASCT+B Reporter operationId: asctb-omap-sheet-config tags: - v1 responses: '200': $ref: '#/components/responses/AsctbReferenceData' '404': $ref: '#/components/responses/ErrorMessage' /v1/asctb-sheet-config: get: summary: Get sheet config data for the ASCT+B Reporter operationId: asctb-sheet-config tags: - v1 responses: '200': $ref: '#/components/responses/AsctbReferenceData' '404': $ref: '#/components/responses/ErrorMessage' /v1/biomarker-term-occurences: get: summary: Get number of biomarker type term occurrences for a search operationId: biomarker-term-occurences tags: - v1 parameters: - $ref: '#/components/parameters/Age' - $ref: '#/components/parameters/AgeRange' - $ref: '#/components/parameters/Bmi' - $ref: '#/components/parameters/BmiRange' - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/OntologyTerms' - $ref: '#/components/parameters/CellTypeTerms' - $ref: '#/components/parameters/BiomarkerTerms' - $ref: '#/components/parameters/Consortiums' - $ref: '#/components/parameters/Providers' - $ref: '#/components/parameters/Sex' - $ref: '#/components/parameters/SpatialSearches' - $ref: '#/components/parameters/Technologies' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/TermOccurences' '404': $ref: '#/components/responses/ErrorMessage' /v1/biomarker-tree-model: get: summary: Get biomarker tree nodes operationId: biomarker-tree-model tags: - v1 parameters: - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/OntologyTree' '404': $ref: '#/components/responses/ErrorMessage' /v1/cell-type-term-occurences: get: summary: Get number of cell type term occurrences for a search operationId: cell-type-term-occurences tags: - v1 parameters: - $ref: '#/components/parameters/Age' - $ref: '#/components/parameters/AgeRange' - $ref: '#/components/parameters/Bmi' - $ref: '#/components/parameters/BmiRange' - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/OntologyTerms' - $ref: '#/components/parameters/CellTypeTerms' - $ref: '#/components/parameters/BiomarkerTerms' - $ref: '#/components/parameters/Consortiums' - $ref: '#/components/parameters/Providers' - $ref: '#/components/parameters/Sex' - $ref: '#/components/parameters/SpatialSearches' - $ref: '#/components/parameters/Technologies' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/TermOccurences' '404': $ref: '#/components/responses/ErrorMessage' /v1/cell-type-tree-model: get: summary: Get cell type tree nodes operationId: cell-type-tree-model tags: - v1 parameters: - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/OntologyTree' '404': $ref: '#/components/responses/ErrorMessage' /v1/collisions: post: summary: Given an extraction site, get mesh-based collisions with the reference organ. operationId: collisions tags: - v1 requestBody: $ref: '#/components/requestBodies/ExtractionSite' responses: '200': description: Successful operation content: application/json: schema: type: object '404': $ref: '#/components/responses/ErrorMessage' '500': $ref: '#/components/responses/ErrorMessage' /v1/consortium-names: get: summary: Get consortium names (for filtering) operationId: consortium-names tags: - v1 parameters: - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/Strings' '404': $ref: '#/components/responses/ErrorMessage' /v1/corridor: post: summary: Given an extraction site, generate a corridor with the reference organ. operationId: corridor tags: - v1 requestBody: $ref: '#/components/requestBodies/ExtractionSite' responses: '200': description: Successful operation content: model/gltf-binary: schema: type: string format: binary '404': $ref: '#/components/responses/ErrorMessage' '500': $ref: '#/components/responses/ErrorMessage' /v1/db-status: get: summary: Get current status of database operationId: db-status tags: - v1 parameters: - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/DatabaseStatus' '404': $ref: '#/components/responses/ErrorMessage' /v1/ds-graph: get: summary: Get dataset graph description: Get potentially filtered experimental data in dataset graph format (previously referred to as rui_loc\ ations.jsonld format) operationId: ds-graph tags: - v1 parameters: - $ref: '#/components/parameters/Age' - $ref: '#/components/parameters/AgeRange' - $ref: '#/components/parameters/Bmi' - $ref: '#/components/parameters/BmiRange' - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/OntologyTerms' - $ref: '#/components/parameters/CellTypeTerms' - $ref: '#/components/parameters/BiomarkerTerms' - $ref: '#/components/parameters/Consortiums' - $ref: '#/components/parameters/Providers' - $ref: '#/components/parameters/Sex' - $ref: '#/components/parameters/SpatialSearches' - $ref: '#/components/parameters/Technologies' - $ref: '#/components/parameters/Token' responses: '200': description: Successful operation content: application/json: schema: type: object '404': $ref: '#/components/responses/ErrorMessage' /v1/extraction-site: get: summary: Lookup Extraction Site operationId: extraction-site tags: - v1 parameters: - $ref: '#/components/parameters/ExtractionSiteIri' responses: '200': description: Successful operation content: application/json: schema: type: object '404': $ref: '#/components/responses/ErrorMessage' /v1/ftu-illustrations: get: summary: Get 2D FTU Illustration data operationId: ftu-illustrations tags: - v1 responses: '200': $ref: '#/components/responses/FtuIllustrations' '404': $ref: '#/components/responses/ErrorMessage' /v1/get-spatial-placement: post: summary: Given a SpatialEntity already placed relative to a reference SpatialEntity, retrieve a new direct Spatial\ Placement to the given SpatialEntity IRI operationId: get-spatial-placement tags: - v1 requestBody: $ref: '#/components/requestBodies/GetSpatialPlacement' responses: '200': $ref: '#/components/responses/SpatialPlacement' '404': $ref: '#/components/responses/ErrorMessage' '500': $ref: '#/components/responses/ErrorMessage' /v1/gtex/rui_locations.jsonld: get: summary: Get all GTEx rui locations (if enabled) description: This option is only enabled if GTEX_ROUTES=true in the environment operationId: gtex-rui-locations tags: - v1 parameters: - $ref: '#/components/parameters/Cache' responses: '200': description: Successful operation content: application/json: schema: type: object '404': description: Not found due to option being disabled /v1/hubmap/rui_locations.jsonld: get: summary: Get all hubmap rui locations (if enabled) description: This option is only enabled if XCONSORTIA_ROUTES=true in the environment operationId: hubmap-rui-locations tags: - v1 parameters: - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/Token' responses: '200': description: Successful operation content: application/json: schema: type: object '404': description: Not found due to option being disabled /v1/mesh-3d-cell-population: post: summary: Given a reference organ, 3d scene node, and cell population, generate cells in that distribution to fit \ in that 3d scene node. operationId: mesh-3d-cell-population tags: - v1 requestBody: $ref: '#/components/requestBodies/Mesh3dCellPopulation' responses: '200': description: Successful response with CSV file content: text/csv: schema: type: string format: binary '404': $ref: '#/components/responses/ErrorMessage' '500': $ref: '#/components/responses/ErrorMessage' /v1/ontology-term-occurences: get: summary: Get number of ontology term occurrences for a search operationId: ontology-term-occurences tags: - v1 parameters: - $ref: '#/components/parameters/Age' - $ref: '#/components/parameters/AgeRange' - $ref: '#/components/parameters/Bmi' - $ref: '#/components/parameters/BmiRange' - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/OntologyTerms' - $ref: '#/components/parameters/CellTypeTerms' - $ref: '#/components/parameters/BiomarkerTerms' - $ref: '#/components/parameters/Consortiums' - $ref: '#/components/parameters/Providers' - $ref: '#/components/parameters/Sex' - $ref: '#/components/parameters/SpatialSearches' - $ref: '#/components/parameters/Technologies' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/TermOccurences' '404': $ref: '#/components/responses/ErrorMessage' /v1/ontology-tree-model: get: summary: Get ontology term tree nodes operationId: ontology-tree-model tags: - v1 parameters: - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/OntologyTree' '404': $ref: '#/components/responses/ErrorMessage' /v1/provider-names: get: summary: Get tissue provider names (for filtering) operationId: provider-names tags: - v1 parameters: - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/Strings' '404': $ref: '#/components/responses/ErrorMessage' /v1/reference-organ-scene: get: summary: Get all nodes to form the 3D scene for an organ operationId: reference-organ-scene tags: - v1 parameters: - $ref: '#/components/parameters/Age' - $ref: '#/components/parameters/AgeRange' - $ref: '#/components/parameters/Bmi' - $ref: '#/components/parameters/BmiRange' - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/OntologyTerms' - $ref: '#/components/parameters/CellTypeTerms' - $ref: '#/components/parameters/BiomarkerTerms' - $ref: '#/components/parameters/OrganIri' - $ref: '#/components/parameters/Consortiums' - $ref: '#/components/parameters/Providers' - $ref: '#/components/parameters/Sex' - $ref: '#/components/parameters/SpatialSearches' - $ref: '#/components/parameters/Technologies' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/SpatialSceneNodes' '404': $ref: '#/components/responses/ErrorMessage' /v1/reference-organs: get: summary: Get all reference organs operationId: reference-organs tags: - v1 parameters: - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/SpatialEntities' '404': $ref: '#/components/responses/ErrorMessage' /v1/rui-reference-data: get: summary: Get reference data for the RUI tool operationId: rui-reference-data tags: - v1 responses: '200': $ref: '#/components/responses/RuiReferenceData' '404': $ref: '#/components/responses/ErrorMessage' /v1/scene: get: summary: Get all nodes to form the 3D scene of reference body, organs, and tissues operationId: scene tags: - v1 parameters: - $ref: '#/components/parameters/Age' - $ref: '#/components/parameters/AgeRange' - $ref: '#/components/parameters/Bmi' - $ref: '#/components/parameters/BmiRange' - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/OntologyTerms' - $ref: '#/components/parameters/CellTypeTerms' - $ref: '#/components/parameters/BiomarkerTerms' - $ref: '#/components/parameters/Consortiums' - $ref: '#/components/parameters/Providers' - $ref: '#/components/parameters/Sex' - $ref: '#/components/parameters/SpatialSearches' - $ref: '#/components/parameters/Technologies' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/SpatialSceneNodes' '404': $ref: '#/components/responses/ErrorMessage' /v1/sennet/rui_locations.jsonld: get: summary: Get all sennet rui locations (if enabled) description: This option is only enabled if XCONSORTIA_ROUTES=true in the environment operationId: sennet-rui-locations tags: - v1 parameters: - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/Token' responses: '200': description: Successful operation content: application/json: schema: type: object '404': description: Not found due to option being disabled /v1/session-token: post: summary: Get a session token operationId: session-token tags: - v1 requestBody: $ref: '#/components/requestBodies/SessionToken' responses: '200': $ref: '#/components/responses/SessionToken' '404': $ref: '#/components/responses/ErrorMessage' '405': $ref: '#/components/responses/ErrorMessage' /v1/sparql: get: summary: Run a SPARQL query operationId: sparql tags: - v1 parameters: - $ref: '#/components/parameters/Query' - $ref: '#/components/parameters/Token' - $ref: '#/components/parameters/Format' responses: '200': $ref: '#/components/responses/SparqlResponse' '404': $ref: '#/components/responses/ErrorMessage' post: summary: Run a SPARQL query (POST) operationId: sparql-post tags: - v1 requestBody: $ref: '#/components/requestBodies/SparqlQuery' parameters: - $ref: '#/components/parameters/Token' - $ref: '#/components/parameters/Format' responses: '200': $ref: '#/components/responses/SparqlResponse' '404': $ref: '#/components/responses/ErrorMessage' /v1/technology-names: get: summary: Get technology names (for filtering) operationId: technology-names tags: - v1 parameters: - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/Strings' '404': $ref: '#/components/responses/ErrorMessage' /v1/tissue-blocks: get: summary: Get Tissue Block Results operationId: tissue-blocks tags: - v1 parameters: - $ref: '#/components/parameters/Age' - $ref: '#/components/parameters/AgeRange' - $ref: '#/components/parameters/Bmi' - $ref: '#/components/parameters/BmiRange' - $ref: '#/components/parameters/Cache' - $ref: '#/components/parameters/OntologyTerms' - $ref: '#/components/parameters/CellTypeTerms' - $ref: '#/components/parameters/BiomarkerTerms' - $ref: '#/components/parameters/Consortiums' - $ref: '#/components/parameters/Providers' - $ref: '#/components/parameters/Sex' - $ref: '#/components/parameters/SpatialSearches' - $ref: '#/components/parameters/Technologies' - $ref: '#/components/parameters/Token' responses: '200': $ref: '#/components/responses/TissueBlocks' '404': $ref: '#/components/responses/ErrorMessage' /ds-graph/atlas-d2k: get: summary: Get Atlas D2K Dataset Graph operationId: atlas-d2k tags: - ds-graph parameters: - $ref: '#/components/parameters/Token' responses: '200': description: Successful operation content: application/json: schema: type: object '404': $ref: '#/components/responses/ErrorMessage' /ds-graph/gtex: get: summary: Get GTEx Dataset Graph operationId: gtex tags: - ds-graph parameters: - $ref: '#/components/parameters/Token' responses: '200': description: Successful operation content: application/json: schema: type: object '404': $ref: '#/components/responses/ErrorMessage' /ds-graph/hubmap: get: summary: Get HuBMAP Dataset Graph operationId: hubmap tags: - ds-graph parameters: - $ref: '#/components/parameters/Token' responses: '200': description: Successful operation content: application/json: schema: type: object '404': $ref: '#/components/responses/ErrorMessage' /ds-graph/sennet: get: summary: Get SenNet Dataset Graph operationId: sennet tags: - ds-graph parameters: - $ref: '#/components/parameters/Token' responses: '200': description: Successful operation content: application/json: schema: type: object '404': $ref: '#/components/responses/ErrorMessage' /hra-pop/cell-summary-report: post: summary: Given a cell summary in csv format, retrieve a predicted cell summary report from HRApop showing relative\ anatomical structures, datasets, and rui locations. operationId: cell-summary-report tags: - hra-pop requestBody: $ref: '#/components/requestBodies/GetCellSummaryReport' responses: '200': $ref: '#/components/responses/CellSummaryReportResponse' '404': $ref: '#/components/responses/ErrorMessage' '500': $ref: '#/components/responses/ErrorMessage' /hra-pop/rui-location-cell-summary: post: summary: Given a SpatialEntity already placed relative to a reference SpatialEntity, retrieve a predicted cell sum\ mary from HRApop operationId: rui-location-cell-summary tags: - hra-pop requestBody: $ref: '#/components/requestBodies/GetRuiLocationCellSummary' responses: '200': $ref: '#/components/responses/RuiLocationCellSummaryResponse' '404': $ref: '#/components/responses/ErrorMessage' '500': $ref: '#/components/responses/ErrorMessage' /hra-pop/supported-organs: get: summary: Get all organs supported by HRApop operationId: supported-organs tags: - hra-pop responses: '200': $ref: '#/components/responses/IdLabelsResponse' '404': $ref: '#/components/responses/ErrorMessage' '500': $ref: '#/components/responses/ErrorMessage' /hra-pop/supported-reference-organs: get: summary: Get all reference organs supported by HRApop operationId: supported-reference-organs tags: - hra-pop responses: '200': $ref: '#/components/responses/IdLabelsResponse' '404': $ref: '#/components/responses/ErrorMessage' '500': $ref: '#/components/responses/ErrorMessage' /hra-pop/supported-tools: get: summary: Get all tools supported by HRApop operationId: supported-tools tags: - hra-pop responses: '200': $ref: '#/components/responses/IdLabelsResponse' '404': $ref: '#/components/responses/ErrorMessage' '500': $ref: '#/components/responses/ErrorMessage' /kg/asctb-term-occurences: get: summary: Get number of ASCT+B term occurrences for a search operationId: asctb-term-occurences tags: - hra-kg parameters: - $ref: '#/components/parameters/OntologyTerms' - $ref: '#/components/parameters/CellTypeTerms' - $ref: '#/components/parameters/BiomarkerTerms' responses: '200': $ref: '#/components/responses/TermOccurences' '404': $ref: '#/components/responses/ErrorMessage' /kg/digital-objects: get: summary: List all digital objects in the HRA KG operationId: digital-objects tags: - hra-kg responses: '200': $ref: '#/components/responses/DigitalObjectsResponse' '404': $ref: '#/components/responses/ErrorMessage' '500': $ref: '#/components/responses/ErrorMessage' /kg/do-search: get: summary: Search for Digital Object PURLs operationId: do-search tags: - hra-kg parameters: - $ref: '#/components/parameters/OntologyTerms' - $ref: '#/components/parameters/CellTypeTerms' - $ref: '#/components/parameters/BiomarkerTerms' - $ref: '#/components/parameters/HraVersions' responses: '200': $ref: '#/components/responses/Strings' '404': $ref: '#/components/responses/ErrorMessage' '500': $ref: '#/components/responses/ErrorMessage' components: schemas: MinMax: title: Number Range description: | Represents a range of numbers using a minimum and maximum. Either end may be omitted to indicate an unlimited/infinite range in that direction. \`min\` should be less than or equal to \`max\` but this is not strictly enforced. type: object properties: min: type: number max: type: number SpatialSearch: title: Probing Sphere description: | Specification for a Spatial Search via Probing Sphere type: object properties: x: title: X coordinate relative to target in millimeters type: number 'y': title: Y coordinate relative to target in millimeters type: number z: title: Z coordinate relative to target in millimeters type: number radius: title: Size of the probing sphere in millimeters type: number target: title: The target spatial entity IRI type: string required: - x - 'y' - z - radius - target additionalProperties: false AggregateCount: title: Aggregated Count \\w Label type: object required: - label - count properties: label: title: Aggregate Name/Field type: string count: title: Aggregated Count oneOf: - type: number nullable: false - type: string nullable: false x-preprocessor-delete: oneOf ErrorMessage: title: Error Message type: object required: - error properties: error: title: Human readable description of the error type: string JsonLdObject: title: JSON-LD Object description: Base object for all json-ld objects. type: object required: - '@id' - '@type' additionalProperties: true properties: '@id': title: Unique Identifier type: string format: uri example: http://purl.obolibrary.org/obo/UBERON_0013702 '@type': title: Object Type description: Contains the name of object class/interface type: string example: Sample x-preprocessor-delete: - properties/@id - properties/@type OntologyTreeNode: title: Ontology Node description: A node in the ontology tree. type: object allOf: - $ref: '#/components/schemas/JsonLdObject' required: - '@type' properties: '@type': type: string enum: - OntologyTreeNode id: title: Identifier description: Unique identifier for the node. type: string format: uri label: title: Label description: Main descriptive label for the node. type: string synonymLabels: title: Synonym Labels description: Additional label for the node. type: array items: type: string parent: title: Parent Node Identifier description: Reference to the parent node. type: string format: uri children: title: Child Node Identifiers description: References to all child nodes. type: array items: type: string format: uri x-preprocessor-delete: - properties/@type OntologyTree: title: Ontology Tree description: An ontology tree. type: object required: - root - nodes properties: root: title: Root Node description: Reference to the root node. type: string format: url nodes: title: All Nodes description: A mapping of identifiers to each node object. additionalProperties: $ref: '#/components/schemas/OntologyTreeNode' SpatialEntityCommon: title: Spatial Entity C