GraphQL Query Tutorial¶
What’s in this document?
The following sections provide examples of Star Wars GraphQL queries and responses. If you have started the services following the Quick Start guide, you can also try the queries out and modify them as you see fit.
All examples in this section are based on the Star Wars dataset.
Retrieve Objects¶
GraphQL queries can fetch single or multiple object types.
Retrieve a List of Objects¶
All we have to do to fetch multiple object types using the Semantic Objects is to define a valid nested GraphQL query.
Let’s say that we need some basic information about all the characters in the Star Wars saga. We need to:
- define a name for our query
query allCharacters {}
- set the type of objects (
character
) and properties (id
,name
,gender
,birthYear
,height
) that we want to retrieve.query allCharacters { character { id name gender birthYear height } }
And that’s it! We have our first query that can retrieve all the characters within the Star Wars dataset. You can edit the query directly in the integrated GraphiQL editor.
query allCharacters { character { id name gender birthYear height } }
Using the same approach, we can define as many queries as we need. The next example fetches all Star Wars films including some of their properties.
query allFilms { film { name episodeId role { roleType person { name } } releaseDate } }
Retrieve a Single Object¶
To retrieve a single object, we can filter a list of objects using a known, unique property value.
For example, let’s say we want to retrieve information about a single Star Wars character
Luke Skywalker
that has a unique ID
property which equals https://swapi.co/resource/human/1
.
We can do this by altering the allCharacters
query (above), by adding a
ID
filter upon the set of all characters:
query character { character(ID: "https://swapi.co/resource/human/1") { id name gender birthYear height } }
Retrieve Nested Objects¶
Now let’s fetch objects and their related objects using single or multi-valued object properties that are defined in the SOML schema. The relationships can be defined using objects single value properties (one-to-one) or multi-valued properties (one-to-many).
These nested object queries retrieve data for an object type along with data from nested or related object types.
The previous example only retrieved scalar
information for the Luke Skywalker
object.
We will extend the example to use nested object properties as well as scalar properties.
The SOML schema defines several nested object relationships using object ranges.
For example, the film
object property has a Film
object type for its range
.
Character:
kind: abstract
typeProp: "rdf:type"
type: ["voc:Character"]
props:
film: {descr: "Star Wars films appeared in", max: inf, range: Film}
homeworld: {label: "Characters homeworld(planet)", range: Planet}
starship: {label: "Characters starship(s)", max: inf, range: Starship}
vehicle: {label: "Characters vehicles(s)", max: inf, range: Vehicle}
species: {label: "Characters species", range: Species, rdfProp: "rdf:type", rangeCheck: true}
We will use the film
relationship and will fetch the names of all films with the Luke Skywalker
character.
query lukeSkywalkerFilms { character(ID: "https://swapi.co/resource/human/1") { id name gender birthYear height film{ name } } }
We can go even deeper and extract all the starships that appear in the films that Luke Skywalker appeared in.
query starshipsInLukeSkywalkerFilms { character(ID: "https://swapi.co/resource/human/1") { id name gender birthYear height film { name starship { name } } } }
Ordered Object List¶
An object list can be ordered by using an orderBy
input argument with an
ascending (ASC
) or descending (DESC
) order.
Note
The order can be applied to objects and multi-valued object properties based on single value or multilingual string based scalars. It can be applied to multi-valued scalars as well.
Now let’s sort a list of character objects by height.
query charactersOrderedByHeight { character(orderBy: {height: DESC}) { id name height } }
We can order nested object properties as well. In the next example, we order all the films that
Luke Skywalker
appeared in by the film’s name in ascending order.
query lukeSkywalkerFilmsOrderedByName { character(ID: "https://swapi.co/resource/human/1") { id name gender birthYear height film (orderBy: {name: ASC}){ name } } }
It is also possible to order using two or more properties.
<object> (orderBy: {<property1>: <ASC/DESC>, <property2>: <ASC/DESC>}) {<properties>}
In the next example, we order all the films
that Luke Skywalker
appeared in by the films
name
(in ascending order). We also, order all the starships
that appeared in each film
by their
maxAtmospheringSpeed
(in descending order). If the starships
have an equal maxAtmospheringSpeed
,
then the starships
are additionally ordered by cargoCapacity
in descending order.
query starshipsInLukeSkywalkerFilmsOrderedBySpeedAndCapacity { character(ID: "https://swapi.co/resource/human/1") { id name gender birthYear height film (orderBy: {name: ASC}){ name starship (orderBy: {maxAtmospheringSpeed: DESC, cargoCapacity: DESC}){ name maxAtmospheringSpeed cargoCapacity } } } }
Another possibility is to order an object list using nested object properties.
<object> (orderBy: {<object_property1>: {<property1>:<ASC/DESC>}}) {<properties> <object_property1>{<property1>}}
For example, let’s order a list of character objects by the character’s species name in ascending order.
query charactersOrderedBySpeciesName { character (orderBy: {species: {name:ASC}}) { id name gender birthYear height species {name} } }
In Semantic Objects 4.1, we can order a list of objects represented by an abstract type using the specific properties from the one or more sub types using the following construct:
<abstract_object> (orderBy: {
<common_property>: <ASC/DESC>,
_ifSubType1: {<object_property1>: {<property1>: <ASC/DESC>}},
_ifSubType2: {<property2>: <ASC/DESC>}
}) {
<common_property>
... on SubType1 { <object_property1> { <property1> } }
... on SubType2 { <property2> }
}
In this case, the objects will be first grouped into a bucket, that consists of objects that have a value for the first property for sorting and will be ordered by the given direction. The remaining objects, that does not have the first property, will be grouped by the second property filter, if applicable, and placed into a bucket. The second bucket will be ordered by the second property for the specified sort direction. The remaining objects will be added as is to the end of the results or ordered by the next criteria again, if present. This is done until all sort properties are exhausted.
We can also order a multi-value scalar property. The species
object definition includes
several multi-value scalar properties. For example, skinColor
has a max
cardinality defined as inf
.
This indicates that the skinColor
property can have infinite (multiple) values, e.g.,
“white”, “brown”, “black”, “beige”, etc.
Species:
type: ["voc:Species"]
typeProp: "rdf:type"
props:
skinColor: {descr: "Species skin colour", max: inf}
hairColor: {descr: "Species hair colour", max: inf}
eyeColor: {descr: "Species eye colour", max: inf}
...
Let’s order the species skin color property values:
query characterOrderedBySpeciesSkinColor { character(ID: "https://swapi.co/resource/human/1") { id name gender birthYear height species{ name skinColor(orderBy: ASC) } } }
LangString Ordering¶
As discussed in the Ordered Object List section, we can apply orderBy
in two distinct cases:
- Order the values of the multi-valued scalar properties
- Order object array by field: use a single-value field to order its multi-valued parent object
The same two cases apply for langString
fields, but such fields are treated as single-valued or multi-valued dynamically, depending on the effective language pattern.
Ordering of LangString Values¶
When fetching a multi-valued string
or langString
field, you can use orderBy
, limit
, and offset
to order the values,
but only if the language specification in effect is using ALL
. Otherwise, an error will be returned.
Here is an example use of the orderBy
to return and sort the English and French language values in ascending order:
query humanDescriptions { human(where: {desc: {}}) { id name desc(lang: "ALL:en~,fr~", orderBy: ASC) { value lang } } }
Other examples of ordering a multi-valued literal properties:
Query | Result |
---|---|
{human {desc(lang: “ALL”, orderBy: ASC) {value}}} | All values in ascending alphabetical order |
{human (lang: “ALL”) {desc(orderBy: ASC) {value}}} | Same: ALL is inherited from the higher level |
{human {desc(orderBy: ASC) {value}}} | Same unless changed in the schema: ALL is the global default |
{human {desc(lang: “ALL:en”, orderBy: ASC) {value}}} | All English-language values in ascending alphabetical order |
{human {desc(lang: “ALL:en~”,orderBy: ASC) {value}}} | All values in English (or “dialect”) in ascending alphabetical order |
{human {desc(lang: “ALL:NONE”,orderBy: ASC) {value}}} | All values without language tag in ascending alphabetical order |
{human {desc(lang: “en”, orderBy: ASC) {value}}} | Error: orderBy cannot be used without ALL |
Ordering by Single LangString Value¶
When fetching a multi-valued object field, you can order by a string
or langString
field
if the field is single-valued, or if the language specification in effect does not contain ALL
.
Note that the langString
fields have different arguments when ordering by them. The format is as follows:
<object>(orderBy : {<langStringProperty>: {dir: <ASC/DESC>, lang: <filterPattern>}}) {
<langStringProperty> {
value
lang
}
}
The ordering could be ASC
, which is the default if not specified, or could be DESC
in Unicode collation order ignoring any language tags.
Due to technical limitations, only values matching the first positive language tag are used for ordering.
If an object does not have a matching value, it comes last for both ASC
and DESC
directions.
There must be a single matching value, otherwise the result of ordering is indeterminate.
It is recommended, but not required, that the ordering field has a UNIQ
constraint for that language tag.
Let’s illustrate this with an example:
query humanDescriptions { human(where: {desc: {}}, orderBy: {desc: {dir: DESC, lang: "en"}}) { id name desc { value lang } } }
Other examples of ordering by langString
properties, where desc
is a multi-valued langString
, label
a single-valued langString
:
Query | Result |
---|---|
{character(orderBy: {desc: {lang: “en”, dir: ASC}}) {desc(lang: “en”) {value}}} | Order alphabetically by en language, there must be only one such value, objects with no matching value come first |
{character(orderBy:{desc: {lang: “en”}}) {desc(lang: “en”) {value}}} | Same: the default dir is ASC |
{character(lang: “en”, orderBy: {desc: {}}) {desc{value}}} | Same: lang spec inherited from higher level, default dir is ASC |
{character(orderBy: {desc: {}}) {desc{value}}} | Same, if the default fetch specification is lang: "en" |
{character(lang: “en”, orderBy: {desc: {dir: DESC}}) {desc{value}}} | Reverse alphabetical order by en desc, objects with no matching value come last |
{character(orderBy: {label: ASC}) {label{value}}} | Order alphabetically; no language spec needed or allowed for single-valued langString |
{character(orderBy: {desc: {lang: “en~”}}) {desc(lang: “en~”) {value}}} | Order alphabetically by en~ desc, there must be only one such, objects with no matching value come first |
{character(orderBy: {desc: {lang: “ALL”}}) {desc{value}}} | Error: ALL is not allowed for ordering |
{character(orderBy: {desc: {lang: “ANY”}}) {desc(lang: “ANY”) {value}}} | Error: ANY does not specify a concrete lang to order by |
{character(orderBy: {desc: {lang: “-fr”}}) {desc(lang: “ANY”) {value}}} | Error: -fr does not specify a concrete lang to order by |
{character(lang: “fr,en”, orderBy: {desc: {}}) {desc{value}}} | Order alphabetically by fr desc, there must be only one such, objects with no matching value come first,
return fr or en descriptions |
{character(lang: “BROWSER”, orderBy: {desc: {}}) {desc{value}}} | Assume the HTTP Accept-Language header has the value
‘fr;q=0.5, en;q=1.0’. This will result in ‘en~,fr~’ as the effective language order pattern.
Order alphabetically by en desc, there must be only one such, objects with
no matching value come first, return en or fr descriptions |
Paginated List of Objects¶
You can paginate an Object list by using LIMIT
and OFFSET
input arguments.
LIMIT
specifies the number of objects to retrieve per page.
OFFSET
determines which page slice to retrieve.
Pagination and offsets can be applied to multi-valued object properties.
Note
Pagination and offsets can be applied to multi-valued object properties as well as to multi-value scalars.
The following are examples of different pagination queries.
Let’s restrict the list of films
to only return the first page of results (No OFFSET
argument),
where a page of results is LIMIT
-ed to only include two films
.
query starshipsInTwoLukeSkywalkerFilms { character(ID: "https://swapi.co/resource/human/1") { id name gender birthYear height film (orderBy: {name: ASC}, limit: 2 ){ name starship (orderBy: {maxAtmospheringSpeed: DESC, cargoCapacity: DESC}){ name maxAtmospheringSpeed cargoCapacity } } } }
To retrieve the second page of results, we need to set an OFFSET
to
two skips to the second page.
query starshipsInTwoLukeSkywalkerSecondPageFilms { character(ID: "https://swapi.co/resource/human/1") { id name gender birthYear height film (orderBy: {name: ASC}, limit: 2, offset: 2 ){ name starship (orderBy: {maxAtmospheringSpeed: DESC, cargoCapacity: DESC}){ name maxAtmospheringSpeed cargoCapacity } } } }
Now let’s LIMIT
the list of starships
to include only two results.
Again the OFFSET
is not defined (the first page of results).
query twoStarshipsInTowLukeSkywalkerFilms { character(ID: "https://swapi.co/resource/human/1") { id name gender birthYear height film (orderBy: {name: ASC}, limit: 2 ){ name starship (orderBy: {maxAtmospheringSpeed: DESC, cargoCapacity: DESC}, limit: 2){ name maxAtmospheringSpeed cargoCapacity } } } }
We can also use an OFFSET
argument on an object list without specifying a LIMIT
argument.
This allows you to retrieve all results from the OFFSET
until the end of the result set.
query allExceptTwoStarshipsInLukeSkywalkerFilms { character(ID: "https://swapi.co/resource/human/1") { id name gender birthYear height film (orderBy: {name: ASC}){ name starship (orderBy: {maxAtmospheringSpeed: DESC, cargoCapacity: DESC}, offset: 2){ name maxAtmospheringSpeed cargoCapacity } } } }
Filtering Object Lists¶
You can use where:
arguments on object lists to filter lists.
A where:
argument can use property values and nested objects property values within filter expressions.
For top-level queries and multi-valued properties, you can use a where
parameter
that expresses a search/filter condition in a structured way, using field names
(including nested properties), comparison operators (e.g., LT
), and Boolean operators (e.g., OR
).
It is possible to combine GraphQL query filters within the same where:
argument by using the default `AND
connective and explicit connectives
such as AND:
, OR:
, EXISTS:
.
Comparison Operators¶
Comparison operators come in pairs:
EQ:NEQ:
- equality/inequality. Should be used for single values filter expressions.
<object> (where: {<property>: {EQ:<value>}}) {<properties>}
The following query will filter the list of characters
to only include those that have the
male
gender type.
query allMaleCharacters { character (where: {gender: {EQ:"male"}}) { id name gender birthYear height } }
IN:NIN:
- inside/outside of an array of values (put them in square brackets).
<object> (where: {<property>: {IN:[<value1, value2>]}}) {<properties>}
<object> (where: {<property>: {IN:<value>}}) {<properties>}
Hint
Please note that SPARQL logic is 3-valued: true, false, and undef (in case the input field is missing), so it is possible for both of these to be unsatisfied:
<object> (where: {<property>: {IN:[3]}}) {<properties>} # looks for a value equal to 3
<object> (where: {<property>: {NIN:3}}) {<properties>} # looks for a value different from 3
The following query will filter the list of characters
to include only those that have a
birthYear
IN 19BBY
.
query allCharactersBornIn19BBY { character (where: {birthYear: {IN:"19BBY"}}) { id name gender birthYear height } }
LT:GTE
andLTE:GT:
- less-than/greater-than-or-equal and less-than-or-equal/greater-than. Comparison of numbers, strings, or IRIs.
The following GraphQL query will filter the list of Character
objects so that it does
not include any characters
who have height
greater than 2 meters.
query allCharactersTallerThan200 { character (where: {height: {GT: 200}}) { id name gender birthYear height } }
RE:NRE
andIRE:NIRE:
- regular expression match/mismatch. TheI
variants make case-insensitive comparisons using Unicode alphabet collation.
Warning
Regex comparison is slow, so you should only use it on small result sets.
The following query will filter the list of characters to only include those with sky
in their name.
query allCharactersWithNameContainingSky { character (where: {name: {IRE: "sky"}}) { id name gender birthYear height } }
ID:
- access an object or object property by IRI (id).
<object> (ID:"<value>") {<properties>}
<object> (ID:["<value1>",""<value1>""]) {<properties>}
<object> (where: {<object_property>: {ID:"<value>"}}) {<properties>}
Characters starring in a A New Hope
film.
query allCharactersInANewHope { character (where: {film: {ID: "https://swapi.co/resource/film/1"}}) { id name gender birthYear height film { name } } }
Logical Connectives¶
You can also use the following logical connectives:
AND
(conjunction) is implicit between clauses in the same input objectTo compare two properties of the same object, put them together.
<object> (where: {<property1>: {EQ:"<value1>"}, <property2>: {IRE:"<value2>"}}) {<properties>}
Filter the list of
characters
to only include those with aheight
less than 100 and amass
greater than or equal to 45.0. (note: commas are optional in GraphQL)Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery characterHeightMassFilter { character(where: {height: {LT: 100}, mass: {GTE: 45.0}}) { id name gender birthYear height mass } }To apply two comparisons to one property (e.g., a range check), put them together.
<object> (where: {<property1>: {GTE:"<value1>", LT:"<value2>"}) {<properties>}
Filter the list of
characters
to only include those with aheight
greater than 150 and less than 165.Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery characterHeightBetween { character(where: {height: {GT: 150, LT: 165}}) { id name gender birthYear height } }AND
is an explicit conjunction: you will need to use it in two cases:- To check two different instances of the same property.
<object> (where: {AND: [{<object_property1>: {<property2>: {EQ:<value1>}}}, {<object_property1>: {<property2>: {EQ:<value2>}}}]}) {<properties>}
Filter the list of
characters
to only include those that have appeared infilms
withepisodeId
1AND
episodeId
5.Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery commonCharactersInFilms { character (where: {AND: [{film: {episodeId: {EQ: 1}}}, {film: {episodeId: {EQ: 5}}}]}){ id name gender birthYear height film { episodeId } } }NOTE: You cannot write this query using
IN
because that would look for all characters starred in the selected episodes.<object> (where: {<object_property1>: {<property2>: {IN: [<value1>, <value2>]}}}) {<properties>}
Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery allCharactersInFilms { character (where: {film: {episodeId: {IN: [1,5]}}}){ id name gender birthYear height } }
OR
takes an array of clauses and applies a disjunction.<object> (where: {OR: [{<property1>: {IRE: <value1>}}, {<property2>: {IRE: <value2>}}]}) {<properties>}
Filter the list of
characters
with nameSkywalker
oreyeColor
green
:Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery charactersWithGreenEyesOrNameSkywalker { character (where: {OR: [{name: {IRE: "Skywalker"}}, {eyeColor: {IRE: "green"}}]}) { id name eyeColor birthYear height } }NOTE: If you need to check for one of several values in the same field, it is easier to use
RE
with|
(for text comparison) orIN
(for fixed values).<object> (where: {<property>: {IRE: "<value1>|<value2>"}}) {<properties>}
Filter the list of
characters
to only include those with a name propertyAnakin
orLuke
in thename
:Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery charactersWithAnakinOrLukeInName { character (where: {name: {IRE: "Anakin|Luke"}}){ id name eyeColor birthYear height } }NOTE: You can use
OR
at the operator level if you need a disjunction of two comparisons on the same field.<object> (where: {<property>: {OR: [{LT: <value1>} {GT: value2}]}}) {<properties>}
Look for
characters
withheight
outside the range 100..200.Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery characterHeightBetween { character(where: {height: {OR: [{LT: 100}, {GT: 200}]}}) { id name gender birthYear height } }NOT
negates a clause. Most of the time you will not need it because you can use negation at the operator level.Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery notMaleCharacters { character (where: {NOT: {gender: {IRE: "male"}}}){ id name eyeColor birthYear height } }exists
is implicit when checking properties and sub-properties (one value is enough to satisfy the condition).<object> (where: {<property>: {}}) {<properties>}
Look for
characters
with at least onestarship
andvehicle
.Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery charactersWithStarshipAndVehicle { character (where: {starship: {}, vehicle: {}}){ id name starship (limit: 1) {name} vehicle (limit: 1) {name} } }ALL
is applicable to multi-valued properties and checks that all values satisfy the condition.<object> (where: {All: {<object_property>: {<property>: {GTE: <value>}}}}) {<properties>}
Find
characters
all of whosestarships
havemaxAtmospheringSpeed
higher than 1000.Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery charactersWithFastStarshipOrMissing { character (where: {ALL: {starship: {maxAtmospheringSpeed: {GTE: 1000}}}}){ id name starship (limit: 1) {maxAtmospheringSpeed} } }Please note that
characters
without anystarship
will also be returned by the above query (a vacuous truth), so you may want to add an existence check:<object> (where: {All: {<object_property1>: {<property2>: {GTE: <value>}}} <object_property1>: {<property2>: {GTE: <value>}}}) {<properties>}
Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery charactersWithFastStarship { character (where: {ALL: {starship: {maxAtmospheringSpeed: {GT: 1000}}} starship: {maxAtmospheringSpeed: {GT: 1000}}}){ id name starship (limit: 1) {maxAtmospheringSpeed} } }ALL_EXISTS
is applicable to multi-valued properties and checks bothALL
andexists
.<object> (where: {ALL_EXISTS: {<object_property>: {<property>: {GTE: <value>}}}}) {<properties>}
The query below filters the list of
characters
that havestarship
with only tallpilots
(over 180cm) and have at least one suchpilot
, and returns all their pilots:Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery charactersWithStarshipAnaHeightPilots { character (where: {starship: {ALL_EXISTS: {pilot: {height: {GTE:180}}}}}){ id name starship { pilot{ height } } } }
Type Selectors¶
Version 3.1 of the Semantic Objects introduces a special type selector that acts as a shortcut for type checking as well as provides access to specific type properties when we filter properties with interface range.
The type selector has the form _ifType
where Type
will be any concrete sub-type for the current interface.
Let’s demonstrate this with an example. In the Star Wars model, we have an interface Character
that has many sub-types. Some of them has additional properties that are not present in the parent:
Loading...https://swapi-platform.ontotext.com/graphqleyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJNODctcWV3SldXTWRMRjIzNUtXUmluTlp4TDA0ZngzIn0.eyJhdWQiOiI2NzJjYTdiMy1jMzcyLTRkZjMtODJkOC05YTFhMGQ3ZDY4YzEiLCJleHAiOjE3MjkyNDk4MTksImlhdCI6MTY5ODE0NTgxOSwiaXNzIjoic3dhcGktcGxhdGZvcm0ub250b3RleHQuY29tIiwic3ViIjoiZTlmOWQzNGQtZThmMS00ODM1LTlkMzAtOWRjNmU5YjQ4ZmMzIiwianRpIjoiODZjNTIzYzEtYzQzNC00MWZiLWFkOTctYWU2MDY5MjgxYWM4IiwiYXV0aGVudGljYXRpb25UeXBlIjoiUEFTU1dPUkQiLCJlbWFpbCI6InJlYWRvbmx5dXNlckBleGFtcGxlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJSZWFkT25seVVzZXIiLCJhcHBsaWNhdGlvbklkIjoiNjcyY2E3YjMtYzM3Mi00ZGYzLTgyZDgtOWExYTBkN2Q2OGMxIiwicm9sZXMiOlsiUmVhZE9ubHkiXSwiZGF0YSI6e319.yVwuhsZQQgbk6ASaaA5iS2z_E7ThqPpMtYKfxjVcND8truequery planetHumanResidentsWithFriendsOrDroidsWithPrimaryFunctionOrWookiee{ planet(where: {resident: { _ifHuman: {friend: {}}, _ifDroid: {primaryFunction: {}}, _ifWookiee: {}} } ) { name resident { name ... on Human { friend { name } } ... on Droid { primaryFunction } } } }
If we run the example, we would get:
- All
Humans
that have any friends- All
Droids
with set primary function- All
Wookiees
As we can see, the type selector allows accessing concrete properties for the type, as well as filtering the objects from the same type.
As the sub-types are disjoint and we combine multiple type selectors, they all are grouped with implicit OR
along with any common filters that apply for all of them.
Note
Multiple type selectors are grouped with implicit OR
along with any common filters that apply for all of them.
Filtering Literal Values¶
Standardized language tags are used in HTML, XML, RDF, and various other web standards. They reuse ISO 639 2-letter and 3-letter language codes, and add extra codes for scripts, regions, and other traits (e.g., “dialects”). The format and handling of language tags is specified in the Best Current Practice 47 (BCP47) Tags for Identifying Languages, IETF Network Working Group, Sep 2009.
Literal values can be filtered using the filter syntax described in the section Filtering Object Lists, while literal language has a different syntax that will be covered in the current section.
We consider the following features for various operations:
Fetch the values of a field. This includes restriction of the returned languages, setting a preference order, obtaining the first value according to this order, or all matching values.
For more information, see the Language Fetching tutorial.
Filter by the values of a field so that the parent object has values and/or does not have values with specified languages.
For more information, see the Language Filtering tutorial.
Validate values during create/update (mutation) in order to restrict certain languages or ensure uniqueness per language.
For more information, see the Literal Properties Validation tutorial.
Implicit lang: allows to omit the lang tag on insert (mutation).
Language Fetching¶
The Ontotext Semantic Objects use a specially formatted language string to specify language tags and a preference order for fetching values.
Language elements:
lang
: exact language match, e.g.,en
oren-US
lang~
: language and its “dialects”, i.e., prefix match at the end of a language tag component, for exampleen~
~
: match any non-empty language, i.e., values withrdf:langString
typeNONE
: match values without language tag, i.e., values withxsd:string
typeANY
: match any language tag, including empty language. Note that this is nearly the same but not equivalent to~,NONE
because that prefers non-empty language first.BROWSER
: match language tags passed via the HTTPAccept-Language
header. The keyword could be used for fetching and ordering the results. For more information, see the HTTP Accept-Language section.
Exclusions: these discard values with the indicated language:
-lang
: exclude this language, e.g.,-en
or-en-US
-lang~
: exclude this language and any of its “dialects”, e.g.,-en~
-~
: exclude all non-empty languages so it will match values without a language tag-NONE
: exclude values without a language tag-ANY
is not allowed because it would forbid all values-BROWSER
is not allowed
A sequence of elements can also be specified:
- By default, there are no restrictions on
lang
, so ALL values are returned.- If you specify
lang
, then only the first value with matching language is returned.
- Use
lang: "ANY"
to return a single value, regardless of its language (or whether it has a language at all).- Use
ALL
as first element (with trailing colon:
) to return all values with matching languages (e.g.,ALL:en,fr
should return all values in English and French). If you use this, the order of languages does not matter, and you should not have generic tags that subsume more specific tags (e.g.,ALL:en-GB,en-GB~
should not appear).
- If you use
ALL:ANY
, then do not use any other language.lang1,lang2,lang3
: comma-separated sequence of languages in preference order.
- You should list more specific tags earlier (e.g.,
en-GB,en-GB~
oren,en~
), else they will have no effect.- There should be no duplicates.
-lang1,-lang2,-lang3
: comma-separated set of exclusions. All are checked, so their order does not matter (and they are customarily specified last). Each exclusion should be less general than any specified language, or it will prevent the language from having an effect. For example,en-GB,en,-en~
makes no sense because the exclusion kills the two preceding languages.BROWSER
: theAccept-Language
header (see HTTP Accept-Language) is parsed, ordered by specificity, then byq
value, converted tolang~
ranges, and inserted instead of theBROWSER
keyword.
- The lang spec is validated as described above (duplicates, lang subsumption and exclusions) before the BROWSER element is replaced, because the
Accept-Language
header is under user control, not under SOML designer’s control.- If the request does not have such header or the value of the header is invalid then the
BROWSER
keyword is ignored. In this case the following behavior could be expected:
lang: "ALL:BROWSER"
will have the same effect aslang: "ALL"
and will fetch all possible valueslang: "BROWSER"
will have the same effect aslang: "~"
and will fetch the first found languageorderBy: {desc: {lang: "BROWSER"}}
will have undetermined order result
In order to use any of the above to filter the returned literal values, the fetch spec needs to be used on a lang
argument for the given property like in the example below. It returns all characters and a single description in German, or, if no German language description is present, in English.
query charactersWithGermanDescription { character(where: {desc: {}}) { name desc(lang: "de,en") { value lang } } }
Here are some examples of language specs that return one value (or no values). “First” means the first value that matches a condition. In case there are several, one is picked at random.
Language Spec | Returns one value |
---|---|
ANY |
first value with any language (or no language) |
~,NONE |
first value with non-empty language, then no language |
en |
first English-language value |
en,fr |
first English-language value, then a French-language value |
en-CA,en~,fr~ |
first en-CA, then any English “dialect”, then any French “dialect” |
en-CA,en~,~ |
first en-CA, then any English “dialect”, then any non-empty language |
en-CA,en~,ANY |
first en-CA, then any English, then any value |
en-CA,en~,~,NONE |
first en-CA, then any English, then any non-empty language, then empty language |
en,NONE |
first value in English, then a pure string (no language tag) |
NONE |
first pure string (no language tag) |
NONE,-~ |
same, but more verbose |
~ |
first value that has a non-empty language |
-NONE |
same |
~,-NONE |
same, but more verbose |
-fr |
first value that is not in French |
-fr~ |
first value that is not in any French dialect |
BROWSER,NONE |
first value based on the user preferences or empty language |
Examples of language specs that return many values. The language order is irrelevant.
Language Spec | Returns many values |
---|---|
(none) | return all values |
null |
same - return all values |
ALL |
same, but more verbose |
ALL:ANY |
same, but even more verbose |
ALL:en |
all English-language values |
ALL:en~ |
all English-language or English “dialect” values |
ALL:~ |
all values with language tag |
ALL:NONE |
all values without language tag (pure strings) |
ALL:en~,-en-US |
all English-language or English “dialect” values except American English |
ALL:BROWSER,en~ |
all user preferred languages or English-language or English “dialect” |
Note
When BROWSER
keyword is used with ALL
, the language weights that come with the Accept-Language
HTTP header are ignored and the order of the results is undetermined.
Examples of invalid language specs:
Language Spec | Error |
---|---|
-ANY |
You cannot use language exclusion -ANY because that forbids all values |
ALL:ANY,en |
Language en is subsumed by ANY so it has no effect in ALL matching mode |
ALL:en,en~ |
Language en is subsumed by en~ so it has no effect in ALL matching mode |
en,ALL,fr |
Language mode ALL is allowed only in first position |
en~,en-GB |
Language en-GB is more specific than en~ but comes later in the list so it has no effect |
en~,en-GB~ |
Language en-GB~ is more specific than en~ but comes later in the list so it has no effect |
en,fr,bg,en |
Language en is specified more than once |
en-GB,en,-en~ |
|
HTTP Accept-Language¶
The HTTP protocol uses an Accept-Language
header defined in RFC 2616 Section 14.4 and RFC 3282.
It is based on RFC 4647 and allows the HTTP client (i.e., browser) to:
- Specify languages acceptable to the user
- Use “basic lang range” (prefix) matching
- Match the most specific (longest) range first
- Use wildcard (
*
) to match any non-empty lang tag - Specify lang precedence by using quality values (
q=
); the default is 1.0.
Below are some examples and their interpretation:
Accept-Language | Interpretation: lang (quality) |
---|---|
da , en-GB;q=0.8 , en;q=0.7 |
Danish (1.0), British English (0.8), other English (0.7) |
bg;q=0.1 , en-GB;q=0.9 , en;q=1.0 |
British English (0.9), other English (1.0), Bulgarian (0.1) |
*;q=0.1 , en;q=1.0 |
Any English (1.0), any other (0.1) |
*;q=1.0 , en;q=0.1 |
Any English (0.1), any other (1.0) |
*;q=1.0 or just * |
Any language (1.0) |
(no value/missing header) | Ignored |
In these interpretations, lang ranges are first ordered by specificity, then by quality value.
Please note that examples 2 and 4 do not make a lot of sense since they give more preference to a less specific lang range:
- Example 2 says “prefer any English to British English” but any does include British English.
- Example 4 says “prefer any language to English” but any does include English.
In order to access the HTTP header value, the BROWSER
keyword must be used.
The header value, if present, is parsed, ordered by specificity, then by q
value, converted to lang~
ranges, and inserted instead of the BROWSER
keyword.
- The language spec is validated as described in the previous Language Fetching section (duplicates, lang subsumption, and exclusions) before the
BROWSER
element is replaced, because theAccept-Language
header is controlled by the user and not by the designer of the SOML. - If the request does not have such a header or the value of the header is invalid, then the
BROWSER
keyword is ignored. In this case, the following behavior can be expected:lang: "ALL:BROWSER"
will have the same effect aslang: "ALL"
and will fetch all possible values.lang: "BROWSER"
will have the same effect aslang: "~"
and will fetch the first found language.orderBy: {desc: {lang: "BROWSER"}}
will have undetermined order result, as for the ordering functionality to work properly, it needs a single value to be selected (preferably in the same language). To minimize the impact of the missing header, add a default to your sort argument, such asorderBy: {desc: {lang: "BROWSER,en"}}
.
The following example demonstrates the use of the BROWSER
keyword and the HTTP Accept-Language
header.
Consider the following SOML schema:
objects:
skos:Concept:
props:
skos:prefLabel: {max: inf, range: stringOrLangString}
skos:definition: {max: inf, range: stringOrLangString}
Assume the following data:
<https://nomenclature.info/nom/5313>
a skos:Concept;
skos:prefLabel
"Two-Handed Crosscut Saw"@en,
"Godendard"@fr-CA,
"Passe-partout"@fr;
skos:definition
"A tool consisting of a stationary, wide, heavy, serrated blade..."@en,
"Outil composé d'une longue lame dentelée à dos convexe..."@fr.
You can use it to fetch a concept with values for its multi-lingual properties based
on the Accept-Language
HTTP header with the following query:
query {
skos_Concept(ID:"https://nomenclature.info/nom/5313") {
skos_prefLabel (lang:"BROWSER,en") {value lang}
skos_definition(lang:"ALL:BROWSER") {value lang}
}
}
It will return:
skos:prefLabel
- the first value that matches the header value or English valueskos:definition
- all values matching the header value
Let’s assume the BROWSER Accept-Language
is set to "fr, fr-CA"
. This will effectively set the query lang
argument to:
query {
skos_Concept(ID:"https://nomenclature.info/nom/5313") {
skos_prefLabel (lang:"fr-CA~,fr~,en") {value lang}
skos_definition(lang:"ALL:fr~") {value lang}
}
}
Note that for the skos_definition
fetching language pattern the fr-CA~
is ignored, as it is included in the fr~
spec.
Then the following response is returned:
{
"data": [{
"skos_Concept": {
"skos_prefLabel": [
{"value": "Godendard", "lang": "fr-CA"}
],
"skos_definition": [
{"value": "Outil composé d'une longue lame dentelée à dos convexe...", "lang": "fr"}
]
}
}]
}
Now let’s assume the HTTP header Accept-Language
is missing. The following response will be returned:
{
"data": [{
"skos_Concept": {
"skos_prefLabel": [
{"value": "Two-Handed Crosscut Saw", "lang": "en"},
],
"skos_definition": [
{"value": "A tool consisting of a stationary, wide, heavy, serrated blade...", "lang": "en"},
{"value": "Outil composé d'une longue lame dentelée à dos convexe...", "lang": "fr"}
]
}
}]
}
If the lang
pattern with``BROWSER`` is applicable for ordering, like in the example below, only the first value of the pattern will take effect.
query {
skos_Concept(lang: "BROWSER,en", orderBy: {skos_prefLabel: {dir: DESC}}) {
skos_prefLabel {value lang}
skos_definition(lang:"ALL:BROWSER") {value lang}
}
}
Let’s assume the BROWSER
Accept-Language
is set to "fr, fr-CA"
again. This will set the effective query lang
arguments as in the example below.
query {
skos_Concept(orderBy: {skos_prefLabel: {lang: "fr-CA~", dir: DESC}}) {
skos_prefLabel(lang: "fr-CA~,fr~,en") {value lang}
skos_definition(lang:"ALL:fr~") {value lang}
}
}
For more information about result sorting, see the Ordered Object List section.
Note
When designing a SOML and language fetching, consider the case that the header value may not be passed and define reasonable defaults in case the value is not present.
The Semantic Objects provide some defaults for the application to work, but to prevent unexpected behavior, consider combining the BROWSER
keyword with other language qualifiers. For example, lang: "BROWSER,en~,NONE"
will allow the application to work for English speaking users even if they have not configured their regional settings.
Language Preference Order for Fetching¶
Language specs can be provided at different levels. The spec at a given level will apply to lower levels if they do not specify their own lang
fetching option. Consider the example:
query humanInEnglish { human(lang: "en") { name desc { value lang } film(lang: "it,de") { name desc { value lang } vehicle { name desc(lang: "de") { value lang } } } homeworld { name desc { value lang } } } }
In this example query, the language spec for fetching is applied at multiple levels:
- When applied at the query level, it will apply for all
Literal
properties. For our example, it means thatPlanet.desc
andPlanet.resident.homeworld.desc
will have only English language descriptions, if any.- When applied to a complex property like
Planet.film
, it overrides the upper level (the query in this case) and changes the default behavior for thePlanet.film.desc
to English, or, if an English language description is not present, to German.- When applied to a literal property’s
lang
argument, it will override any spec coming from an upper level. In our example, thePlanet.film.vehicle.desc
andPlanet.resident.desc
have their own language fetch specs, so they will be used for fetching the descriptions for these objects.
If the query does not define any language fetch spec (or lang: null
is provided), there are two possible outcomes:
- The values will be filtered based on the language fetch configuration in the SOML model for the
langString
orstringOrLangString
properties. For more information, see the SOML property language configurations.- All values will be returned.
Hint
Language preference is applicable not only for queries, but also for mutations. It can be used for the result part of the mutation the same way it is for the queries. For more information, check the Object creation section.
Language Filtering¶
While the previous section describes using language specs to fetch language-tagged values, here we will see how to filter objects by language-tagged values of a field. Make sure that the object has values and/or does not have values with specified languages.
Language specs for filtering are similar to language specs for fetching, but simpler:
- An object satisfies a language spec if it has at least one matching value.
- To find objects that do not have matching values, you cannot use exclusion (
-
). UseNOT
at the outer level (see examples below).- The mode is always
ALL
because all conditions are checked.ANY
is not allowed because it is a vacuous check.-ANY
is not allowed because it would exclude all objects.- The same conditions about language subsumption and exclusion compatibility apply as in the previous section.
BROWSER
is not allowed because it makes no sense to search for objects having a value in a user-determined language.
Language specs for filtering add the following features:
UNIQ
: find objects that do not have multiple values in the same language. This is intended to check SKOS Integrity Condition S14.-UNIQ
: find objects that have multiple values in the same language. This can be used to find and fix such objects.- These checks pertain to empty language tags.
- You can combine them with language tags to refine the list of languages being checked.
- The
UNIQ
check must come last and be separated with semicolon.
Examples of filtering by language spec:
GraphQL Query | Return objects that |
---|---|
{obj(where: {field: {lang: "en"}}) {...} |
have an English-language value |
{obj(where: {field: {lang: "en~,-en-US"}}) {...} |
have value in any English or “dialect” except American English |
{obj(where: {field: {lang: "-en-US"}}) {...} |
have a value in any language except American English (including empty language) |
{obj(where: {NOT: {field: {lang: "en-US"}}}) {...} |
do not have a value in American English |
{obj(where: {field: {lang: "UNIQ"}}) {...} |
do not have multiple values in the same language |
{obj(where: {field: {lang: "-UNIQ"}}) {...} |
have multiple values in the same language |
{obj(where: {field: {lang: "~;-UNIQ"}}) {...} |
have multiple values in the same non-empty language |
{obj(where: {field: {lang: "en;-UNIQ"}}) {...} |
have multiple values in English |
{obj(where: {field: {lang: "en~;-UNIQ"}}) {...} |
have multiple values in the same language, which is an English “dialect” |
{obj(where: {field: {value: {IRE: "foo"}, lang: "-UNIQ"}}) {...} |
have multiple values in the same language that match the string “foo” |
Examples of invalid language specs for filtering:
Language Spec | Error |
---|---|
ALL:-en |
Mode ALL is implied when filtering by language and should not be specified |
ANY,en |
ANY is not allowed when filtering by language because it is a vacuous check |
-ANY |
-ANY is not allowed when filtering by language because it would exclude all objects |
en,en~ |
Language en is subsumed by en~ so it has no effect |
en~,en-GB |
Language en-GB is more specific than en~ so it has no effect |
en~,en-GB~ |
Language en-GB~ is more specific than en~ so it has no effect |
en,fr,bg,en |
Language en is specified more than once |
en-GB,en,-en~ |
|
Examples:
All objects in the schema.yaml
have a multilingual property desc
, which can be used for trying the language filtering functionality.
Find all Characters
that have values with non-empty language:
query charactersWithNoneEmptyLangs { character(where: {desc: {lang: "~"}}) { name desc { value lang } } }
All Film
-s that have description in German, and we fetch only the German descriptions:
query filmsWithGermanDescription { film(where: {desc: {lang: "de"}}) { name desc(lang: "de") { value lang } } }
All Character
-s that have non-English description. Try removing the value fetching filter -en
to see how the response changes.
query characterWithNoneEnglishDescription { character(where: {desc: {lang: "~,-en~"}}) { name desc(lang: "-en") { value lang } } }
Find Character
-s that do not have unique language description. Try changing the filter to UNIQ
.
query characterWithNoneUniqueDescription { character(where: {desc: {lang: "-UNIQ"}}) { name desc { value lang } } }
Combine Multiple Arguments¶
To filter and constrain lists with more complex expressions, we can combine
where
, orderBy
, limit
, and offset
.
Let’s make some complex queries in order to fetch specific data.
Examples:
All characters
ordered in descending character name order, where the character
appeared in the film
A New Hope and the characters films
are filtered to only include A New Hope
with the character’s films
ordered in ascending releaseDate
order.
query charactersInDescendingNameOrderWhereFilmWasNewHopeOrderedByReleaseDate { character(orderBy: {name: DESC}, where: {film: {name: {EQ: "A New Hope"}}}) { name film(orderBy: {releaseDate: ASC}, where: {name: {EQ: "A New Hope"}}) { name releaseDate } } }
Cycle Queries¶
GraphQL allows cyclic queries, such as the one shown below. They are virtually endless and can be considered DoS queries. To protect the database, we have added two limits:
sparql.endpoint.maxTupleResults
- maximum number of tuples that can be returned from the DB for one request property.- Default value is set to
5_000_000
. If it is exceeded, the query will be terminated and an error will be thrown. No data will be returned in this case as it is not possible to return a meaningful response.
graphql.query.depthLimit
- limit on the depth of the GraphQL query.- Default value is set to
15
. If it is exceeded, an error will be thrown notifying the user the query depth limit is 15.
query cyclicQuery { character { film { character { film { character { film { character { film { character { film { character { film { character { film { character { film { character { film { character { film { character { film { id } } } } } } } } } } } } } } } } } } } } } } }
Multiple Queries in a Request¶
If multiple queries are part of the same query
request, they are executed in parallel, and the individual responses are collated and returned.
You can fetch objects of different unrelated types in the same query.
query multipleRootObjects { film { name releaseDate } starship{ name cargoCapacity costInCredits } }
Variables in Queries¶
A GraphQL query can be parameterized with variables, maximizing query reuse, and avoiding costly string building in clients at runtime.
If not defined as constant, a variable can be supplied for an input value.
Variables must be defined at the top of an operation and are in scope throughout the execution of that operation.
Let’s try it out. Insert the following variables in the Query variables
section of the editor below:
{
"ids":["https://swapi.co/resource/vehicle/38","https://swapi.co/resource/vehicle/44"]
}
query starship_by_pilot_vehicle_id ($ids: [ID!]!) { starship(where:{ALL_EXISTS: {pilot: {vehicle: {ID: $ids}}}}, limit: 2) { id name pilot(orderBy: {name: DESC}) { id name vehicle(orderBy: {name: DESC}) { id name } } } }
In the example above, we have defined a variable ids
.
($ids: [ID!]!)
- here we define the variable and say that we expectID
to be passed for it.- And here is the usage of the variable in the query filter:
(where:{ALL_EXISTS: {pilot: {vehicle: {ID: $ids}}}}, limit: 2)
Fragment and Aliases¶
Fragments¶
Fragments are the primary unit of composition in GraphQL.
Fragments allow for the reuse of common repeated selections of fields, reducing duplicated text in the document. Inline Fragments can be used directly within a selection to condition upon a type condition when querying against an interface or union.
For example, if we want to fetch some common information about a film, we would have the following query:
query usingFragments { film(ID: "https://swapi.co/resource/film/1") { id name role { roleType person { name } character { name } } planet { id name resident { id name film { id name role { roleType person { name } character { name } } } } } } }
The repeated fields can be extracted into a fragment and composed by a parent fragment or query.
query usingFragments { film(ID: "https://swapi.co/resource/film/1") { ...commonFilmProperties planet { id name resident { id name film { ...commonFilmProperties } } } } } fragment commonFilmProperties on Film { id name role { roleType person { name } character { name } } }
Fragments are consumed by using the spread operator (…). All fields selected by the fragment will be added to the query field selection at the same level as the fragment invocation. This happens through multiple levels of fragment spreads.
query usingFragments { film(ID: "https://swapi.co/resource/film/1") { ...detailedFilmProperties planet { id name resident { id name film { ...commonFilmProperties } } } } } fragment commonFilmProperties on Film { id name role { roleType person { name } character { name } } } fragment detailedFilmProperties on Film { releaseDate desc { value lang } episodeId ...commonFilmProperties }
Inline Fragments¶
Fragments can be defined inline within a selection set. This is done to conditionally include fields based on their runtime type.
query film1 { film(ID: "https://swapi.co/resource/film/1") { id name character { type name ... on Droid { name id } ... on Human { name eyeColor skinColor } } } }
Note that the name
field is requested separately for character
, Droid
, and Human
, but it is returned only once for each character.
When more than one fields of the same name are executed in parallel, their selection sets are merged together when completing the value in order to continue execution of the sub‐selection sets.
Aliases¶
GraphQL Aliases allows you to rename the result of a field to anything you want.
Let’s say you want to have the same top level field in the same query with different arguments
We can achieve this by using alias for film
.
For example:
query usingAliases { Film1:film(ID: "https://swapi.co/resource/film/1") { id name releaseDate } Film2:film(orderBy:{episodeId:DESC}) { id name releaseDate episodeId openingCrawl } }
Aliases are necessary for the query to work. If you run the query without aliases, it will return an error:
query withoutAliases { film(ID: "https://swapi.co/resource/film/1") { id name releaseDate } film(orderBy:{episodeId:DESC}) { id name releaseDate episodeId openingCrawl } }
GraphQL Aliases are dynamic, written on the client making the request. This is a workaround for use cases where you want the selection set to be named more readable. It is not prudent to write this for every query from every client making this request for modifying trivial fields.
Query Data Control¶
Controlling how queries are evaluated is an important part of any SPARQL based database. As such, the Semantic Objects provide several capabilities that can affect query evaluation. The section below describes the following functionalities:
- Changing query dataset
- Changing the target repository
- Changing query inference
- Changing handling of owl:sameAs
Dataset selection¶
SPARQL offers ways for changing the dataset against which a given query is evaluated.
For queries, this is done using the FROM
keyword used to specify
what is included in the default dataset and which graphs to be included during query evaluation.
In GraphQL, this is represented as the from
query argument.
See more about SPARQL datasets in the SPARQL query specification here.
See more about SPARQL queries and datasets in the GraphDB documentation here.
Here is an example GraphQL query that specifies a source dataset when evaluating a query:
query {
object(from: "https://swapi.co/resource/humans") {
id
}
}
Note
GraphDB has a set of system named graphs controlling the query behavior that will also affect the GraphQL result. These special graphs can be used with the from
argument.
The complete list of special graphs can be found here.
Note
FROM NAMED
currently is not supported. If you need support for it, consider contacting the Platform Support.
Change repository¶
Along with changing the query dataset, GraphQL queries can also be used to change the target repository altogether. The only requirement is that the other repository is accessible on the same server address.
The target repository is specified using the repository
argument in GraphQL query like so:
query {
object(repository: "otherRepository") {
id
}
}
Alternatively, the target repository can be provided via the X-Repository
HTTP header. When supplied this way, the value will apply to all queries and mutations in the request.
Note
The query configuration has higher precedence over the request header value.
If security is enabled, it can also be read from the JSON Web Token (JWT) claim.
To enable this, the configuration sparql.endpoint.repository
must be defined as ${ctx.claims.<claim_key>:<default_repository>}
, where:
claim_key
is the name of the JWT claim from which the repository identifier can be readdefault_repository
is the repository to be used if no such key and value are found in the claims of the authenticated user. An example configuration that reads a claim namedrepository
and default repository namedsoaas
would look like this:${ctx.claims.repository:soaas}
.
The access to the repositories can be restricted by using the Semantic Objects configuration sparql.endpoint.repositoryWhitelist
. If not empty, the only accessible repositories will be the ones listed there.
It can also be used to effectively disable the functionality completely by listing the only one available repository like so:
sparql.endpoint.repository: soaas
sparql.endpoint.repositoryWhitelist: soaas
If no specific information about the target repository is provided in the query or the HTTP header, the repository value will be taken from the SOML configuration, if available. The SOML schema configuration looks like this:
config:
repository: soaas
If the configured SPARQL endpoint server has security enabled, the configured user must have access to all repositories that they need to access.
Inference¶
The default behavior of the Semantic Objects (unless specified otherwise) is to include the inferred statements from the underlying repository when evaluating the queries and mutations.
See more about inference and inferred statements here.
In each query, the includeInferred
parameter can be used to change the inference for that particular query:
query { object(includeInferred: false) { id name } }
The HTTP header X-Include-Inferred: false
can also be used to disable the inference for the entire GraphQL request.
Note
The query configuration has higher precedence over the request header value.
Note
This configuration is applicable for any RDF4J-based endpoints.
The way inferred statements are included in the query evaluation can also be changed at SOML schema level in the config section.
The SOML config value will be applied if there is no explicit override in a request via a query argument or an HTTP header.
config: includeInferred: false
Expand over owl:sameAs¶
Note
The following section is applicable only if the Semantic Objects communicate with a GraphDB repository.
The default behavior of the Semantic Objects (unless specified otherwise) is to join results for subjects that are linked with the owl:sameAs
predicate when evaluating the queries and mutations, but only if the support for it is enabled at repository and ruleset level.
See more about owl:sameAs
and how it is implemented in GraphDB here.
The default behavior for owl:sameAs
expansion can be configured at SOML schema level in the config section.
The value there will be applied if a particular request does not override it explicitly.
config: expandOwlSameAs: true
In each query, the parameter expandOwlSameAs
can be used to change the owl:sameAs
behavior for that particular query.
query { object(expandOwlSameAs: false) { id name } }
The HTTP header X-Expand-Over-Owl-SameAs: false
can also be used to disable the owl:sameAs
resolution for the entire GraphQL request.
Note
The query configuration has higher precedence over the request header value.
An alternative to the argument expandOwlSameAs: false
is to use from: "onto:disable-sameAs"
as this is the same behavior that the Semantic Objects apply under the hood.
query { object(from: "onto:disable-sameAs") { id name } }
The default behavior for owl:sameAs
expansion could be configured on SOML schema level in the config section.
The value there will be applied if a particular request does not override it explicitly.
config: expandOwlSameAs: true