This
page
is
part
of
the
Continuous
Integration
Build
of
FHIR
Specification
(v5.0.0:
R5
-
STU
).
This
is
the
current
published
version
in
it's
permanent
home
(it
will
always
(will
be
available
incorrect/inconsistent
at
this
URL).
For
a
full
list
of
available
versions,
see
times).
See
the
Directory
of
published
versions
.
Page
versions:
R5
R4B
R4
Responsible
Owner:
FHIR
Infrastructure
Work
Group
|
Standards
Status
:
|
GraphQL
is
a
query
language
for
APIs
and
a
runtime
for
fulfilling
those
queries
with
your
existing
data.
This
page
describes
how
to
use
GraphQL
with
FHIR.
The
GraphQL
interface
may
be
implemented
by
any
server,
and
may
be
provided
as
a
facade
service
in
front
of
a
conformant
RESTful
API.
For
GraphQL
documentation,
see
http://graphql.org
.
Implementation Note: This page is a draft. For ongoing discussion, see chat.fhir.org
.
Implementers
should
note
that
GraphQL
is
not
a
formal
standard,
and
no
standards
path
has
been
described
for
it.
At
present,
GraphQL
is
copyright
by
Facebook
,
and
licensed
under
a
standard
BSD-3
license.
The
GraphQL
language
is
still
under
development.
The graphQL functionality defined here has a matching schema .
The standard end points for graphQL are as defined on the $graphql operation :
[base]/$graphql
A System level query. The query must start by selecting a resource type and some search criteria, as defined below .
[base]/[Type]/[id]/$graphql
A Resource Instance level the query assumes a single resource is in scope, and just queries on the data available in the given resource.
GraphQL
can
be
invoked
by
get
with
a
query
parameter,
or
a
POST
with
the
graphQL
as
the
body,
or
a
JSON
body.
(see
the
GraphQL
documentation
).
The mime type of the response is application/json. Other formats are not described by the specification. The mimetype is *not* application/fhir+json - the response is not a FHIR resource, though it may look like one closely.
Servers that conform to FHIR/GraphQL specification:
Note that most servers only provide a subset of the full functionality described by the FHIR interface. Where servers support FHIR features, and implement GraphQL, they must make them available as defined by this page, but these rules do not require that servers implement all (or even any) of the functionality defined here. Also, these rules do not prevent servers providing additional end-points, queries or mutations that provide additional functionality.
Clients that use the FHIR/GraphQL specification make requests using graphQL statements that select subsets of the resources to retrieve. Clients SHOULD always be retrieving mandatory and modifier elements and checking their values (see the safety checklist ).
With regard to handling errors, FHIR GraphQL servers:
A graphQL error response with an OperationOutcome looks like this:
{
"data": null,
"errors": [
{
"extensions": {
"resource" : {
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "error",
"code": "exception",
"diagnostics": "500: Internal server error"
}
]
},
},
"message": "500: Internal server error"
}
]
}
The
error
response
SHALL
include
at
least
one
error.
Each
error
SHALL
include
a
message
,
and
MAY
include
the
graphQL
locations
and
path
properties.
Each
error
SHOULD
include
an
OperationOutcome
in
the
resource
property
in
the
graphQL
extensions
element.
Note
that
in
this
usage,
there
MAY
be
multiple
OperationOutcome,
one
for
each
errors
item,
with
one
issue
matching
the
message.
Any
FHIR
defined
field
can
be
used
directly
e.g.
e.g.,
this
graphql
against
the
Patient
resource
(r3)
{
name { text given family }
}
Example:
http://test.fhir.org/r5/Patient/example/$graphql?query={name{text,given,family}}
(note:
examples
are
only
informative).
Polymorphic
fields
are
represented
by
their
JSON
property
name
E.g.
e.g.,
for
Observation.value[x]:
{
valueQuantity { value unit }
}
Example:
http://test.fhir.org/r5/Observation/example/$graphql?query={valueQuantity{value,unit}}
(note:
examples
are
only
informative).
Note: This is because the leaf names have to correspond to scalar types, so there is no use selecting all the variants at once
Extensions
on
primitives:
the
JSON
convention
for
primitives
is
observed.
e.g.
e.g.,
use
_[name]
for
accessing
extensions
on
primitives.
So
{
birthDate _birthDate { extension {valueDateTime} }
}
results in
{
"birthDate":"2016-05-18",
"_birthDate":{
"extension":[{
"valueDateTime":"2016-05-18T10:28:45Z"
}]
}
}
Example:
http://test.fhir.org/r5/Patient/example/$graphql?query={birthDate,_birthDate{extension{valueDateTime}}}
(note:
examples
are
only
informative).
Primitive fields SHALL NOT have any arguments at all. Complex fields may have one of more of the following parameters, all of which help select a subset of a repeating element:
fhirpath
-
a
FHIRPath
statement
selecting
which
of
the
subnodes
is
to
be
included
[field]
-
the
name
of
a
sub-property
with
a
specified
value
that
must
be
matched
for
the
field
to
be
included
_offset
-
specify
the
offset
to
start
at
for
a
repeating
element
(see
below)
_count
-
specify
how
many
to
elements
to
return
from
a
repeating
list
FHIRPath:
Use a FHIRPath statement selecting which of the set of notes in a list is to be included:
{
name(fhirpath: "family.exists()") { text given family }
}
Example:
http://test.fhir.org/r5/Patient/example/$graphql?query={name(fhirpath:%22family.exists()%22){text,given,family}}
(as
compared
to
http://test.fhir.org/r5/Patient/example/$graphql?query={name{text,given,family}}
)
(note:
examples
are
only
informative).
Field Filter:
Not all systems support FHIRPath, so a simpler syntax is provided, where the client specifies a single sub-element by name, and a specified value that must be matched for the field to be included:
{
name(use: official) { text given family }
}
Example:
http://test.fhir.org/r5/Patient/example/$graphql?query={name(use:official){text,given,family}}
(note:
examples
are
only
informative).
One way this can be used is to select particular extensions:
{
myext: extension(url: "http://myextension.url/details") { value : valueString }
}
will result in
{
"myext" : {
"value" : "some value"
}
}
List offsets: _offset and _count
For
some
large
resources,
it
may
be
desired
to
select
only
a
subset
of
a
long
list
of
elements,
and
to
make
repeated
requests
reading
further
into
the
list
as
long
as
required.
This
can
be
done
with
the
_count
and
offset
filters:
{
entry(_count: 5, _offset: 5) { deleted item { reference } }
}
Example:
http://test.fhir.org/r5/List/long/$graphql?query={entry(_count:5,_offset:5){deleted
item{reference}}}
(note:
examples
are
only
informative).
This will select the second set of 5 entries in the nominated List resource. Clients can use this approach to iterate through a list. If a filter is applied to this (as documented above), the offset and count apply to the filtered list. Clients would iterate the list until there are no more entries returned.
An
object
of
type
Reference
can
have
an
additional
selection
resource
.
This
is
an
instruction
to
the
server
to
resolve
the
reference,
and
then
include
the
contents
of
the
resource
as
specified
by
sub-selections
in
the
property
name
"resource"
(can
be
aliased).
e.g.
e.g.,
On
Observation:
{
subject { reference, resource {active} }
}
The resource selector has two arguments:
optional
:
true
|
false.
(default
is
false).
If
the
server
cannot
resolve
the
reference
{
id
subject {
reference
resource {
...on Patient {
birthDate
}
...on Group {
name
}
}
}
code {coding {system code} }
}
Example:
http://test.fhir.org/r5/Observation/example/$graphql?query={id,subject{reference,resource{...on%20Patient{birthDate}...on%20Practitioner{practitionerRole{speciality}}}}code{coding{system,code}}}
(note:
examples
are
only
informative).
but slightly denser:
{
id
subject {
reference
resource(type : Patient) { birthDate }
resource(type : Practitioner) { practitionerRole { speciality } }
}
code {coding {system code} }
}
Example:
http://test.fhir.org/r5/Observation/example/$graphql?query={id,subject{reference,resource(type:Patient){birthDate}resource(type:Practitioner){practitionerRole{speciality}}}code{coding{system,code}}}
(note:
examples
are
only
informative).
Clients can use either approach - type selection as a parameter, of using a fragment type condition - the first is shorter while the second aligns with the GraphQL schema more explicitly.
When a GraphQL statement is run at the system level, rather than against a particular resource, the first thing the query must do is select the resource(s) of interest. The logic of this follows the FHIR search API, but reimplements in a GraphQL centric way.
There are 3 ways to query, for a single resource, for a simple list of resources, and a full API. For a single resource, the client names the type of the resource, and provides an _id:
{
Patient(_id: example) { id, active }
}
This returns a single Patient with the name id. The output from this is a single resource:
{
"data" : {
"Patient" {
"id" : "example",
"active" : "true",
}
}
}
Example:
http://test.fhir.org/r5/$graphql?query={Patient(_id:example){id,name{given,family}}}
(note:
examples
are
only
informative).
Alternatively, the client can ask for a list of resources. Here, the client simply asks for a list of resources:
{
ConditionList(clinical_status: relapse, patient: example) { id, clinicalStatus }
}
This is a request to list all the Condition resources that have a status if 'relapsed' for the patient with id = example. The arguments are most of the search parameters defined on or for the specified resource. Notes:
The output of this is a list:
{
"data" : {
"ConditionList" : [{
"id" : "100",
"clinicalStatus" : "relapse"
},{
"id" : "100",
"clinicalStatus" : "relapse"
}]
}
}
Example:
http://test.fhir.org/r5/$graphql?query={PatientList(name:%22pet%22){name{family,given}}}
(note:
examples
are
only
informative).
Servers may reject the request if there are too many matches to return in a single request. If they do so, they SHALL return an error indicating that the query could not be fulfilled. (rather than silently filtering the list).
The
simple
list
approach
does
not
allow
for
the
management
of
long
lists.
To
do
this,
clients
are
able
to
request
a
Connection
based
approach
(based
on
http://graphql.org/learn/pagination/
,
but
adapted
to
the
existing
FHIR
Search
API).
{
ConditionConnection (clinical_status: active, patient: example) {
count offset pagesize
edges {
mode, score, resource { id, active }
}
first previous next last
}
}
The arguments are the same as for the simple List case, with the addition of the special argument 'cursor' (see below). The server returns a connection object that contains information about the search, along with a list of 'edges', one for each match. Each edge has 3 properties: mode, score (match the same properties on Bundle.entry.search) and "resource" which is the actual matches.
{
"data" : {
"ConditionConnection" : {
"count": 50,
"offset" : 0,
"pageSize" : 25,
"next" : "45f9ada8-db37-4498-ba7d-75a044668387:3"
"edges" : [{
"resource" : {
"id" : "100",
"clinicalStatus" : "relapse",
}
},{
"resource" : {
"id" : "100",
"clinicalStatus" : "relapse",
}
}]
}
}
}
Example
1:
http://test.fhir.org/r5/$graphql?query={PatientConnection(name:%22pet%22){count,offset,pagesize,first,previous,next,last,edges{mode,score,resource{name{family,given}}}}}
(note:
examples
are
only
informative).
Example
2
(cursor):
http://test.fhir.org/r5/$graphql?query={PatientConnection(){count,offset,pagesize,first,previous,next,last,edges{mode,score,resource{resourceType,id,name{family,given}}}}}}}}
(note:
examples
are
only
informative).
Notes:
The client can follow up on the first/previous/next/last links using the argument 'cursor':
{
ConditionConnection (_cursor : "45f9ada8-db37-4498-ba7d-75a044668387") {
count offset pagesize
edges {
id, clinicalStatus
}
first previous next last
}
}
Example:
http://test.fhir.org/r5/$graphql?query={PatientConnection(cursor:%225b0719b5-0f01-442e-9576-5b0514c19a:50%22){count,offset,pagesize,first,previous,next,last,edges{mode,score,resource{resourceType,id,name{family,given}}}}}}}}
(note:
examples
are
only
informative).
(note,
though,
that
to
make
this
one
work,
you
have
to
replace
the
cursor
token
with
one
that
you
got
from
the
link
above).
Notes:
The specification defines the 2 forms of searches to meet differing requirements. For the List search:
In
general,
clients
should
use
the
simple
search,
for
efficiency
purposes,
where
appropriate
(e.g.
(e.g.,
where
the
user
is
not
going
see
a
'next'
button).
This
particularly
applies
when
doing
reverse
reference
resolution.
It's
also
possible
to
use
search
is
a
special
mode,
doing
reverse
lookups
-
e.g.
e.g.,
list
all
the
resources
that
refer
to
this
resource.
An
example
of
this
use
is
to
look
up
a
patient,
and
also
retrieve
all
the
Condition
resources
for
the
patient.
This
is
a
special
case
of
search,
above,
but
with
an
additional
mandatory
parameter
_reference
.
For
example:
{
name { [some fields] }
ConditionList(_reference: patient) {
[some fields from Condition]
}
}
There must be at least the argument "_reference" which identifies which of the search parameters for the target resource is used to match the resource that has focus. In addition, there may be other arguments as defined above in search (except that the "id" argument is prohibited here as nonsensical)
The response for the query above would be
{
"name: [ [some fields] ],
"ConditionList" : [
{ [some fields from matching Condition resource] }
]
}
Example:
http://test.fhir.org/r5/Patient/example/$graphql?query={name{family,given}ConditionList(_reference:patient){id,clinicalStatus}}
(note:
examples
are
only
informative).
The
"connection"
based
search
option
is
also
supported,
as
described
above,
with
the
addition
of
_reference.
If
the
client
wishes
to
pursue
any
of
the
cursor
based
links
in
the
graphQL
results
it
asks
for
back,
then
it
initiates
this
a
new
separate
query
as
defined
above,
rather
than
repeating
the
nested
query.
I.e.
i.e.,
the
'cursor'
argument
is
prohibited,
except
at
the
root
of
query.
Example:
http://test.fhir.org/r5/Patient/example/$graphql?query={name{family,given}ConditionConnection(_reference:patient){count,offset,pagesize,first,previous,next,last,edges{mode,score,resource{...onCondition{resourceType,id,clinicalStatus}}}}}
(note:
examples
are
only
informative).
It's also possible to apply graphql to the results of other operations. This is done by adding the parameter "_graphql" when invoking the operation. e.g.
GET [base]/ValueSet/doc-typecodes/$validate-code?system=http://loinc.org&code=1963-8&display=test&_graphql={result:parameter(name:"result"){value:valueBoolean}}
Example:
http://test.fhir.org/r5/ValueSet/doc-typecodes/$validate-code?system=http://loinc.org&code=1963-8&display=test&_graphql={result:parameter(name:%22result%22){value:valueBoolean}}
(note:
examples
are
only
informative).
The graphQL is executed on the output of the operation. If the operation fails, and returns an operation outcome, then the graphQL is not executed.
GraphQL
is
a
very
effective
language
for
navigating
a
graph
and
selecting
subset
of
information
from
it.
However
for
some
uses,
the
physical
structure
of
the
result
set
is
important.
This
is
most
relevant
when
extracting
data
for
statistical
analysis
in
languages
such
as
R
.
In
order
to
facilitate
these
kind
of
uses,
FHIR
servers
should
consider
supporting
the
following
directives
that
allow
implementers
to
flatten
the
return
graph
for
easier
analysis
@flatten
This directive indicates that the field to which it is attached is not actually produced in the output graph. Instead, its children will be processed and added to the output graph as specified in its place.
Notes:
For an example, take this graphQL, and apply it to the patient example:
{
identifier { system value }
active
name { text given family }
}
This will give the output:
{
"identifier": [{
"system": "urn:oid:1.2.36.146.595.217.0.1",
"value": "12345"
}],
"active": true,
"name": [{
"given": ["Peter","James"],
"family": "Chalmers"
},{
"given": ["Jim"]
},{
"given": ["Peter","James"],
"family": "Windsor"
}]
}
Adding
the
@flatten
directive
changes
the
output:
{
identifier @flatten { system value }
active
name @flatten { text given family }
}
This has the output:
{
"system":["urn:oid:1.2.36.146.595.217.0.1"],
"value":["12345"],
"active":true,
"given":["Peter","James","Jim","Peter","James"],
"family":["Chalmers","Windsor"]
}
@first
This is a shortcut for a FHIR path filter [$index = 0] and indicates to only take the first match of the elements. Note that the selection of the first element only applies to the immediate context of the field in the source graph, not to the output graph
Example:
{
identifier @flatten { system value }
active
name @flatten { text given @first family }
}
Gives the output:
{
"system":["urn:oid:1.2.36.146.595.217.0.1"],
"value":["12345"],
"active":true,
"given":["Peter","Jim","Peter"],
"family":["Chalmers","Windsor"]
}
@singleton
This
directive
indicates
that
a
field
collates
to
a
single
node,
not
a
list.
It
is
only
used
in
association
with
fields
on
which
a
parent
has
@flatten
,
and
overrides
the
impact
of
flattening
the
parent
in
making
it
a
list.
The
server
SHALL
return
an
error
if
there
is
more
than
one
value
when
flattening
Extending
the
previous
example,
adding
@singleton
:
{
identifier @flatten { system @singleton value @singleton }
active
name @flatten @first { text given family @singleton }
}
Gives the output:
{
"system":"urn:oid:1.2.36.146.595.217.0.1",
"value":"12345",
"active":true,
"given":["Peter","James"],
"family":"Chalmers"
}
@slice(fhirpath)
This indicates that in the output graph, each element in the source will have "." and the result of the FHIRPath as a string appended to the specified name. This slices a list up into multiple single values. For example
{ name @slice(path: "$index") @flatten {given @first @singleton family}}
For a resource that has 2 names will result in the output
{
"Given.0" : "first name, first given",
"Family.0" : ["first name family name"],
"Given.1" : "second name, first given",
"Family.1" : ["second name family name"]
}
Other
uses
might
be
e.g.
e.g.,
Telecom
@slice(use)
to
generate
telecom.home
for
instance.
Notes:
@singleton
Examples:
{
identifier @flatten { system value }
active
name @flatten @slice(path: "use") { given family @singleton }
}
produces
{
"system":["urn:oid:1.2.36.146.595.217.0.1"],
"value":["12345"],
"active":true,
"given.official":["Peter","James"],
"family.official":"Chalmers",
"given.usual":["Jim"],
"given.maiden":["Peter","James"],
"family.maiden":"Windsor"
}
and
{
identifier @flatten { system value }
active
name @flatten @slice(path: "$index") { given family @singleton }
}
produces
{
"system":["urn:oid:1.2.36.146.595.217.0.1"],
"value":["12345"],
"active":true,
"given.0":["Peter","James"],
"family.0":"Chalmers",
"given.1":["Jim"],
"given.2":["Peter","James"],
"family.2":"Windsor"
}
Mutations are defined for the operations Create, Update, and Delete.
Create:
PatientCreate(res : Patient) {
returns a Patient
}
Like the API, the Patient resource might or might not have an ID; if it is present, the value is overwritten by the server.
Update:
PatientUpdate(id : ID, res : Patient) {
returns a Patient
}
Delete:
PatientDelete(id : ID) {
[no return]
}
The parameters are input types that are resources that exactly match the output types. If these operations fail, an http error is returned.
Todo: mutations for patch, batch, transaction?