Skip to content

GraphQL interface for NASA's Common Metadata Repository (CMR).

License

Notifications You must be signed in to change notification settings

nasa/cmr-graphql

Repository files navigation

serverless Build Status codecov

About

CMR-GraphQL is an API developed by NASA EOSDIS to search against Common Metadata Repository (CMR) concept metadata using GraphQL.

License

Copyright © 2007-2023 United States Government as represented by the Administrator of the National Aeronautics and Space Administration. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Application Installation

Before running the application you'll want to ensure that all necessary packages are installed by running:

npm install

You will also need Python3.9+ (Ideally installed in a virtual environment) to query the collection generateVariableDrafts field. Run the following to ensure proper operation of this query.

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

CMR-GraphQL uses a few environment variables for configuring runtime options:

Variable Name Default Description
CMR_ROOT_URL URL to ping when retrieving metadata from CMR e.g. https://cmr.earthdata.nasa.gov
MMT_ROOT_URL URL to ping when retrieving metadata from MMT e.g. https://mmt.earthdata.nasa.gov
DRAFT_MMT_ROOT_URL URL to ping when retrieving draft metadata from Draft MMT e.g. https://draftmmt.earthdata.nasa.gov
LAMBDA_TIMEOUT 30 Number of seconds to set the Lambda timeout to.
EDL_KEY_ID, EDL_JWK, EDL_CLIENT_ID For facilitating EDL connection -- obtain these from a dev

Serverless Framework

The local development environment for the static assets can be started by executing the command below in the project root directory:

serverless offline

This will run the application at http://localhost:3003/dev/api

Optional Headers

CMR-GraphQL supports a few optional headers that can be used for various features and debugging purposes.

Authentication

CMR-GraphQL accepts Earthdata Login (EDL) tokens via the Authorization header. If provided, this token will be provided to any CMR call made as part of the query. CMR-GraphQL will return errors if the token is invalid or expired in which case the client will need to handle the response accordingly.

Identification

In order for us to best provide debugging, statistics, and to inform us of future feature work CMR-GraphQL accepts the Client-Id header that allows all clients to identifiy themselves. If provided, this value is passed to any CMR call made as part of the query and is used to determine usage patterns, helps debug issues by filtering down logs, and also will help determine priority of feature requests.

Request Tracking

Logging is key to debugging, and to ensure that we can provide the best support to users' when issues may arise, CMR-GraphQL supports the X-Request-Id header. This header will be passed to any CMR call made as part of the query which will be prepended to any CMR logs that are generated as a result of a query. This value is also used in CMR-GraphQL logs so that we can associate our logs, CMR logs, and any logs you may have if debugging becomes necessary. We recommend setting this value with all requests in the event it is needed, it cannot be added retroactively.

Queries

When querying for multiple items there are three high level parameters that can be provided, count, cursor, facets and items.

Count

count will hold the value returned from the CMR header CMR-Hits for the respective concept type providing the total number of results (ignoring the current page size).

Cursor

cursor tells CMR-GraphQL that you'd like to fetch the search after identifier out of the response header with the intent of harvesting data (or fetching multiple pages of results). To take advantage of the cursor you can then include it in subsequent queries until no data is returned.

First Request
{
  concept {
    count
    cursor
    items {
      conceptId
    }
  }
}

Which will return something similar to the following:

{
  "data": {
    "concept": {
      "count": 2483,
      "cursor": "eyJqc29uIjoiLTQ2OTA0MDY3NyJ9=",
      "items": [
        {
          "conceptId": "C1000000001-EXAMPLE"
        }
      ]
    }
  }
}
Subsequent Requests
{
  concept(cursor: "eyJqc29uIjoiLTQ2OTA0MDY3NyJ9=") {
    count
    cursor
    items {
      conceptId
    }
  }
}

A couple of things to keep in mind when using a cursor

  1. Subsequent queries require that the same search parameters are sent to ensure that the same query is performed.
  2. Subsequent queries must be made sequentially (as of August 21, 2020) as the version of Elastic Search CMR uses does not support parallel queries using the same cursor value.

When all results have been returned, the response will be an empty array and the cursor will return a value of null.

Facets

facets will return the data provided by CMR determined by which facets you requested in your query. In order for this data to be provided by CMR you will need to include the includeFacets parameter in your query. For more information regarding facets refer to the CMR documentation. See below for a basic example:

{
  collections(
    includeFacets:"v2"
  ) {
    facets
    items {
      conceptId
    }
  }
}
Items

items is where you will provide the columns you'd like returned from CMR.

{
  concept {
    count
    items {
      conceptId
    }
  }
}

If you're querying single objects count is not available and therefore items isn't necessary -- you can simply list the columns you'd like returned from CMR as a direct child of your query.

{
  concept {
    conceptId
  }
}

Note that the response you get will match the structure of your query, meaning that in the event you've requested data from a list query you'll receive the results in an items array whereas with a single query request you will not.

Usage

Currently, this API supports the following functionality within NASA's Earthdata Ecosystem.

Concepts (Objects)

Drafts of concepts

Associations between the supported concepts

Granules are not supported in this implementation, associations cannot be made between granules and any other concept

Access controls and permissions pertaining to the supported concepts

Collections

A subset of supported arguments will automatically be sent to immediately adjacent granule queries, for a list of those arguments see Passthrough Arguments.

For all supported arguments and columns, see the schema.

Collection Queries
Query for a single collection
{
  collection(conceptId:"C1000000001-EXAMPLE") {
    title
    granules {
      count
      items {
        conceptId
        title
      }
    }
    services {
      count
      items {
        conceptId
        type
      }
    }
    tools {
      count
      items {
        conceptId
        supportedBrowsers
      }
    }
    variables {
      count
      items {
        conceptId
        name
      }
    }
  }
}
Query for multiple collections
{
  collections(
    conceptId:["C1000000001-EXAMPLE", "C1000000002-EXAMPLE"]
  ) {
    count
    items {
      title
      granules {
        count
        title
      }
      services {
        count
        items {
          conceptId
          type
        }
      }
      tools {
        count
        items {
          conceptId
          supportedBrowsers
        }
      }
      variables {
        count
        items {
          conceptId
          name
        }
      }
    }
  }
}
Restore a previous revision of a collection
mutation RestoreCollectionRevision(
  $conceptId: String!
  $revisionId: String!
) {
  restoreCollectionRevision(
    conceptId: $conceptId,
    revisionId: $revisionId
  ) {
    revisionId
    conceptId
  }
}

Granules

For performance reasons, CMR requires that a collection be provided in order to query granules. While CMR supports multiple aliases for the collection CMR-GraphQL requires that it be called collectionConceptId; if this is not provided CMR will return an error. We don't enforce this in the schema because you can also use conceptId if you're looking for specific granules and schemas don't offer a means of offering conditional validations.

Passthrough Arguments

A subset of the supported arguments for Collections will be passed through to the granule query by default. Those arguments are as follows:

  • boundingBox
  • circle
  • point
  • polygon
  • temporal

For all supported arguments and columns, see the schema.

Granule Queries
Query for a single granule
{
  granule(conceptId:"G1000000001-EXAMPLE") {
    conceptId
    title
  }
}
Query for multiple granules
{
  granules(collectionConceptId:"G1000000001-EXAMPLE") {
    items {
      conceptId
      title
    }
  }
}

Services

For all supported arguments and columns, see the schema.

Service Queries
Query for a single service
{
  service(conceptId:"S1000000001-EXAMPLE") {
    conceptId
    type
  }
}
Query for multiple services
{
  services {
    count
    items {
      conceptId
      type
      description
    }
  }
}
Restore a previous revision of a service
mutation RestoreServiceRevision(
  $conceptId: String!
  $revisionId: String!
) {
  restoreServiceRevision(
    conceptId: $conceptId,
    revisionId: $revisionId
  ) {
    revisionId
    conceptId
  }
}

Subscriptions

For all supported arguments and columns, see the schema.

Subscription Queries
Query for a single subscription
{
  subscription(conceptId:"SUB1000000001-EXAMPLE") {
    conceptId
    nativeId
    query
  }
}

To also retrieve details pertaining to the associated collection:

{
  subscription(conceptId:"SUB1000000001-EXAMPLE") {
    conceptId
    nativeId
    query
    collection {
      title
    }
  }
}
Query for multiple subscriptions
{
  subscriptions {
    count
    items {
      conceptId
      query
    }
  }
}

To also retrieve details pertaining to the associated collections:

{
  subscriptions {
    count
    items {
      conceptId
      query
      collection {
        title
      }
    }
  }
}
Mutations
Creating a Subscription

If no nativeId is provided, CMR-GraphQL will generate a GUID and supply it.

mutation {
  createSubscription(
    collectionConceptId: "C1000000001-EXAMPLE"
    name: "Example Subscription"
    query: "polygon=-18,-78,-13,-74,-16,-73,-22,-77,-18,-78"
    subscriberId: "username"
  ) {
    conceptId
    revisionId
  }
}

To set the nativeId to a desired value, simply provide it as an argument and it will be used.

mutation {
  createSubscription(
    collectionConceptId: "C1000000001-EXAMPLE"
    name: "Example Subscription"
    nativeId: "SUPPLIED-NATIVE-ID"
    query: "polygon=-18,-78,-13,-74,-16,-73,-22,-77,-18,-78"
    subscriberId: "username"
  ) {
    conceptId
    revisionId
  }
}
Updating a Subscription

CMR defines a record as unique based on the nativeId, in order to update a subscription supply a nativeId that belongs an existing record.

mutation {
  updateSubscription(
    collectionConceptId: "C1000000001-EXAMPLE"
    name: "Example Subscription"
    nativeId: "EXISTING-NATIVE-ID"
    query: "polygon=-18,-78,-13,-74,-16,-73,-22,-77,-18,-78"
    subscriberId: "username"
  ) {
    conceptId
    revisionId
  }
}

NOTES:

  • Due to the way in which CMR works, createSubscription and updateSubscription will operate identically when supplying an existing nativeId however, this may not always be the case so we encourage you to use the explicit updateSubscription mutation noted below.
Deleting a Subscription

CMR defines a record as unique based on the nativeId, in order to delete a subscription supply a nativeId that belongs an existing record.

mutation {
  deleteSubscription(
    conceptId: "SUB1000000001-EXAMPLE"
    nativeId: "EXISTING-NATIVE-ID"
  ) {
    conceptId
    revisionId
  }
}

Tools

For all supported arguments and columns, see the schema.

Tool Queries
Query for a single tool
{
  tool(conceptId:"T1000000001-EXAMPLE") {
    conceptId
    scienceKeywords
    supportedBrowsers
  }
}
Query for multiple tools
{
  tools {
    count
    items {
      conceptId
      toolKeywords
      supportedBrowsers
    }
  }
}
Deleting a Tool
mutation DeleteTool(
  $providerId: String!
  $nativeId: String!
) {
  deleteTool(
    providerId: $providerId
    nativeId: $nativeId
  ) {
    conceptId
    revisionId
  }
}

Variables:

{
  "providerId": "EXAMPLE",
  "nativeId": "tool-1"
}
Restore a previous revision of a tool
mutation RestoreToolRevision(
  $conceptId: String!
  $revisionId: String!
) {
  restoreToolRevision(
    conceptId: $conceptId,
    revisionId: $revisionId
  ) {
    revisionId
    conceptId
  }
}

Groups

For all supported arguments and columns, see the schema.

Group Queries
Query for a single group

Query:

query Group (
  $params: GroupInput
) {
  group (
    params: $params
  ) {
    id
    name
  }
}

Variables:

{
  "params": {
    "id": "EXAMPLE"
  }
}
Query for multiple groups

Query:

query Groups (
  $params: GroupsInput
) {
  groups (
    params: $params
  ) {
    count
    items {
      id
      name
    }
  }
}

Variables:

{
  "params": {
    "tags": ["EXAMPLE"],
    "name": "group-1"
  }
}
Group Mutations
Creating a group

Query:

mutation CreateGroup (
  $name: String!
  $tag: String
  $description: String
) {
  createGroup (
    name: $name
    tag: $tag
    description: $description
  ) {
    id
    name
  }
}

Variables:

{
  "name": "Test Group",
  "tag": "EXAMPLE",
  "description": "Test group"
}
Updating a group

Query:

mutation UpdateGroup (
  $id: String!
  $name: String
) {
  updateGroup (
    id: $id
    name: $name
  ) {
    id
    name
  }
}

Variables:

{
  "id": "1234-abcd-5678-efgh",
  "name": "New Group Name"
}
Deleting a group

Query:

mutation DeleteGroup (
  $id: String!
) {
  deleteGroup (
    id: $id
  )
}

Variables:

{
  "id": "1234-abcd-5678-efgh"
}

Variables

For all supported arguments and columns, see the schema.

Variable Queries
Query for a single variable
{
  variable(conceptId:"V1000000001-EXAMPLE") {
    conceptId
    scienceKeywords
    variableType
  }
}
Query for multiple variables
{
  variables {
    count
    items {
      conceptId
      scienceKeywords
      variableType
    }
  }
}
Restore a previous revision of a variable
mutation RestoreVariableRevision(
  $conceptId: String!
  $revisionId: String!
) {
  restoreVariableRevision(
    conceptId: $conceptId,
    revisionId: $revisionId
  ) {
    revisionId
    conceptId
  }
}

Grids

For all supported arguments and columns, see the schema.

Grid Queries
Query for a singe grid
{
  grid(conceptId:"GRD1000000001-EXAMPLE") {
    conceptId
    title
  }
}
Query for multiple grids
{
  grids {
    items {
      conceptId
      name
      longName
      description
    }
  }
}

Order Options

For all supported arguments and columns, see the schema.

Order Option Queries
Query for a single order option
{
  query ($params: OrderOptionInput) {
    orderOption(params: $params) {
      associationDetails
      conceptId
      id
      name
      nativeId
      description
      form
    }
  }
}

Variables:

{
  "params": {
    "conceptId": "OO1000000001-EXAMPLE"
  }
}
Query for multiple order options
{
  orderOptions {
    count
    items {
      conceptId
      name
      nativeId
      id
      description
      scope
      form
      sortKey
    }
  }
}
Order Option Mutations
Creating an order option

Query:

mutation CreateOrderOption($description: String!, $name: String!, $providerId:
String!, $form: String!, $nativeId: String) {
  createOrderOption(description: $description, name: $name, providerId: $providerId, form: $form, nativeId: $nativeId) {
    conceptId
    revisionId
  }
}

Variables:

{
  "description": "This is a description",
  "form": "This is the form",
  "name": "This is another new name",
  "nativeId": "test-native-id-2",
  "providerId": "MMT_1",
}
Updating an order option

Query:

mutation UpdateOrderOption($providerId: String!, $description: String!, $form: String!, $nativeId: String!, $name: String!) {
  updateOrderOption(providerId: $providerId, description: $description, form: $form, nativeId: $nativeId, name: $name) {
    conceptId
    revisionId
  }
}

Variables:

{
  "description": "This is a new description",
  "form": "something new",
  "name": "this is a name",
  "nativeId": "collection1",
  "providerId": "MMT_1",
}
Deleting an order option

Query:

mutation DeleteOrderOption($nativeId: String!, $providerId: String!) {
  deleteOrderOption(nativeId: $nativeId, providerId: $providerId) {
    conceptId
    revisionId
  }
}

Variables:

{
  "nativeId": "b4876280-c7ff-41ab-b08f-af91369fe464",
  "providerId": "MMT_1"
}

Data Quality Summaries

For all supported arguments and columns, see the schema.

Data Quality Summary Queries
Query for a single data quality summary
{
  query ($params: DataQualitySummaryInput) {
    dataQualitySummary(params: $params) {
      associationDetails
      conceptId
      id
      name
      nativeId
      summary
    }
  }
}

Variables:

{
  "params": {
    "conceptId": "DQS1000000001-EXAMPLE"
  }
}
Query for multiple data quality summaries
{
  dataQualitySummaries {
    items {
      conceptId
      associationDetails
      name
      summary
      id
    }
  }
}

Related Collections

For all supported arguments and columns, see the schema.

CMR-GraphQL queries CMR's GraphDB in order to find related collections on supported fields. These related collections can be returned as part of the Collection type response.

relatedCollections will return related collections, with those collections that share the most relationships first

We use GraphQL interfaces in order to return the different relationship types as siblings in the return object.

Related Collection Queries
{
  conceptId
  relatedCollections (
    limit: 1
  ) {
    count
    items {
      id
      title
      doi
      relationships {
        relationshipType
        ... on GraphDbProject {
          name
        }
        ... on GraphDbPlatformInstrument {
          platform
          instrument
        }
        ... on GraphDbRelatedUrl {
          url
          description
          type
          subtype
        }
      }
    }
  }
}
Response
{
  "conceptId": "C1000000001-EXAMPLE",
  "relatedCollections": {
    "count": 18,
    "items": [
      {
        "id": "C2000000001-EXAMPLE",
        "title": "Infrared Global Geostationary Composite Demo 4",
        "doi": "10.5067/GHRC/AMSU-A/DATA303",
        "relationships": [
          {
            "relationshipType": "platformInstrument",
            "platform": "MTSAT-1R",
            "instrument": "VISSR"
          },
          {
            "relationshipType": "relatedUrl",
            "url": "https://doi.org/10.5067/9LNYIYOBNBR5",
            "description": "Another Related URL for Demo",
            "type": "VIEW RELATED INFORMATION",
            "subtype": "DATA RECIPE"
          },
          {
            "relationshipType": "project",
            "name": "Project2"
          }
        ]
      }
    ]
  }
}

Generate Collection Variable Drafts

For all supported arguments and columns, see the schema.

CMR-GraphQL queries an earthdata-varinfo lambda in order to generate collection variable drafts. These generated variable drafts can be returned as part of the Collection type response.

generateVariableDrafts will return collection generated variable drafts, using the earthdata-varinfo project(https://github.com/nasa/earthdata-varinfo)

Collection Variable Draft Queries
{
  query Collection($params: CollectionInput) {
    collection(params: $params) {
      conceptId
      generateVariableDrafts {
        count
        items {
          dataType
          definition
          dimensions
          longName
          name
          standardName
          units
          metadataSpecification
        }
      }
    }
  }
}

Variables:

{
  "params": {
    "conceptId": "C1000000001-EXAMPLE"
  }
}
Response
  {
  "data": {
    "collection": {
      "conceptId": "C1000000001-EXAMPLE",
      "generateVariableDrafts": {
        "count": 16,
        "items": [
          {
            "dataType": "int32",
            "definition": "Grid/time",
            "dimensions": [
              {
                "Name": "Grid/time",
                "Size": 1,
                "Type": "TIME_DIMENSION"
              }
            ],
            "longName": "Grid/time",
            "name": "Grid/time",
            "standardName": "time",
            "units": "seconds since 1970-01-01 00:00:00 UTC",
            "metadataSpecification": {
              "URL": "https://cdn.earthdata.nasa.gov/umm/variable/v1.8.2",
              "Name": "UMM-Var",
              "Version": "1.8.2"
            }
          }
        ]
      }
    }
  }
}

Publish Generated Collection Variable Drafts

For all supported arguments and columns, see the schema.

CMR-GraphQL queries an earthdata-varinfo lambda in order to generate and publish collection variable drafts. The resulting variables can be returned as part of the Variable type response.

publishVariableDrafts will return collection generated variables, using the earthdata-varinfo project(https://github.com/nasa/earthdata-varinfo)

Generate Collection Variable Drafts Mutation
mutation PublishGeneratedVariables($conceptId: String!) {
  publishGeneratedVariables(conceptId: $conceptId) {
    count
    items {
      conceptId
      dataType
      definition
      dimensions
      longName
      name
      standardName
      units
      metadataSpecification
    }
  }
}

Variables:

{
  "conceptId": "C1000000001-EXAMPLE"
}
Response
  {
  "data": {
    "publishGeneratedVariables": {
      "count": 1,
      "items": [
        {
          "conceptId": "V1000000001-EXAMPLE",
          "dataType": "int32",
          "definition": "Grid/time",
          "dimensions": [
            {
              "Name": "Grid/time",
              "Size": 1,
              "Type": "TIME_DIMENSION"
            }
          ],
          "longName": "Grid/time",
          "name": "Grid/time",
          "standardName": "time",
          "units": "seconds since 1970-01-01 00:00:00 UTC",
          "metadataSpecification": {
            "URL": "https://cdn.earthdata.nasa.gov/umm/variable/v1.8.2",
            "Name": "UMM-Var",
            "Version": "1.8.2"
          }
        }
      ]
    }
  }
}

Drafts

For all supported arguments and columns, see the schema.

The Draft type utilizes the PreviewMetadata union type, which means you can return any of the types supported by the union in the previewMetadata return field. You need to ensure that your conceptType parameter matches the previewMetadata type. In the examples below notice the conceptType parameter is Tool, and the syntax in the request of ... on Tool {.

Draft Queries
Query for a single draft
query Draft($params: DraftInput) {
  draft(params: $params) {
    conceptId
    conceptType
    deleted
    name
    nativeId
    providerId
    revisionDate
    revisionId
    ummMetadata
    previewMetadata {
      ... on Tool {
        name
        longName
        collections {
          count
        }
      }
    }
  }
}

Variables:

{
  "params": {
    "conceptId": "TD1000000001-EXAMPLE",
    "conceptType": "Tool"
  }
}
Query for multiple drafts
query Drafts($params: DraftsInput) {
  drafts(params: $params) {
    count
    items {
      conceptId
      conceptType
      deleted
      name
      nativeId
      providerId
      revisionDate
      revisionId
      ummMetadata
      previewMetadata {
        ... on Tool {
          name
          longName
          collections {
            count
          }
        }
      }
    }
  }
}

Variables:

{
  "params": {
    "conceptType": "Tool"
  }
}
Ingesting a draft
mutation IngestDraft(
  $conceptType: DraftConceptType!
  $metadata: JSON!
  $nativeId: String!
  $providerId: String!
  $ummVersion: String!
) {
  ingestDraft(
    conceptType: $conceptType
    metadata: $metadata
    nativeId: $nativeId
    providerId: $providerId
    ummVersion: $ummVersion
  ) {
    conceptId
    revisionId
    warnings
    existingErrors
  }
}

Variables:

{
  "conceptType": "Tool",
  "metadata": {
    "Name": "Test Tool",
    "MetadataSpecification": {
      "URL": "https://cdn.earthdata.nasa.gov/umm/tool/v1.2.0",
      "Name": "UMM-T",
      "Version": "1.2.0"
    }
  },
  "nativeId": "sampleNativeId",
  "providerId": "EXAMPLE",
  "ummVersion": "1.0.0"
}
Deleting a draft
mutation DeleteDraft(
  $conceptType: DraftConceptType!
  $nativeId: String!
  $providerId: String!
) {
  deleteDraft(
    conceptType: $conceptType
    nativeId: $nativeId
    providerId: $providerId
  ) {
    conceptId
    revisionId
    warnings
    existingErrors
  }
}

Variables:

{
  "conceptType": "Tool",
  "nativeId": "tool-3",
  "providerId": "EXAMPLE"
}
Publishing a draft
mutation PublishDraft(
  $draftConceptId: String!
  $nativeId: String!
  $ummVersion: String!
) {
  publishDraft(
    draftConceptId: $draftConceptId
    nativeId: $nativeId
    ummVersion: $ummVersion
  ) {
    conceptId
    revisionId
    warnings
    existingErrors
  }
}

Variables:

{
  "draftConceptId": "TD1000000001-EXAMPLE",
  "nativeId": "tool-1",
  "ummVersion": "1.2.0"
}

Associations

For all supported arguments and columns, see the schema.

Associations are supported between any of the following concepts, and can be made to any/from any of the concepts

  • Tool
  • Variable
  • Service
  • Collections
  • Order Options
Association Mutations
Associating a concept to another concept
mutation CreateAssociation(
  $conceptId: String!
  $associatedConceptId: String
  ) {
  createAssociation(
    conceptId: $conceptId,
    associatedConceptId: $associatedConceptId
  ) {
    associatedConceptId
    conceptId
    revisionId
  }
}

Variables:

{
  "conceptId": "C1000000001-EXAMPLE",
  "associatedConceptId": "TL12000000-EXAMPLE"
}
Associating a concept to multiple other concepts
mutation CreateAssociation(
  $conceptId: String!,
  $associatedConceptIds: [String]
  ) {
  createAssociation(
    conceptId: $conceptId,
    associatedConceptIds: $associatedConceptIds
  ) {
    associatedConceptId
    conceptId
    revisionId
  }
}

Variables:

{
  "conceptId": "C1000000001-EXAMPLE",
  "associatedConceptIds": ["TL12000000-EXAMPLE", "TL12000001-EXAMPLE"]
}
Associating a concept to other concepts with data
mutation CreateAssociation(
  $conceptId: String!,
  $associatedConceptData: JSON
  ) {
  createAssociation(
    conceptId: $conceptId,
    associatedConceptData: $associatedConceptData
  ) {
    associatedConceptId
    conceptId
    revisionId
  }
}

Variables:

{
  "conceptId": "C1000000001-EXAMPLE",
  "associatedConceptData": [{
    "conceptId": "TL12000000-EXAMPLE",
    "data": {
      "namespace": {
        "data": true
      }
    }
  }, {
    "conceptId": "TL12000001-EXAMPLE",
    "data": {
      "namespace": {
        "data": false
      }
    }
  }]
}
Deleting A Single Association
mutation DeleteAssociation(
  $conceptId: String!,
  $associatedConceptId: String
) {
  deleteAssociation(
    conceptId: $conceptId,
    associatedConceptId: $associatedConceptId
  ) {
    revisionId
    conceptId
    associatedConceptId
  }
}

Variables:

{
  "conceptId": "C1000000001-EXAMPLE",
  "associatedConceptId": "TL12000000-EXAMPLE"
}
Deleting Multiple Associations
mutation DeleteAssociation(
  $conceptId: String!,
  $associatedConceptId: String
) {
  deleteAssociation(
    conceptId: $conceptId,
    associatedConceptId: $associatedConceptId
  ) {
    revisionId
    conceptId
    associatedConceptId
  }
}

Variables:

{
  "conceptId": "TL12000000-EXAMPLE",
  "conceptType": "Tool",
  "collectionConceptIds": [
    {
      "conceptId": "C1000000001-EXAMPLE",
      "associatedConceptIds": ["TL12000000-EXAMPLE", "TL12000001-EXAMPLE"]
    }
  ]
}

ACLs

For all supported arguments and columns, see the schema.

ACL Queries
Query for a single ACL
query Acl($conceptId: String) {
  acl(conceptId: $conceptId) {
    name
    groupPermissions
  }
}

Variables:

{
  "conceptId": "ACL1000000001-EXAMPLE"
}
ACL Query Response
{
  "data": {
    "acl": {
      "groupPermissions": [
        {
          "group_id": "ACL1000000001-EXAMPLE",
          "permissions": [
            "read"
          ]
        },
        {
          "group_id": "ACL1000000002-EXAMPLE",
          "permissions": [
            "read"
          ]
        }
      ],
      "providerIdentity": {
        "target": "PROVIDER_CONTEXT",
        "provider_id": "EXAMPLE"
      }
    }
  }
}
Query for multiple ACLs
query Acls($params: AclsInput) {
  acls(params: $params) {
    items {
      systemIdentity
      providerIdentity
    }
  }
}

Variables:

{
  "params": {
    "permittedUser": "typical",
    "target": "PROVIDER_CONTEXT"
  }
}
ACLs Query Response
{
  "data": {
    "acls": {
      "items": [
        {
          "groupPermissions": [
            {
              "group_id": "ACL1000000001-EXAMPLE",
              "permissions": [
                "read"
              ]
            },
            {
              "group_id": "ACL1000000002-EXAMPLE",
              "permissions": [
                "read"
              ]
            }
          ],
          "providerIdentity": {
            "target": "PROVIDER_CONTEXT",
            "provider_id": "EXAMPLE"
          }
        }
      ]
    }
  }
}
ACL Mutations
Creating an ACL
mutation CreateAcl(
  $groupPermissions: JSON
    $catalogItemIdentity: JSON
  ) {
  createAcl(
    groupPermissions: $groupPermissions
    catalogItemIdentity: $catalogItemIdentity
  ) {
    revisionId
    conceptId
  }
}
Updating an ACL
mutation UpdateAcl(
  $conceptId: String!
    $catalogItemIdentity: JSON
    $groupPermissions: JSON
) {
  updateAcl(
    conceptId: $conceptId
    catalogItemIdentity: $catalogItemIdentity
    groupPermissions: $groupPermissions
  ) {
  revisionId
  conceptId
  }
}

Variables:

{
  "conceptId": "ACL1000000001-EXAMPLE",
  "catalogItemIdentity": {
        "name": "ACL Example Renamed",
        "provider_id": "EXAMPLE",
        "granule_applicable": true
    },
    "groupPermissions": [{
        "user_type": "guest",
        "permissions": ["read"]
    }
  ]
}
Deleting an ACL
mutation DeleteAcl($conceptId: String!) {
  deleteAcl(conceptId: $conceptId) {
    conceptId
    revisionId
  }
}

Variables:

{
  "conceptId": "ACL1000000001-EXAMPLE"
}

Permissions

Searching by Concept ID
query GetPermissions($params: PermissionsInput) {
  permissions(params: $params) {
    count
    items {
      conceptId
      permissions
    }
  }
}

Variables:

{
  "params": {
    "userType": "registered",
    "conceptId": "C1000000001-EXAMPLE"
  }
}
Searching by System Object
query GetPermissions($params: PermissionsInput) {
  permissions(params: $params) {
    count
    items {
      systemObject
      permissions
    }
  }
}

Variables:

{
  "params": {
    "userType": "registered",
    "systemObject": "USER"
  }
}
Searching by Target & Provider
query GetPermissions($params: PermissionsInput) {
  permissions(params: $params) {
    count
    items {
      target
      permissions
    }
  }
}

Variables:

{
  "params": {
    "userType": "registered",
    "target": "GROUP",
    "provider": "EXAMPLE",
  }
}

Local graph database

Normally running GraphQl with serverless offline will utilize the (cmr.earthdata.nasa.gov/graphdb) endpoint, to query against related collections and duplicate collections in the graph database. To send queries to a locally running graph database, we can use a docker gremlin-server that exposes an HTTP endpoint. This is launched by running

docker run -it -p 8182:8182 tinkerpop/gremlin-server conf gremlin-server-rest-modern.yaml

as well as altering the gremlinPath in (src/utils/cmrGraphDb.js) to the localhost address the gremlin server is running on.

We may add data to this local graph database with http POST requests to the gremlin-server.