GraphQL guide
The GraphQL endpoint reads the entities of your Knowledge Graph as JSON shaped like the query. It is read-only. To compare it with SPARQL, see Query the Knowledge Graph. The request and response schema is in the API reference.
First query
Replace $WORDLIFT_KEY with your WordLift key:
curl -s https://api.wordlift.io/graphql \
-H "Authorization: Key $WORDLIFT_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ entities(rows: 3) { iri name: string(name: \"schema:name\") } }"}'
{
"data": {
"entities": [
{ "iri": "https://data.example.org/kg/acme", "name": "Acme" },
{ "iri": "https://data.example.org/kg/beta", "name": "Beta" },
{ "iri": "https://data.example.org/kg/gamma", "name": "Gamma" }
]
}
}
Requests
- Send
POSTwith a JSON body:query, and optionallyvariablesandoperationName. - Send one operation per request. Batched arrays of operations are not supported.
- Authenticate with
Authorization: Key <your key>orX-API-Key: <your key>. The key selects your Knowledge Graph. - Add
X-Include-Private: trueto read private data.
The endpoint supports introspection, so GraphQL clients and code generators can read its schema.
Entry points
Each entry point returns entities. The most common are:
| Entry point | Returns |
|---|---|
resource(iri: "…") | one entity, by IRI |
entities(query, page, rows) | any entities, with filters on type, URL, name and other properties |
entity(url: "…") | the entities with this schema:url |
articles, products, webpages, events, organizations, persons, faqPages, … | entities of one type, with filters for that type |
entitySearch(query, page, rows, orderBy) | entities that match filters or a vector search, with sorting |
Introspect the endpoint to see every entry point and which filters each accepts.
Read properties
Entities read any property by name. Choose the field for the kind of value:
| Field | Returns |
|---|---|
string(name), strings(name) | literals as strings |
int, float, bool, date, dateTime, time, and their plurals | literals as that type |
text(name, lang, langs), texts(…) | { value lang }, optionally only in some languages |
ref(name), refs(name) | the IRIs a property points to |
resource(name), resources(name) | the entities a property points to, to read their properties in turn |
topN(name, limit, sort) | the first entities a property points to, sorted on one of their properties |
aggregateInt, aggregateFloat(name, operation, aggregationField) | the SUM or AVG of a property of the entities a property points to |
The singular field returns the first value; the plural returns all of them. Name properties with a prefix, such as schema:name or rdf:type.
{
product(iri: "https://data.example.org/kg/acme-anvil") {
name: string(name: "schema:name")
description: text(name: "schema:description", lang: "en") { value }
brand: resource(name: "schema:brand") { name: string(name: "schema:name") }
averagePrice: aggregateFloat(name: "schema:offers", operation: AVG, aggregationField: "schema:price")
}
}
Use aliases (name:, brand:) to give each field a name in the answer.
Filter
A list entry point's query argument holds its filters, and an entity must match all of them. Most filters are named <property>Constraint and take one operator:
| Operator | Matches values that |
|---|---|
eq: "x" | equal x |
in: […], notIn: […] | are, or are not, in the list |
regex: { pattern, i } | match a regular expression; i: true ignores case |
gt, gte, lt, lte | are greater or smaller |
between: { lower, upper } | are within a range |
exists: { exists: true } | are present (or absent, with false) |
contains is an older name for eq. It matches a whole value, not part of one: use regex for that.
{
entities(
query: {
typeConstraint: { in: ["http://schema.org/Article", "http://schema.org/WebPage"] }
headlineConstraint: { regex: { pattern: "knowledge graph", i: true } }
}
rows: 20
) {
iri
headline: string(name: "schema:headline")
}
}
Each constraint takes one operator. For a range, use between instead of combining gte and lte. Find what changed with GraphSync shows a date filter.
Page through results
pagecounts from 0, androwsis the page size. With onlypage, a page has 10 entities.- Paged results come in a stable order, by IRI (after the
orderBysort, where an entry point has one). Read pages until one has fewer thanrowsentities, and you get every match exactly once. - Without
pageandrows, results come in no particular order. Page any list that can be long.
Vector search
entitySearch ranks entities by meaning, not by exact words:
{
entitySearch(query: { search: { string: "customer service" } }, rows: 5) {
iri
score: float(name: "_:score")
name: string(name: "schema:name")
}
}
- Results come best first. The only sort allowed is by score (
orderBy: [score_DESC]). - Read the similarity score with
float(name: "_:score"). - Other filters in
querystill apply, for exampletypeConstraint.
Private data
Some properties and entities in your Knowledge Graph can be private, such as the GraphSync bookkeeping properties in the seovoc: namespace. Without X-Include-Private: true:
- private entities are left out of every answer;
- a field that reads a private property returns
null, or[]for a list; - a filter or sort on a private property matches nothing.
Send the header when your application needs those values, and only from a server: do not expose it, or your key, in a browser.
Errors
- A GraphQL error, such as a syntax error, an unknown field or an invalid regular expression, returns HTTP
200with anerrorsarray. Checkerrorsas well as the status code. - A field that fails returns
nullwith an error for its path. The rest of the answer is kept. 401and403mean the key is missing or not valid.