Skip to content

Query API ​

NeoWiki runs read-only queries against the wiki's graph stores, through one endpoint per kind of store:

EndpointQuery languageOn a wiki with
POST /neowiki/v0/query/sparqlSPARQL 1.1a SPARQL store
POST /neowiki/v0/query/cypherCypherNeo4j

A wiki can have both. On a wiki without that kind of store, the endpoint answers 404.

Both endpoints need the neowiki-query right but no CSRF token. To call them as a user rather than anonymously, log in as for the rest of the REST API. The Schema endpoints list the Schema and property names to query.

Both report a failed query with a body such as { "errorType": "emptyQuery", "message": "Query is empty." }. Branch on errorType, not on message, which is English and may change between releases. When the store rejects a query, the message carries the store's own detail. Besides their own errors, listed below, both endpoints answer:

errorTypeHTTPWhen
emptyQuery400The query is empty or contains only whitespace.
permissionDenied403The caller lacks the neowiki-query right.
rateLimitExceeded429The caller exceeded the rate limit.
internalError500Anything else.

SPARQL query endpoint ​

The query runs against the wiki's first configured SPARQL store. It holds one or more projections, in a named graph per page and projection. RDF Export describes the native projection; a Mapping defines the vocabulary of an ontology projection, such as EDM.

Request ​

POST /rest.php/neowiki/v0/query/sparql
Content-Type: application/json
json
{
    "query": "SELECT ?label WHERE { GRAPH ?page { ?s <http://www.w3.org/2000/01/rdf-schema#label> ?label } } LIMIT 10"
}
FieldTypeRequiredDescription
querystringYesA SPARQL 1.1 SELECT or ASK query. CONSTRUCT and DESCRIBE are not supported.

Successful response (200) ​

The body is the store's W3C SPARQL results JSON document, including any extras the store adds, such as QLever's meta. NeoWiki caps no rows.

json
{
    "head": { "vars": ["label"] },
    "results": { "bindings": [ { "label": { "type": "literal", "value": "Johann Sebastian Bach" } } ] }
}

Errors ​

errorTypeHTTPWhen
sparqlSyntaxError400The store rejected the query, most often for its syntax.
sparqlStoreUnavailable503The store could not be reached, failed, or did not answer within the caller's timeout.

Cypher query endpoint ​

Graph Model describes what Neo4j holds: the node labels, relationships and properties to match.

Request ​

POST /rest.php/neowiki/v0/query/cypher
Content-Type: application/json
json
{
    "cypher": "MATCH (s:Subject:Person) WHERE s.`Birth year` > $minYear RETURN s.name AS name, s.`Birth year` AS year",
    "parameters": { "minYear": 2000 }
}
FieldTypeRequiredDescription
cypherstringYesA single read-only Cypher statement.
parametersobjectNoParameter name → value map, referenced as $name in the query. Defaults to {}.

Successful response (200) ​

json
{
    "columns": ["name", "year"],
    "rows": [
        { "name": "Alice Fontaine", "year": 2001 },
        { "name": "Ben Markov",     "year": 2003 }
    ],
    "truncated": false,
    "resultCount": 2,
    "durationMs": 14
}
FieldTypeDescription
columnsarray of stringThe column names, in RETURN order. Row object key order is not guaranteed.
rowsarray of objectEach row keyed by column name.
truncatedbooleantrue when rows beyond the caller's row cap were dropped.
resultCountintegerNumber of rows in rows.
durationMsintegerQuery time in milliseconds, measured by the wiki.

Cell normalization ​

Scalar Cypher values (strings, integers, floats, booleans, null) pass through as-is. Other types surface as:

Cypher typeJSON shape
Node{ "id": ..., "labels": [...], "properties": {...} }
Relationship{ "id": ..., "type": "...", "startNodeId": ..., "endNodeId": ..., "properties": {...} }
Path{ "nodes": [...], "relationships": [...] }, its relationships without startNodeId and endNodeId
dateISO 8601 date string, e.g. "2023-10-01"
datetime / zoned timeISO 8601 string with a whole-minute offset, e.g. "2023-09-13T14:22:23+00:00" / "14:22:23+02:00"
localdatetime / localtimeISO 8601 string without offset, e.g. "2023-09-13T14:22:23" / "09:30:00"
duration{ "months": ..., "days": ..., "seconds": ..., "nanoseconds": ... }
point{ "x": ..., "y": ..., "crs": "...", "srid": ... } (plus "z" for 3D points)

id, startNodeId and endNodeId are Neo4j's internal ids. The ID of a Subject or Relation is the id in its properties.

Errors ​

errorTypeHTTPWhen
parameterMissing400The query references $x but parameters has no key x.
cypherSyntaxError400Neo4j reports a syntax error in the query.
queryTimeout408The query ran past the caller's timeout.
writeQueryRejected422The query is not read-only, or uses CALL or SHOW.
backendUnavailable503Neo4j could not be reached.

Limits and tiers ​

Unless $wgNeoWikiQueryLimits changes them, two tiers cap each query:

TierWhoTimeout (timeoutSeconds)Cypher row cap (maxRows)
defaultCallers without apihighlimits30 s5,000 rows
expensiveCallers with the core apihighlimits right300 s50,000 rows

Queries run from wikitext or Lua always use the default tier.

Rate limits ​

Calls to either endpoint count against MediaWiki's $wgRateLimits key neowiki-query. NeoWiki's defaults:

CallerLimit
All anonymous callers together10 requests / 60 s
Each logged-in user60 requests / 60 s
Each bot1,000 requests / 60 s
Administrators and bureaucratsUnlimited (core noratelimit right)

Permissions ​

RightDefault groupsGrants
neowiki-query* (everyone, including anonymous visitors)Calling the query endpoints, running queries from wikitext or Lua, and seeing Subject counts. A holder reads whole graph stores: results are not filtered per page.
apihighlimitsbot, sysop (core defaults)The expensive tier.
  • REST API — the other endpoints, and the OpenAPI spec.
  • Parser Functions — {{#sparql_raw}} and {{#cypher_raw}} for query output in wikitext.
  • Lua API — nw.sparqlQuery() and nw.query() for queries from Lua modules.
  • ADR 19: Graph Database Architecture — why each store keeps its own query language, with no NeoWiki query language on top.