RAMOSE#

from pathlib import Path

from helper import call

TOKEN = Path("ramose/state/token").read_text().strip()

A simple request#

Looking up a DOI returns the article’s title from OpenCitations Meta.

call("http://localhost:8081/api/v1/articles/10.1007/s11192-022-04367-w?format=json")
curl 'http://localhost:8081/api/v1/articles/10.1007/s11192-022-04367-w?format=json' 

# 200 OK

[
  {
    "doi": "10.1007/s11192-022-04367-w",
    "title": "Identifying And Correcting Invalid Citations Due To DOI Errors In Crossref Data"
  }
]

The join#

RAMOSE reaches both OpenCitations endpoints and combines their results inside one operation. Where the other tools can only join on terms that already coincide in the data, RAMOSE splits an operation into steps and joins the resulting tables on an arbitrary key: here it resolves the DOI to an OMID, then combines the title from Meta with the reference count from Index.

call("http://localhost:8081/api/v1/citations/10.1007/s11192-022-04367-w?format=json")
curl 'http://localhost:8081/api/v1/citations/10.1007/s11192-022-04367-w?format=json' 
# 200 OK

[
  {
    "doi": "10.1007/s11192-022-04367-w",
    "title": "Identifying And Correcting Invalid Citations Due To DOI Errors In Crossref Data",
    "br": "https://w3id.org/oc/meta/br/061202127149",
    "oc_reference_count": "30"
  }
]

Output#

The same operation in JSON and CSV.

call("http://localhost:8081/api/v1/citations/10.1007/s11192-022-04367-w?format=csv")
curl 'http://localhost:8081/api/v1/citations/10.1007/s11192-022-04367-w?format=csv' 
# 200 OK

doi,title,br,oc_reference_count
10.1007/s11192-022-04367-w,Identifying And Correcting Invalid Citations Due To DOI Errors In Crossref Data,https://w3id.org/oc/meta/br/061202127149,30

Pagination#

A bounded window with RFC 8288 Link headers and a known total.

call("http://localhost:8081/api/v1/references/10.1007/s11192-022-04367-w?format=json&page=1&page_size=2", show_headers=True)
curl -i 'http://localhost:8081/api/v1/references/10.1007/s11192-022-04367-w?format=json&page=1&page_size=2' 
# 200 OK
# Content-Type: application/json
# Link: </api/v1/references/10.1007/s11192-022-04367-w?format=json&page=2&page_size=2&total_items=30>; rel="next", </api/v1/references/10.1007/s11192-022-04367-w?format=json&page=1&page_size=2&total_items=30>; rel="first", </api/v1/references/10.1007/s11192-022-04367-w?format=json&page=15&page_size=2&total_items=30>; rel="last"

[
  {
    "doi": "10.1007/s11192-022-04367-w",
    "br": "https://w3id.org/oc/meta/br/061202127149",
    "cited": "https://w3id.org/oc/meta/br/060504627"
  },
  {
    "doi": "10.1007/s11192-022-04367-w",
    "br": "https://w3id.org/oc/meta/br/061202127149",
    "cited": "https://w3id.org/oc/meta/br/061202300315"
  }
]

Versioning#

The API version is carried in the base path (/api/v1).

API description#

OpenAPI 3.2. RAMOSE serves a Swagger UI at http://localhost:8081/docs and the spec at http://localhost:8081/api/v1/openapi.yaml.

import requests
import yaml

from helper import embed_swagger

spec = yaml.safe_load(requests.get("http://localhost:8081/api/v1/openapi.yaml", timeout=120).text)
embed_swagger(spec, base_url="http://localhost:8081/")

Authentication#

Bearer tokens. An operation marked #auth required in the spec file needs a token; the others stay open. RAMOSE keeps only the SHA-256 hash of each token in a local SQLite store and issues them from the CLI (--token-create). The /protected operation below requires a token, so without one the request is rejected with 401.

call("http://localhost:8081/api/v1/protected/10.1007/s11192-022-04367-w?format=json")
curl 'http://localhost:8081/api/v1/protected/10.1007/s11192-022-04367-w?format=json' 

# 401 UNAUTHORIZED

{
  "error": 401,
  "message": "HTTP status code 401: missing or invalid bearer token"
}

With a valid bearer token the same request succeeds.

call(
    "http://localhost:8081/api/v1/protected/10.1007/s11192-022-04367-w?format=json",
    headers={"Authorization": f"Bearer {TOKEN}"},
)
curl -H 'Authorization: Bearer 4nQyIVMRFGKj1dUZoxxi-se5NqyOYuaxOrBJm9Ep9pg' 'http://localhost:8081/api/v1/protected/10.1007/s11192-022-04367-w?format=json' 
# 200 OK

[
  {
    "doi": "10.1007/s11192-022-04367-w",
    "title": "Identifying And Correcting Invalid Citations Due To DOI Errors In Crossref Data"
  }
]

Non-RDF sources#

This RAMOSE demo exposes a REST API over a non-RDF CSV source. The operation below reads the same article from a CSV file through SPARQL Anything.

call("http://localhost:8081/api/v1/non-rdf/10.1007/s11192-022-04367-w?format=json")
curl 'http://localhost:8081/api/v1/non-rdf/10.1007/s11192-022-04367-w?format=json' 
# 200 OK

[
  {
    "doi": "10.1007/s11192-022-04367-w",
    "title": "Identifying And Correcting Invalid Citations Due To DOI Errors In Crossref Data",
    "venue": "Scientometrics"
  }
]