API Specifications

Versions

OpenAPI is used to describe the endpoints and the format of the objects to exchange on the wire, the specifications are shared below.

  • The current (i.e., last) version of the SKG-IF OpenAPI specifications is available at https://w3id.org/skg-if/api/skg-if-openapi.yaml.
  • One can access the OpenAPI specifications of all (current and previous) versions by using a version number in the w3id.org URL, following this pattern: https://w3id.org/skg-if/api/<X.Y.Z>/skg-if-openapi.yaml.

The SKG-IF OpenAPI version, present in the YAML, is independent from the SKG-IF Data model version.

Please also refer to the SKG-IF OpenAPI Implementer documentation. You will find detailed information to validate your API implementation.

Versions history

SKG-IF OpenAPI SKG-IF OpenAPI YAML SKG-IF compatible data model
1.0.0 (Current) https://w3id.org/skg-if/api/skg-if-openapi.yaml 1.1.0

Current context

openapi: 3.1.0
info:
  version: 1.0.0
  title: SKG-IF OpenAPI - compatible with SKG-IF Data Model 1.1.0

  ...
   "@context":
    "https://w3id.org/skg-if/context/1.1.0/skg-if.json", // Fixed SKG-IF data model context
    "https://w3id.org/skg-if/context/1.0.0/skg-if-api.json", // Fixed SKG-IF API context
    {
      "@base": "https://w3id.org/skg-if/sandbox/acme/"
    }
  ...

Make sure your server JSON-LD output implementation is using the same context JSON URLs, refer to paragraph below to define your @base.

OpenAPI viewers

You can also visualize the OpenAPI specifications with standard tools like :

Define your @base

@base is a default prefix domain fallback for all identifiers not defined as URLs in the @graph A local_identifier value, when not starting with “http”, is interpreted by concatenation to the @base.

For the local_identifier domain (your @base), you have a few options for the ACME organisation.

  • Option 1 : Define a w3id.org domain ex: https://w3id.org/acme/ . You can set up w3id.org to redirect to your catalogue. ex: https://w3id.org/acme/prod-1 => https://www.acme.com/product-catalogue/prod-1. This approach is a flexible way to define PIDs for your entities.
  • Option 2 : Use a graph dedicated domain you already have ex: https://www.acme.com/graph/. Make sure your URL entities resolve, it is a best practice.
  • Option 3 : If you mint DOIs for your main entities you expose (typically the research products), you can use the DOI itself as local_identifier, always as a full URL in the JSON-LD output. You won’t have to define a specific @base. In this case if you have on-the-fly ids that don’t have to resolve ( for specific entities like persons ), you can rely on a sandbox @base for them ( https://w3id.org/skg-if/sandbox/acme/ ).
  • Option 4 : Use https://w3id.org/skg-if/sandbox/acme/ for all entities. We don’t recommend it for prod because it does not resolve anywhere ( related to your ACME organisation )

Make sure that you generate distinct URLs ids for person, product… They should not conflict.

Endpoints and JSON-LD output

  • The SKG-IF OpenAPI defines 2 types of endpoints
    • Get Entity by Id
    • Get List of Entity
  • The SKG-IF OpenAPI endpoints outputs are JSON-LD and compatible with the SKG-IF data model
  • The @graph array contains entities, identified by their local_identifier, each entity may have relation to other entities also identified by their local_identifier.
  • From a client perspective, if the sub entity is not embedded with its fields, you may need to perform sub queries to access these fields.
  • The JSON-LD output contains a meta section SHOULD provide you API links for each entity, identified by its local_identifier. As a client you are not supposed to guess the API URL from the local_identifier format, there is no standard for the API domain prefix, each implementer is free to have a domain for its local_identifier and another one for its API (It is even recommended).

Get Product by Id : https://acme.com/skg-if/api/products/prod-1

{
    "meta" : {
        "local_identifier": "https://acme.com/skg-if/api/products/prod-1", // parent entity - product : API URL
        "entity_type": "single_entity",
        "api_items": [
            {
                    "local_identifier": "https://w3id.org/skg-if/sandbox/acme/pers-1", // child entity - person : local_identifier / PID
                    "urls": [
                        {
                            "entity_type": "link",
                            "rel": "self",
                            "href": "https://acme.com/skg-if/api/persons/pers-1" // child entity - person : API link
                        }
                    ]
            }
            // note : The SKG-IF API link for the parent entity - product is already defined by the meta.local_identifier.
            //   You are free to duplicate it in the api_items array.
        ]
    },
    "@graph": [
        {
            "local_identifier": "https://w3id.org/skg-if/sandbox/acme/prod-1", //  parent entity - product : local_identifier / PID
            "contributions": [
            {
                "by" : {
                    "local_identifier": "https://w3id.org/skg-if/sandbox/acme/pers-1" // child entity - person : local_identifier / PID
                    //...
                }
                //...
            }
            ]
            //...
        }
    ]
}

Get List of Product : https://acme.com/skg-if/api/products?filter=xxx&page=1

{
    "meta": {
        "local_identifier": "https://acme.com/skg-if/api/products?filter=xxx&page=1", // search identifier, API link
        "entity_type": "single_entity",
        "api_items": [
            {
                    "local_identifier": "https://w3id.org/skg-if/sandbox/acme/prod-1", // search result 1 - parent entity - product : local_identifier / PID
                    "urls": [
                        {
                            "entity_type": "link",
                            "rel": "self",
                            "href": "https://acme.com/skg-if/api/products/prod-1" //  search result 1 - parent entity - product : API link
                        }
                    ]
            },
            {
                    "local_identifier": "https://w3id.org/skg-if/sandbox/acme/pers-1", // search result 1 - child entity - person : local_identifier / PID
                    "urls": [
                        {
                            "entity_type": "link",
                            "rel": "self",
                            "href": "https://acme.com/skg-if/api/persons/pers-1" //  search result 1 - child entity - person : API link
                        }
                    ]
            },
            {
                    "local_identifier": "https://w3id.org/skg-if/sandbox/acme/prod-2", // search result 2 - parent entity - product : local_identifier / PID
                    "urls": [
                        {
                            "entity_type": "link",
                            "rel": "self",
                            "href": "https://acme.com/skg-if/api/products/prod-2" //  search result 2 - parent entity - product : API link
                        }
                    ]
            },
        ]

    },
    "@graph": [
        {
            "local_identifier": "https://w3id.org/skg-if/sandbox/acme/prod-1", // search result 1 - parent entity - product : local_identifier / PID
            "contributions": [
            {
                "by" : {
                    "local_identifier": "https://w3id.org/skg-if/sandbox/acme/pers-1" // search result 1 - child entity - person : local_identifier / PID
                    //...
                }
                //...
            }
            ]
            //...
        },
        {
            "local_identifier": "https://w3id.org/skg-if/sandbox/acme/prod-2" // search result 2 - parent entity - product : local_identifier / PID
            //...
        },

    ]
}

API Get Entity by Id, single entity resolving

Single entity resolve API format follows this format https://acme.com/skg-if/api/{entity-type}/{local_identifier}

For example : https://acme.com/skg-if/api/products/prod-1

Your API MUST also be able to resolve full local_identifiers including the domain/base :

https://acme.com/skg-if/api/products/https://w3id.org/skg-if/sandbox/acme/prod-1

Note : this pattern is also used in standard SKG API like Crossref

  • http://api.crossref.org/works/https://doi.org/10.1039/d1cb00160d => OK
  • http://api.crossref.org/works/10.1039/d1cb00160d => OK

Content negotiation

If you simply need to expose single entities without any API, you can expose SKG-IF with content-negotiation

The Accept header is application/vnd.skgif.ld+json

curl --location --request GET 'https://acme.com/skg-if/api/products/prod-1' --header 'Accept: application/vnd.skgif.ld+json'​

You may have custom non SKG-IF API for your entities, they can be integrated in the meta.api_links array, with the rel : service. SKG-IF Link entity relies on active stream vocabulary, rel : https://www.w3.org/TR/activitystreams-vocabulary/#dfn-rel

    "api_items": [
    {
            "local_identifier": "https://w3id.org/skg-if/sandbox/acme/prod-1", //  product : local_identifier / PID
            "urls": [
                {
                    "entity_type": "link",
                    "rel": "service",
                    "media_type": "text/xml",
                    "href": "https://acme.com/myapi/prod-1" //  product : NON SKG-IF API link
                },
                 {
                    "entity_type": "link",
                    "rel": "service",
                    "media_type": "application/json",
                    "href": "myprotocol://acme.com/serv/prod-1" //  product : NON SKG-IF API link
                },

            ]
    },

Validate a local server implementation compliance with the SKG-IF OpenAPI.

  • See : https://docs.google.com/document/d/1t7b7h28UTtM56Sda4NGJIp0hnQfGbcVVGn12fny9wfI/edit?tab=t.0
  • Read the “validation process” and “hackathon” paragraphs at the beginning of this document.
  • You can include the PRISM proxy server in your CI/CD pipeline.

Search filter formats

Filter format identifier ids

On this the get list of entity URLs like https://acme.com/skg-if/api/products?filter=identifiers.id:xxx&page=1. You may wonder what is the supported format for xxx identifiers ids.

Simple identifier URL identifier
10.1609/icwsm.v15i1.18053 https://doi.org/10.1609/icwsm.v15i1.18053
0000-0002-5355-2576 https://orcid.org/0000-0002-5355-2576

For external identifiers like DOIs, Orcids, the server :

  • MUST support simple identifiers
  • SHOULD support URL identifiers.

See how existing APIs support these patterns.

Query SKG-IF Query Equiv. Query OpenAlex Equiv. Query Crossref Equiv. Query OpenAIRE
simple identifier products?filter=identifiers.id:10.1609/icwsm.v15i1.18053 https://api.openalex.org/works?filter=doi:10.1609/icwsm.v15i1.18053 https://api.crossref.org/works?filter=doi:10.1039/d1cb00160d https://api.openaire.eu/graph/v1/researchProducts?pid=10.1038/s41563-023-01669-z
simple identifier escaped products?filter=identifiers.id:10.1609%2Ficwsm.v15i1.18053 https://api.openalex.org/works?filter=doi:10.1609%2Ficwsm.v15i1.18053 https://api.crossref.org/works?filter=doi:10.1039%2Fd1cb00160d https://api.openaire.eu/graph/v1/researchProducts?pid=10.1038%2Fs41563-023-01669-z
URL identifier products?filter=identifiers.id:https%3A%2F%2Fdoi.org%2F10.1609%2Ficwsm.v15i1.18053 https://api.openalex.org/works?filter=doi:https%3A%2F%2Fdoi.org%2F10.1609%2Ficwsm.v15i1.18053 https://api.crossref.org/works?filter=doi:https%3A%2F%2Fdoi.org%2F10.1609%2Ficwsm.v15i1.18053 https://api.openaire.eu/graph/v1/researchProducts?pid=https%3A%2F%2Fdoi.org%2F10.1609%2Ficwsm.v15i1.18053 KO
URL identifier escaped products?filter=identifiers.id:https://doi.org/10.1609/icwsm.v15i1.18053 https://api.openalex.org/works?filter=doi:https://doi.org/10.1609/icwsm.v15i1.18053 https://api.crossref.org/works?filter=doi:https://doi.org/10.1039/d1cb00160d https://api.openaire.eu/graph/v1/researchProducts?pid=http://doi.org/10.1038/s41563-023-01669-z KO

Table of contents


This site uses Just the Docs, a documentation theme for Jekyll.