grlc#
grlc treats each SPARQL query as a first-class artefact stored in a Git repository: every query file becomes one operation, and the API version is the commit. It reaches both endpoints, but with one operation each, so it cannot combine them.
from helper import call
A simple request#
One operation returns the title from OpenCitations Meta.
call("http://localhost:8082/api-local/article-meta?doi=10.1007/s11192-022-04367-w", headers={"Accept": "application/json"})
curl -H 'Accept: application/json' 'http://localhost:8082/api-local/article-meta?doi=10.1007/s11192-022-04367-w'
# 200 OK
{
"head": {
"vars": [
"title",
"br"
]
},
"results": {
"bindings": [
{
"title": {
"type": "literal",
"value": "Identifying And Correcting Invalid Citations Due To DOI Errors In Crossref Data"
},
"br": {
"type": "uri",
"value": "https://w3id.org/oc/meta/br/061202127149"
}
}
]
}
}
The join#
No join. Each query file binds one endpoint, so the reference count from Index needs a second, separate operation; the client correlates the two responses on the OMID.
call("http://localhost:8082/api-local/references-index?br=https://w3id.org/oc/meta/br/061202127149", headers={"Accept": "application/json"})
curl -H 'Accept: application/json' 'http://localhost:8082/api-local/references-index?br=https://w3id.org/oc/meta/br/061202127149'
# 200 OK
{
"head": {
"vars": [
"br",
"oc_reference_count"
]
},
"results": {
"bindings": [
{
"br": {
"type": "uri",
"value": "https://w3id.org/oc/meta/br/061202127149"
},
"oc_reference_count": {
"type": "literal",
"datatype": "http://www.w3.org/2001/XMLSchema#integer",
"value": "30"
}
}
]
}
}
Output#
Format follows the Accept header, forwarded to the endpoint.
call("http://localhost:8082/api-local/article-meta?doi=10.1007/s11192-022-04367-w", headers={"Accept": "text/csv"})
curl -H 'Accept: text/csv' 'http://localhost:8082/api-local/article-meta?doi=10.1007/s11192-022-04367-w'
# 200 OK
title,br
Identifying And Correcting Invalid Citations Due To DOI Errors In Crossref Data,https://w3id.org/oc/meta/br/061202127149
Pagination#
The last link is a guess: grlc does not get the real total because of a bug (CLARIAH/grlc#573).
call("http://localhost:8082/api-local/cited-list?br=https://w3id.org/oc/meta/br/061202127149&page=1", headers={"Accept": "application/json"}, show_headers=True)
curl -i -H 'Accept: application/json' 'http://localhost:8082/api-local/cited-list?br=https://w3id.org/oc/meta/br/061202127149&page=1'
# 200 OK
# Content-Type: application/json;charset=utf-8
# Link: <http://localhost:8082/api-local/cited-list?br=https%3A%2F%2Fw3id.org%2Foc%2Fmeta%2Fbr%2F061202127149&page=2>; rel=next, <http://localhost:8082/api-local/cited-list?br=https%3A%2F%2Fw3id.org%2Foc%2Fmeta%2Fbr%2F061202127149&page=0>; rel=prev, <http://localhost:8082/api-local/cited-list?br=https%3A%2F%2Fw3id.org%2Foc%2Fmeta%2Fbr%2F061202127149&page=1>; rel=first, <http://localhost:8082/api-local/cited-list?br=https%3A%2F%2Fw3id.org%2Foc%2Fmeta%2Fbr%2F061202127149&page=500.0>; rel=last
[
{
"cited": "https://w3id.org/oc/meta/br/062501777134"
},
{
"cited": "https://w3id.org/oc/meta/br/061302130520"
}
]
Versioning#
The version is the Git commit. With a GITHUB_TOKEN in .env and the queries pushed to GitHub, grlc serves any past revision through the api-git route, naming the commit in the path:
curl -H 'Accept: application/json' \
'http://localhost:8082/api-git/arcangelo7/sparql-api-comparison/subdir/grlc/queries/commit/1872cd59b0524ce764060ba72f61d5e7aafe29a4/article-meta?doi=10.1007/s11192-022-04367-w'
API description#
OpenAPI 2.0.
call("http://localhost:8082/api-local/swagger")
curl http://localhost:8082/api-local/swagger
# 200 OK
{
"basePath": "/api-local/",
"definitions": {
"Message": {
"type": "string"
}
},
"host": "localhost",
"info": {
"contact": {
"name": "",
"url": ""
},
"description": "API generated from local files",
"title": "local",
"version": "local"
},
"next_commit": null,
"paths": {
"/article-meta": {
"get": {
"description": "\n\n```\n#+ summary: Title of a bibliographic resource in OpenCitations Meta, by DOI\n#+ endpoint: http://meta-counted:7001/sparql\n#+ method: GET\n#+ tags:\n#+ - meta\n\nPREFIX datacite: <http://purl.org/spar/datacite/>\nPREFIX literal: <http://www.essepuntato.it/2010/06/literalreification/>\nPREFIX dcterms: <http://purl.org/dc/terms/>\n\nSELECT ?title ?br WHERE {\n ?id datacite:usesIdentifierScheme datacite:doi ;\n literal:hasLiteralValue ?_doi .\n ?br datacite:hasIdentifier ?id ;\n dcterms:title ?title .\n}\n\n```",
"parameters": [
{
"default": "http://meta-counted:7001/sparql",
"description": "Alternative endpoint for SPARQL query",
"in": "query",
"name": "endpoint",
"type": "string"
},
{
"description": "A value of type string that will substitute ?_doi in the original query",
"in": "query",
"name": "doi",
"required": true,
"type": "string"
}
],
"produces": [
"text/csv",
... (184 more lines)
Consumer authentication#
Not supported.
Endpoint authentication#
HTTP Basic. config.ini sets a default endpoint together with a user and a password; grlc sends them only to that default endpoint, since a query that names its own endpoint in a #+ endpoint decorator is sent without credentials. The article-meta-basic query names no endpoint, so it reaches meta-basic with the credentials.
from pathlib import Path
print(Path("grlc/config.ini").read_text())
call("http://localhost:8082/api-local/article-meta-basic?doi=10.1007/s11192-022-04367-w", headers={"Accept": "application/json"})
[auth]
github_access_token = xxx
gitlab_access_token = yyy
[local]
local_sparql_dir = /app/queries/
[defaults]
sparql_endpoint = http://meta-basic:3030/sparql
server_name = localhost
user = demo
password = demo
debug = False
[api_gitlab]
gitlab_url = https://gitlab.com
[user_agent]
product = grlc
version = 1.3.11
comment = https://github.com/CLARIAH/grlc
curl -H 'Accept: application/json' 'http://localhost:8082/api-local/article-meta-basic?doi=10.1007/s11192-022-04367-w'
# 200 OK
{
"head": {
"vars": [
"title",
"br"
]
},
"results": {
"bindings": [
{
"title": {
"type": "literal",
"value": "Identifying And Correcting Invalid Citations Due To DOI Errors In Crossref Data"
},
"br": {
"type": "uri",
"value": "https://w3id.org/oc/meta/br/061202127149"
}
}
]
}
}
Operations#
GET and POST, both running the same read query. The other methods are rejected.
call("http://localhost:8082/api-local/article-meta?doi=10.1007/s11192-022-04367-w", method="POST", headers={"Accept": "application/json"})
curl -X POST -H 'Accept: application/json' 'http://localhost:8082/api-local/article-meta?doi=10.1007/s11192-022-04367-w'
# 200 OK
{
"head": {
"vars": [
"title",
"br"
]
},
"results": {
"bindings": [
{
"title": {
"type": "literal",
"value": "Identifying And Correcting Invalid Citations Due To DOI Errors In Crossref Data"
},
"br": {
"type": "uri",
"value": "https://w3id.org/oc/meta/br/061202127149"
}
}
]
}
}
call("http://localhost:8082/api-local/article-meta?doi=10.1007/s11192-022-04367-w", method="PUT", max_lines=0)
call("http://localhost:8082/api-local/article-meta?doi=10.1007/s11192-022-04367-w", method="DELETE", max_lines=0)
curl -X PUT 'http://localhost:8082/api-local/article-meta?doi=10.1007/s11192-022-04367-w'
# 405 METHOD NOT ALLOWED
... (5 more lines)
curl -X DELETE 'http://localhost:8082/api-local/article-meta?doi=10.1007/s11192-022-04367-w'
# 405 METHOD NOT ALLOWED
... (5 more lines)
Caching#
Not supported. The tool reaches OpenCitations Meta through a proxy that records every request it forwards, and two identical calls send the same SPARQL requests twice.
from helper import count_endpoint_requests
count_endpoint_requests("http://localhost:8082/api-local/article-meta?doi=10.1007/s11192-022-04367-w", headers={'Accept': 'application/json'})
First call: 200 OK, SPARQL requests that reached the endpoint: 1
Second call: 200 OK, SPARQL requests that reached the endpoint: 1