@oneilsh/jrest

Command-line interface to axios for REST calls from JSON input on stdin.

Usage no npm install needed!

<script type="module">
  import oneilshJrest from 'https://cdn.skypack.dev/@oneilsh/jrest';
</script>

README

jrest

jrest is a small wrapper around the axios npm library for making REST calls from the command-line, formatted as JSON read on stdin. It works best when paired with the amazing jq utility for JSON slicing and dicing.

It operates like a deep map, looking for objects in the input with an axios property; when it find them it assumes the object is formatted as an axios config object for making REST calls, and replaces the object with the result of the call (or an {axiosError: ...} object if the call didn't succeed with status 200).

{"this": "is", "some": "json", "replaceme": {"axios": true, "method": "get", "url": "http://some.api"}}
  =>
{"this": "is", "some": "json", "replaceme": <DATA returned by http://some.api>}

Since axios is used under the hood, the request object can specify headers, method (POST, GET, PUT, etc.), data (for POST et al.), params, and so on.

Install

tbd

Example

For an example, let's look for genes suspected to be associated with COVID-19 (MONDO:0100096 from the Monarch Initiative API), querying the /api/bioentity/disease endpoint with some params to keep the output small; we build the query and send it to jrest, then send the result to jq for nice output formatting.

echo '{"axios": true,
       "method": "get",
       "url": "https://api.monarchinitiative.org/api/bioentity/disease/MONDO:0100096/genes",
       "params": {"unselect_evidence": true}}' |\
  jrest |\
  jq

Result (I've hidden a bunch of output fields with ... to save space, the object fields are what we're interested in):

{
  "associations": [
    {
      "id": "16a26193-cf36-46d7-a53b-2b1ab7302716",
      ...
      "object": {
        "taxon": {
          "id": "NCBITaxon:9606",
          "label": "Homo sapiens"
        },
        "id": "HGNC:79",
        "label": "ABO",
        "iri": "https://www.genenames.org/data/gene-symbol-report/#!/hgnc_id/HGNC:79",
        "category": [
          "gene"
        ]
      },
      ...
    },
    {
      "id": "f1e30951-566a-4c05-9b63-f4004a1f3b6e",
      ...
      "object": {
        "taxon": {
          "id": "NCBITaxon:9606",
          "label": "Homo sapiens"
        },
        "id": "HGNC:6741",
        "label": "LZTFL1",
        "iri": "https://www.genenames.org/data/gene-symbol-report/#!/hgnc_id/HGNC:6741",
        "category": [
          "gene"
        ]
      },
      ...
    }
  ],
  "compact_associations": null,
  ...
}

We can modify the jq at the end to clean it up:

echo '{"axios": true,
       "method": "get",
       "url": "https://api.monarchinitiative.org/api/bioentity/disease/MONDO:0100096/genes",
       "params": {"unselect_evidence": true}}' |\
  jrest |\
  jq '.associations[] | {gene: .object.id, label: .object.label}'

Result:

{
  "gene": "HGNC:79",
  "label": "ABO"
}
{
  "gene": "HGNC:6741",
  "label": "LZTFL1"
}

Instead of just using jq to just filter the output, let's use it to format a set of embedded REST queries, identifying the phenotypes known to be associated with each gene. We wrap the whole expression in [] to ensure a single valid JSON object is output (an array), rather than the stream of objects as above. (jq syntax is complex; this tutorial at The Programming Historian is pretty good. The Programming Historian is awesome all around.)

echo '{"axios": true,
       "method": "get",
       "url": "https://api.monarchinitiative.org/api/bioentity/disease/MONDO:0100096/genes",
       "params": {"unselect_evidence": true}}' |\
  jrest |\
  jq '[.associations[] | {
                          gene: .object.id,
                          label: .object.label,
                          phenotypes: {
                            axios: true,
                            url: "https://api.monarchinitiative.org/api/bioentity/gene/\(.object.id)/phenotypes",
                            params: {unselect_evidence: true}
                          }
                        }]'

Resulting in JSON with embedded requests:

[
  {
    "gene": "HGNC:79",
    "label": "ABO",
    "phenotypes": {
      "axios": true,
      "url": "https://api.monarchinitiative.org/api/bioentity/gene/HGNC:79/phenotypes",
      "params": {
        "unselect_evidence": true
      }
    }
  },
  {
    "gene": "HGNC:6741",
    "label": "LZTFL1",
    "phenotypes": {
      "axios": true,
      "url": "https://api.monarchinitiative.org/api/bioentity/gene/HGNC:6741/phenotypes",
      "params": {
        "unselect_evidence": true
      }
    }
  }
]

And we can send that to jrest | jq for converting the internal requests and formatting. Here are just the first few lines of the very long output with some output hidded behind ...:

[
  {
    "gene": "HGNC:79",
    "label": "ABO",
    "phenotypes": {
      "associations": [
        {
          ...
          "object": {
            "taxon": {
              "id": null,
              "label": null
            },
            "id": "EFO:0004611",
            "label": "low density lipoprotein cholesterol measurement",
            "iri": "http://www.ebi.ac.uk/efo/EFO_0004611",
            "category": [
              "phenotype"
            ]
          },
          "relation": {
            "inverse": false,
            "id": "RO:0003304",
            "label": "contributes to condition",
            "iri": "http://purl.obolibrary.org/obo/RO_0003304",
            "category": null
          },
          ...

Each request object has been replaced with the result of the call; now we have a list of gene objects, each with a phenotypes sub-object, containing a list of associations - each association has an object (the phenotype) and a relation type (e.g. "contributes to condition"). Let's pull just that info with jq; here's the full pipeline:

echo '{"axios": true,
       "method": "get",
       "url": "https://api.monarchinitiative.org/api/bioentity/disease/MONDO:0100096/genes",
       "params": {"unselect_evidence": true}}' |\
  jrest |\
  jq '[.associations[] | {
                          gene: .object.id,
                          label: .object.label,
                          phenotypes: {
                            axios: true,
                            url: "https://api.monarchinitiative.org/api/bioentity/gene/\(.object.id)/phenotypes",
                            params: {unselect_evidence: true}
                          }
                        }]' |\
  jrest |\
  jq '[ .[] |
        {gene: .gene,
         label: .label,
         phenotypes: .phenotypes.associations |
         map_values({
           relationship: .relation.label,
           phenotype: .object.label,
           phenotypeId: .object.id}
         )}
      ]'

And the first few lines of result:

[
  {
    "gene": "HGNC:79",
    "label": "ABO",
    "phenotypes": [
      {
        "relationship": "contributes to condition",
        "phenotype": "low density lipoprotein cholesterol measurement",
        "phenotypeId": "EFO:0004611"
      },
      {
        "relationship": "contributes to condition",
        "phenotype": "intraocular pressure measurement",
        "phenotypeId": "EFO:0004695"
      },
      {
        "relationship": "contributes to condition",
        "phenotype": "von Willebrand factor measurement",
        "phenotypeId": "EFO:0004629"
      },