Stream: implementers
Topic: GraphQL
nicola (RIO/SS) (Nov 29 2015 at 21:38):
Just to fire discussion:
https://github.com/facebook/graphql
https://github.com/Netflix/falcor
https://www.youtube.com/watch?v=ByNs9TG30E8
Martin Chavez Aguilar (Oct 06 2016 at 16:58):
Hi, I am wondering if the use of GraphQL - http://graphql.org is something that has been discussed in the past (in the context of FHIR), if not, who can I contact to start a discussion about it? (some part of the tech industry is moving wards this type of API)
Martin Chavez Aguilar (Oct 06 2016 at 16:59):
Hi, I am wondering if the use of GraphQL - http://graphql.org is something that has been discussed in the past (in the context of FHIR), if not, who can I contact to start a discussion about it? (some part of the tech industry is moving wards this type of API)
Grahame Grieve (Oct 06 2016 at 18:43):
looks interesting. this would be the place to ask
Rowan Foster (Oct 10 2016 at 00:14):
@Josh Mandel did a prototype around this a while back
https://github.com/FHIR-CN/gra-fhir-ql
nicola (RIO/SS) (Oct 12 2016 at 09:38):
+1. Looks like it solves real world problems (we are analyzed couple of our current projects on FHIR). We are going to support GraphQL in aidbox (after swagger:). In some way GraphQL is related to Compartments topic.
Patrick Werner (Oct 12 2016 at 20:14):
swagger
Abbie Watson (Oct 13 2016 at 04:02):
Meteor is currently supporting GraphQL integration in Meteor apps via the Apollo database proxy; so Clinical Meteor currently has partial support for it. We're waiting for GraphQL support in the Mongo shell before migrating the entire Clinical Meteor framework over to Apollo; but it's on the long term roadmap.
Grahame Grieve (May 18 2017 at 18:53):
I've started working on a graphql processor in my server, with the aim of clarifying what we need to say in the FHIR spec about a standard way of using graphql with FHIR
Grahame Grieve (May 18 2017 at 18:53):
I'm creating this thread to discuss things as I go along. @Josh Mandel at least is interested in this.
Grahame Grieve (May 18 2017 at 18:54):
let's start by how to invoke graphql... I think that it goes something like this:
Grahame Grieve (May 18 2017 at 18:56):
POST [base]/$graphql
POST [base]/[Type]/$graphql
POST [base]/[Type]/[id]/$graphql
Grahame Grieve (May 18 2017 at 18:57):
the nature of the queries/mutations supported depends on the scope at which it is implemented. e.g. if you invoke the graphql on an instance of a resource, the query has a known context and you don't specify a selection, where as if you invoke at a higher level, you have to provide a selection
Grahame Grieve (May 18 2017 at 18:58):
e.g. invoking at /Patient/example:
{ active, name, address, dateOfBirth }
Grahame Grieve (May 18 2017 at 18:59):
but invoking at /Patient:
{ Patient[id: example] { active, name, aaddress, dateOfBirth } }
Grahame Grieve (May 18 2017 at 19:00):
also, let's, for now, restrict ourselves only to queries, and get to talk about mutations later
nicola (RIO/SS) (May 18 2017 at 20:06):
:+1: @Grahame Grieve how do you deal with polymorphic elements and primitive extensions?
Grahame Grieve (May 18 2017 at 20:07):
don't know. that's one of many questions to be resolved
Josh Mandel (May 18 2017 at 21:38):
For polymorphic elements I'd consider just using the specified property names, like valueString
or valueCode
for Observation.value[x]
. For references that can use >1 type, I think we'd use object spreads like ... on Patient
or ... on Practitioner
to account for multiple possible types at a spot.
Josh Mandel (May 18 2017 at 21:39):
So for example I could query /Patient/123/Procedure
with:
Procedure { type { text } performer { actor { ... on Practitioner { name { given } identifier { system value } } } } } }
Josh Mandel (May 18 2017 at 21:42):
(deleted)
Grahame Grieve (May 18 2017 at 23:59):
note that Josh's example here autimatically walks across references. It's not clear that this is good for me - what does a server do with references that it can't resolve?
Grahame Grieve (May 19 2017 at 00:42):
also, there's the question of whether it is good to support compartment queries like this, given that most servers are not supporting them
Grahame Grieve (May 19 2017 at 09:50):
So let's see if we can get consensus on something simple. Say I perform the following query:
POST [base]/Patient/example/$graphql { identifier active name }
Grahame Grieve (May 19 2017 at 09:51):
then the correct response is
{ "identifier": [ { "use": "usual", "type": { "coding": [ { "system": "http://hl7.org/fhir/v2/0203", "code": "MR" } ] }, "system": "urn:oid:1.2.36.146.595.217.0.1", "value": "12345", "period": { "start": "2001-05-06" }, "assigner": { "display": "Acme Healthcare" } } ], "active": true, "name": [ { "use": "official", "family": "Chalmers", "given": [ "Peter", "James" ] }, { "use": "usual", "given": [ "Jim" ] }, { "use": "maiden", "family": "Windsor", "given": [ "Peter", "James" ], "period": { "end": "2002" } } ] }
Grahame Grieve (May 19 2017 at 09:51):
anyone disagree with that?
Grahame Grieve (May 19 2017 at 10:07):
less obvious question: is it relevant to talk about xml or turtle responses to graphQL?
Grahame Grieve (May 19 2017 at 11:54):
hmm no. fields must represent primitive values...
Grahame Grieve (May 19 2017 at 12:07):
does anyone know what this, in the GraphQL spec means?
Serialization formats which can only represent unordered maps should retain this order grammatically (such as JSON).
John Moehrke (May 19 2017 at 13:16):
Might this be a good solution for more complex Privacy Consent rules? That is to support cases where the patient wants to blind a specific type of clinical condition, or specific episode, etc? I would like if the Consent resource could be more simple, and leverage a construct that is designed to do complex selection for more complex privacy needs.
Grahame Grieve (May 19 2017 at 17:34):
I'm not sure how a query format would solve consent problems. I'm looking forward to it making things worse :-(
Abbie Watson (May 19 2017 at 18:32):
Have you all taken a look at Mostafa Sholkamy's gql-fhir tool? It uses the Apollo graphQL libraries, which I can attest are getting very good attention and work on.
https://github.com/shalkam/gql-fhir/tree/master
Grahame Grieve (May 19 2017 at 19:00):
hadn't seen it before. @Mostafa Sholkamy are you tracking this topic?
Eric Haas (May 19 2017 at 22:37):
In the bigger picture context? Could this replace parts of the FHIR API ( specifically _query ) in R4 or is it a supplementary piece that is outside of the FHIR specification.
Josh Mandel (May 20 2017 at 00:47):
_query is designed to provide more expressive ways of matching resources in a query; graphql is more focused on describing what properties to return and what links to follow from the resources that match (though there is certainly some overlap).
Mostafa Sholkamy (May 20 2017 at 01:34):
Hi,
First let's talk about GraphQL for little.
Now for developers building new APIs, using REST style API - I can say - is no longer a thing
http://nordicapis.com/is-graphql-the-end-of-rest-style-apis/
Currently to develop a FHIR app using GraphQL will make it automatically non compliant with the FHIR specs.
FHIR is adopting RESTful style API with a HTTP endpoint for each resource because it was a standard way in the industry to APIs back then.
Of course that was before GraphQL come into the play, as oppose to REST; GraphQL is all about having a single HTTP endpoint for all your requests to save user having multiple round trips to get the data he wants.
You can imagine it like writing a MYSQL query against a database except that it is using GraphQL query language and it sends the query string over HTTP.
So doing something like this :
POST [base]/$graphql
POST [base]/[Type]/$graphql
POST [base]/[Type]/[id]/$graphql
is not okay or necessary according to GraphQL standards ( it's all about a single HTTP endpoint )
Now I will talk about my project a little bit, how I am implementing GraphQL for FHIR.
I am using my own JSON parser - not complete yet -to convert Structure definitions into a GraphQL schema.
What my project does:
- It can handle all the CRUD operations for the supported resouces.
What my project does not:
- Because of my lack of understanding for FHIR - especially the infrastructure part - it doesn't handle searches, bundles and conformance stuff I can say the whole infrastructure part is yet to be done.
Looking forward to knowing your thoughts about this.
Regards,
Mostafa
Eric Haas (May 20 2017 at 01:54):
I thought that Graphql returns only properties from resources and not the entire resources and is a shortcut for _revinclude or _include or a _query. E.g., I could get all the practitioner names for a patient A using something like this...
Eric Haas (May 20 2017 at 01:54):
{
Patient {
name
Practitioner{
name
}
}
}
"data": { "Patient": { "name": "A", "Practitioner": [ { "name": Dr X" }, { "name": Dr Y" }, { "name": "Dr Z" } ] } } }
Mostafa Sholkamy (May 20 2017 at 02:09):
@Eric Haas GraphQL is all about getting the exact result a defined in the query string, it does not care about how we do it or what's going under the hood in the server
Josh Mandel (May 20 2017 at 02:28):
But the semantics of graphql require that you can define your "entry points" for a query and can start from the there, right @Mostafa Sholkamy? For example, if I wanted to get a list of blood pressures and conditions for a given patient, this is readily expressed with graphql (well, if we assume what FHIR would call "reverse" relationships from Patient to Condition, and from Patient to Observation -- note that natively FHIR defines these relationships in the other direction, and we'll probably want to define both directions in a graphql mapping). But I can't use graphql to say "find me list of patients who have had an elevated blood pressure reading and also have a diagnosis of hypertension". In other words, it's not a graph search paradigm so much as filtered subgraph retrievable. Is that fair?
Grahame Grieve (May 20 2017 at 02:46):
I think that there's 2 things at play here - one is using graphQL, and the other is changing your patterns.
Grahame Grieve (May 20 2017 at 02:47):
These:
GET base/Patient/example/$graphql?q={name link active}
Grahame Grieve (May 20 2017 at 02:48):
and
GET base/$graphql?q={Patient[id:example] {name link active}}
Grahame Grieve (May 20 2017 at 02:48):
are synonymous. That doesn't mean that the first has no use, or that the second is going to replace RESTful URLs and make them redundant
Grahame Grieve (May 20 2017 at 02:50):
@Josh Mandel you can use graphQL to say what you said, if we define it accordingly. But it's not inherent in graphql - it would be for us to define how that kind of search functionality is made available
Josh Mandel (May 20 2017 at 03:38):
Do you mean by defining some clever set of arguments, in something akin to chained search? Like Patient("_has:Procedure:patient.code":"123"){}
Sure, but I guess my point is is then it's not some new or newly-expressive graph-based model for query, it's just packing dots into a string argument. (Also graphql is nicely typed, which is awesome but I don't know if you can get this much flexibility without explicitly naming every allowed argument.)
Josh Mandel (May 20 2017 at 03:41):
Arguments within inner blocks don't change the behavior of the outer blocks, so you can't achieve this kind of query with nested graphql blocks.
Grahame Grieve (May 20 2017 at 06:36):
well, I was more thinking Patient(search: "[_filter string]") { fields..} where search is as specified here: http://hl7.org/fhir/search_filter.html
Grahame Grieve (May 20 2017 at 14:03):
for those tracking this discussion - I just created a first test case on this, in subversion - \build\tests\graphql.
Grahame Grieve (May 20 2017 at 14:03):
it says that if you execute this qraphql
{ identifier { system value } active name { text given family } }
Grahame Grieve (May 20 2017 at 14:03):
against the resource context Patient/example (e.g. [base]/Patient/example/$graphql)
Grahame Grieve (May 20 2017 at 14:04):
then the correct output is
{ "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" }] }
Grahame Grieve (May 20 2017 at 14:05):
btw. I think that there's a pretty simple answer to the question of omitting mandatory attributes: the output of graphql is not expected to be resources, it's a view on them
Grahame Grieve (May 20 2017 at 14:06):
can we all agree that if you execute this graphql against that resource, that's the correct outcome?
Grahame Grieve (May 20 2017 at 14:11):
if we can all agree to that, then the next things to work on are:
- polymorphic fields
- field filters and directives
- extensions in primitive fields / schema reconciliation
- forward reference resolution
- searching resources (.e.g context [base]/$graphql)
- backwards reference resolution
- mutations
(in that approximate order)
Josh Mandel (May 20 2017 at 14:42):
well, I was more thinking Patient(search: "[_filter string]") { fields..} where search is as specified here: http://hl7.org/fhir/search_filter.html
Sure. Again, just emphasizing that graphql doesn't provide a new model for graph search. It lets us use our existing models.
Josh Mandel (May 20 2017 at 14:49):
For forward reference resolution, I'd like to suggest that we just use a "resource" field within any reference, like MedicationRequest { patient { resource {active} } }
-- this preserves access to the reference's display and value fields.
Josh Mandel (May 20 2017 at 15:01):
For reverse references, one option to consider is constructing names from "Source type" + underscore + "search parameter name". Like, to get conditions pointing to a patient, you might say Patient { Condition_patient { id} }
. This feels a bit clumsy, but it's at least simple.
Josh Mandel (May 20 2017 at 15:09):
If it were possible to refer to fields in a parent result, we could do something a bit cleaner like Patient { Condition(patient: "$parent.id") { severity {text} }}
... but I don't think graphql defines something like this.
Josh Mandel (May 20 2017 at 15:13):
I guess we could just define things as working this way, with a magic "parent" variable or something like it (ideally, you'd be able to more precisely state which parent, with assigned variable names and stuff). But this kind of magic makes it hard to reuse existing graphql server support libraries...
Josh Mandel (May 20 2017 at 15:20):
My preference would be the Condition_patient approach, which avoids blurring the boundary between references and arguments.
Grahame Grieve (May 20 2017 at 19:01):
I don't understand anything from after you start talking about parent, but I agree with resource. This lets us do:
Grahame Grieve (May 20 2017 at 19:02):
MedicationRequest { patient { resource(policy : error) {active} } }
Grahame Grieve (May 20 2017 at 19:02):
or
MedicationRequest { patient { resource(policy : optional) {active} } }
Grahame Grieve (May 20 2017 at 19:37):
ok. so this graphQL:
{ id subject { reference, resource {active} } code {coding {system code} } }
Grahame Grieve (May 20 2017 at 19:37):
run in the context of Observation/example, gives this:
Grahame Grieve (May 20 2017 at 19:37):
{ "id" : "example", "subject" : { "reference" : "Patient/example", "resource" : { "active": true } }, "code": { "coding": [{ "system": "http://loinc.org", "code": "29463-7" },{ "system": "http://loinc.org", "code": "3141-9" },{ "system": "http://snomed.info/sct", "code": "27113001" },{ "system": "http://acme.org/devices/clinical-codes", "code": "body-weight" }] } }
Grahame Grieve (May 20 2017 at 21:45):
ok, static notes extracted from this thread: http://wiki.hl7.org/index.php?title=FHIR_and_GraphQL
Josh Mandel (May 20 2017 at 23:08):
I don't understand anything from after you start talking about parent
Okay, how about before the stuff about "parent"? Thoughts on the Condition_patient
notation?
Grahame Grieve (May 21 2017 at 03:31):
I don't know what it's supposed to do. I think that the requirement is:
- at this point in the graph, insert the list of resources that refer to this resource in property [x]
Josh Mandel (May 21 2017 at 03:42):
That's close to how I'd describe the requirement, too. Only tweak I'd make is "insert the list of resources of type Y that refer to this resource via property X". So in my example, Y was "Condition" and X was the Condition's "patient" element acting as the source of the reference. I was suggesting we define a graphql field called "Condition_patient" to capture this relationship (would have preferred "Condition.patient", but .
isn't valid) . Possibly we can further restrict X to "elements implicated by standard reference-type search parameters", which means we could use those search parameter names instead of having to point to arbitrary element paths.
Josh Mandel (May 21 2017 at 03:44):
Also we should capture as an explicit goal: publishing a graphql schema for FHIR. This will make our design decisions explicit and easy to use from code.
Grahame Grieve (May 21 2017 at 03:54):
I think search parameter names is correct.
Grahame Grieve (May 21 2017 at 03:55):
but I would have gone for something like this:
references(resource: Condition, parameter: patient) { }
Grahame Grieve (May 21 2017 at 03:55):
instead of
Condition_patient { }
Grahame Grieve (May 21 2017 at 04:03):
with regard to polymorphic types - there's kind of 2 ways to do it. Say we're dealing with Observation, and we want the value:
{
valueQuantity, valueCodeableConcept, valueString, valueBoolean, valueRange, valueRatio, valueSampledData, valueAttachment, valueTime, valueDateTime, valuePeriod
}
Grahame Grieve (May 21 2017 at 04:04):
or we could go for
{
value
}
Grahame Grieve (May 21 2017 at 04:05):
actually, you can't. unless the types are all primitives - and I don't think that actually happens anywhere
Grahame Grieve (May 21 2017 at 04:06):
you'd have to blow them out and specify their primitives, courtesy of GraphQL's rule about all leafs be scalars
Grahame Grieve (May 21 2017 at 04:23):
so
{ subject{reference} valueQuantity {value unit} }
Grahame Grieve (May 21 2017 at 04:23):
on Observation/example gives this:
{ "subject" : { "reference" : "Patient/example" }, "valueQuantity": { "value": 185, "unit": "lbs" } }
Mostafa Sholkamy (May 21 2017 at 06:20):
can we all agree that if you execute this graphql against that resource, that's the correct outcome?
Yes That is correct
Mostafa Sholkamy (May 21 2017 at 06:36):
- searching resources
I think we should create a filter type for each resource that uses search as defined here : http://hl7.org/fhir/search_filter.html
and we can also create a resourceFilter interface that implements the common things when searching a resource.
Mostafa Sholkamy (May 21 2017 at 06:48):
@Josh Mandel
- references
First thing I want to confirm that we all agree that we should add a resource
field to the Reference
element as that doesn't exist in FHIR specs
http://hl7.org/fhir/references.html
Now that we have the resource
field in hand it's pretty easy to resolve it.
GraphQL has an interface type http://graphql.org/learn/schema/#interfaces , So we can create a resource interface that has all the common fields for all resources then we can do something like this:
{ id subject { reference resource { ...on Patient { birthDate } ...on Practioner { practitionerRole { speciality } } } code {coding {system code} } }
Mostafa Sholkamy (May 21 2017 at 06:55):
- extensions in primitive fields / schema reconciliation
@Grahame Grieve Could you explain more what do you mean by schema reconciliation?
I think there is no problem with extensions for primitive fields,the _
prefix works just fine, here is how I do it:
first I define an element type
# Base for all elements type Element { id: ID extension: [Extension] }
then use the element for the primitive field extension in Address
type for example:
# A postal address type Address { id: ID extension: [Extension] use: String _use: Element type: String _type: Element text: String _text: Element line: [String] _line: Element city: String _city: Element district: String _district: Element state: String _state: Element postalCode: String _postalCode: Element country: String _country: Element period: Period }
Grahame Grieve (May 21 2017 at 07:31):
so the question with extensions is whether graphql is specific to json, or more general. so far, all the discussion has been that it's a json only thing. that would make being explicit about the json representatation of extensions the right thing - which is what you've done
Mostafa Sholkamy (May 21 2017 at 07:53):
@Grahame Grieve that is correct GraphQL is for JSON only APIs
Grahame Grieve (May 21 2017 at 09:43):
that's not quite what the graphql spec says
Mostafa Sholkamy (May 21 2017 at 10:12):
the response is always json
Grahame Grieve (May 21 2017 at 11:16):
section 7.1: GraphQL does not require a specific serialization format. However, clients should use a serialization format that supports the major primitives in the GraphQL response
Grahame Grieve (May 21 2017 at 11:17):
JSON is the preferred serialization format for GraphQL, though as noted above, GraphQL does not require a specific serialization format.
Mostafa Sholkamy (May 21 2017 at 13:04):
it's the first time I see the this, but again I searched for any GraphQL server that supports anything other than JSON but I've found nothing
Grahame Grieve (May 21 2017 at 16:08):
yes that is certainly true
Grahame Grieve (May 21 2017 at 16:08):
I could be first ;-)
Grahame Grieve (May 21 2017 at 19:09):
back to extensions. Running this:
{ subject { resource { birthDate } } subject { resource { _birthDate { extension {valueDateTime} } } } }
Grahame Grieve (May 21 2017 at 19:09):
against Observation/20minute-apgar-score results in this output:
Grahame Grieve (May 21 2017 at 19:10):
{ "subject": [{ "resource": { "birthDate": "2016-05-18" } },{ "resource": { "_birthDate": { "extension":[{ "valueDateTime": "2016-05-18T10:28:45Z" }] } } }] }
Mostafa Sholkamy (May 21 2017 at 19:17):
Well if I don't see a reason you should duplicate a fragment of the query twice, I think you would get an error with that.
the correct one would look like that:
{ subject { resource { birthDate _birthDate { extension { valueDateTime } } } } }
Grahame Grieve (May 21 2017 at 19:24):
oh -I was also testing that my processor handled that properly - as far as I can tell, the graphQL spec allows that. But I agree that the way you did it would be more natural
Grahame Grieve (May 21 2017 at 19:26):
anyway, I've just set this live at http://test.fhir.org/r3 - so people can test it. Note that the server doesn't yet support root level query (only on resource instance) and it doesn't yet support anything on the todo list here: http://wiki.hl7.org/index.php?title=FHIR_and_GraphQL
Grahame Grieve (May 21 2017 at 19:27):
one thing I haven't found in the graphql spec yet is how the client gets the schema... is it inline, or just doco?
Grahame Grieve (May 21 2017 at 19:29):
Mostafa Sholkamy (May 21 2017 at 19:40):
one thing I haven't found in the graphql spec yet is how the client gets the schema... is it inline, or just doco?
Could you explain more what do you mean by that?
Grahame Grieve (May 21 2017 at 19:54):
can the client actually ask the server for the schema? or does the server just have to publish it somewhere?
Grahame Grieve (May 21 2017 at 19:58):
hah - just found it - Schema Introspection.
Mostafa Sholkamy (May 21 2017 at 20:11):
yes, that is correct, this can also work as a sort of conformance statement if I understand it correctly
Mostafa Sholkamy (May 21 2017 at 20:13):
Good job with http://wiki.hl7.org/index.php?title=FHIR_and_GraphQL
I will go through it and I will give you my feedback on it
Mostafa Sholkamy (May 21 2017 at 20:28):
As regard Data type mappings for primitive types
In GraphQL you can create custom scalar types http://graphql.org/learn/schema/#scalar-types
In the GraphQL schema it's pretty easy you can just do something like:
scalar positiveInt
and the server determines how to deal with this scalar type, My project - it's using node.js -deals with it this way
import { GraphQLScalarType } from 'graphql'; import { GraphQLError } from 'graphql/error'; import { Kind } from 'graphql/language'; export default new GraphQLScalarType({ name: 'positiveInt', description: 'an integer with value more than zero', serialize: value => { return value; }, parseValue: value => { return value; }, parseLiteral: ast => { if (ast.kind !== Kind.INT) { throw new GraphQLError('Query error: Can only parse integers got a: ' + ast.kind, [ ast ]); } if (!(ast.value > 0)) { throw new GraphQLError('Query error: Not a valid positive integer', [ ast ]); } return ast.value; } });
I've got my primitive types defined here
https://github.com/shalkam/gql-fhir/tree/master/src/data/fhir/types/primitive
Mostafa Sholkamy (May 21 2017 at 20:41):
this can be also useful when profiling, an Array scalar type can be created for handling cardinality like this:
scalar ArrayMin1Max5
Grahame Grieve (May 21 2017 at 22:10):
hmm. that loses the mapping to the underlying scalar type. How do you know that unsignedInt is a number in json? I think that's just bizarre, and I'd rather avoid defining them then
Grahame Grieve (May 21 2017 at 22:11):
so far, there's 2 things that strike as weird in graphql - that, and the fact that you have to do selection sets for objects
Grahame Grieve (May 21 2017 at 23:02):
ok, back to reverse references (@Josh Mandel). So after looking at the schema, let's do it this way:
{ name {...} Condition(_key: patient) { .. fields from Condition ... } }
Grahame Grieve (May 21 2017 at 23:03):
name the resource type that you are looking up - helpful for typing - and, provide which index you want to use for matching as the argument '_key'. You can provide other search parameters as arguments, to further filter
Josh Mandel (May 21 2017 at 23:35):
And _key
is limited to search parameters? I like this! I might change _key
to reference
or _reference
just to avoid introducing a new term for this idea.
Grahame Grieve (May 21 2017 at 23:36):
yes. I don't mind changing to _reference. I will update the doco and my implementation
Grahame Grieve (May 21 2017 at 23:38):
has to be _reference not reference because there are existing search parameters named reference and you might want to combine them
Grahame Grieve (May 21 2017 at 23:38):
I will update test.fhir.org to support this later today
Mostafa Sholkamy (May 22 2017 at 00:52):
hmm. that loses the mapping to the underlying scalar type. How do you know that unsignedInt is a number in json? I think that's just bizarre, and I'd rather avoid defining them then
No, that is just a standard in GraphQL and fulfills a requirement in FHIR specs; I don't see a reason why we should avoid it. You have a GraphQL schema string and you have resolver
function for each type in the schema.
a resolver
function is responsible for getting the data to deliver to the client, it doesn't matter how but most of the time it will be doing some database queries against a model.
It's a GraphQL server responsibility to match those two together. resolvers
can be written in any programming language according to your favorite language and according to that the server library you are using.
It's not the responsibility of HL7 to define how resolver
functions will look like, it is just enough to write a GraphQL schema and then anyone can figure out how to resolve that schema in his way using his own preferred programming language.
Please take a look at this link and see if it makes more sense after : http://dev.apollodata.com/tools/graphql-tools/scalars.html
Mostafa Sholkamy (May 22 2017 at 01:28):
and here is another article about resolvers: http://dev.apollodata.com/tools/graphql-tools/resolvers.html
Mostafa Sholkamy (May 22 2017 at 01:29):
Please note that most of the Links I am referencing are for Node.js libraries, of course other languages have their own corresponding libraries
Grahame Grieve (May 22 2017 at 02:00):
right. resolvers are a private thing to the server. The question for the client is, what is scalar type xxx? a string? a number? something else?
Grahame Grieve (May 22 2017 at 02:22):
on the subject of looking up reverse references, do we need to worry about there being too many of them?
Grahame Grieve (May 22 2017 at 02:23):
and if we did worry about it, what would we do about it?
Grahame Grieve (May 22 2017 at 03:56):
so there's another problem here - we define search parameter names with '-' in them. These make them non-valid argument names in graphQL
Grahame Grieve (May 22 2017 at 04:24):
for now, I am replacing - with _
Grahame Grieve (May 22 2017 at 09:36):
do we have any need for directives other than the mandatory ones?
Mostafa Sholkamy (May 22 2017 at 15:09):
The question for the client is, what is scalar type xxx? a string? a number? something else?
There is always a schema introspection every scalar type has its own description in the schema, Most of the time the type name itself is self explanatory.
And also FHIR describes every scalar/primitive type
Mostafa Sholkamy (May 22 2017 at 15:13):
on the subject of looking up reverse references, do we need to worry about there being too many of them?
and if we did worry about it, what would we do about it?
Do you mean like a some sort of pagination solution?
Grahame Grieve (May 22 2017 at 15:51):
well, that's the question - do we need to?
Mostafa Sholkamy (May 22 2017 at 16:14):
Of course if it's too many we have to paginate
Mostafa Sholkamy (May 22 2017 at 16:14):
Could you take a look at this : https://facebook.github.io/relay/docs/graphql-relay-specification.html ?
Mostafa Sholkamy (May 22 2017 at 16:26):
it adds more specifications to take care of pagination and other stuff
Grahame Grieve (May 22 2017 at 16:39):
so the way that works puts all the control on the part of the server, yes? the client doesn't get to say anything about it?
Grahame Grieve (May 22 2017 at 16:40):
I'm also not sure how you would make that work deep inside a graph
Eric Haas (May 22 2017 at 16:40):
so looking at http://wiki.hl7.org/index.php?title=FHIR_and_GraphQL
I am confused by the notation or syntax of ellipses.
of this:
resource { ...on Patient {
vs ellipses here:
{ name {...} Condition(_reference: patient) { .. fields from Condition ... }
I'm assuming the first case is actual GraphQL syntax and the second means 'some data here' ?
Grahame Grieve (May 22 2017 at 16:40):
ah yes. tricky. I'll make the second explicit
Grahame Grieve (May 22 2017 at 16:41):
try that
Eric Haas (May 22 2017 at 16:43):
that is clearer. thanks
Mostafa Sholkamy (May 22 2017 at 17:31):
so the way that works puts all the control on the part of the server, yes? the client doesn't get to say anything about it?
could you explain more?
Grahame Grieve (May 22 2017 at 18:22):
I couldn't find anywhere in that approach where the client said whether it wanted paging
Mostafa Sholkamy (May 22 2017 at 18:35):
the client can always state whether it wants paging or not
so, using this example
{ name {...} Condition(_reference: patient) { .. fields from Condition ... }
we can do something like this
{ name {...} Condition(_reference: patient, start: 0, limit: 10) { .. fields from Condition ... }
Mostafa Sholkamy (May 22 2017 at 18:35):
the arguments can always be changed per client query
Grahame Grieve (May 22 2017 at 20:06):
I missed that bit. Should we make this standard?
Grahame Grieve (May 22 2017 at 21:10):
I think we should, yes. But a more difficult question: order....
Josh Mandel (May 22 2017 at 23:32):
I think we probably want to align our paging approach with what we do in the search API, using opaque "next page" tokens and a client-suggested count.
Josh Mandel (May 22 2017 at 23:33):
http://graphql.org/learn/pagination/ describes relevant considerations
Grahame Grieve (May 22 2017 at 23:33):
that makes sense at the root, but I'm quite unpersuaded that it makes sense deep inside a graph
Josh Mandel (May 22 2017 at 23:34):
It does imply we need a kind wrapper though around the list of paginated things. Like a ConditionList instead of Condition.
Josh Mandel (May 22 2017 at 23:36):
What I'm suggesting is essentially the best practice described on the "learn" site
Josh Mandel (May 22 2017 at 23:36):
What worries you about it?
Grahame Grieve (May 22 2017 at 23:42):
it's one thing to say start/limit or something a the root, or have a cursor approach that matches what we do no
Grahame Grieve (May 22 2017 at 23:42):
get me all the resources that match these conditions.... right. that's obvious.
Josh Mandel (May 22 2017 at 23:43):
Oh, yes deeply nested this kind of token would be hard to pass into a followup query. I was imaging the followup query would be targeted to just the nested piece (not containing/repeating all the outer stuff).
Grahame Grieve (May 22 2017 at 23:44):
it get's especially hard when you have nested lists - the server is keeping a lot of speculative lists that the client will never follow
Grahame Grieve (May 22 2017 at 23:44):
I'm not even sure how many servers would be able to retain an independent context in which the deep queries could be followed
Josh Mandel (May 22 2017 at 23:46):
But letting the client provide offsets doesn't quite work either: if I do a top level query for Patients and want to get first 5 Encounters for each and then independently page through the next 5 Encounters for just the first patient... I'd probably just issue a follow-up query for that on patient's next encounters, rather than repeat the whole outer query, right? (I can't see another way to express it, because the outer query is doesn't give me a way to use different offsets for different patients.)
Josh Mandel (May 22 2017 at 23:49):
The server doesn't need to maintain speculative lists -- it can instead just produce pagination tokens that internally just represent something like "skip 15". The point is just that the server gets to choose (between this and db cursors or whatever), and the client treats it as opaque.
Grahame Grieve (May 23 2017 at 01:05):
I can't present
Grahame Grieve (May 23 2017 at 01:06):
I can't present a token that means 'skip 15' unless I know what the server has to skip from
Grahame Grieve (May 23 2017 at 01:07):
I think that there's no place for pagination queries on anything but the root. For the nested stuff, just let the client specify a limit, and only on the root allow pagination and links for following the sequence (the stuff we already do)
Josh Mandel (May 23 2017 at 02:53):
And how does a client follow up beyond the initial fetch limit? A nicely designed pagination token embeds enough context to reproduce a query (e.g. The query parameters and an index of a last returned result.)
Grahame Grieve (May 23 2017 at 02:57):
I'm just implementing it on the root. It's problematic. Here's my example, which should illustrate:
Grahame Grieve (May 23 2017 at 02:58):
request:
{ Patient(active : true) { id }
Grahame Grieve (May 23 2017 at 02:58):
response:
Grahame Grieve (May 23 2017 at 02:59):
{ "Patient": [ { "type": "paging", "first": "search-id=e6686cc0-11cc-4266-a027-aef4c7f3fb&&active=true&_sort=_id&search-offset=0&_count=50", "next": "search-id=e6686cc0-11cc-4266-a027-aef4c7f3fb&&active=true&_sort=_id&search-offset=50&_count=50", "last": "search-id=e6686cc0-11cc-4266-a027-aef4c7f3fb&&active=true&_sort=_id&search-offset=200&_count=50" }, { "type": "resource", "id": "1" }, { "type": "resource", "id": "100" }, .. etc... ] }
Josh Mandel (May 23 2017 at 03:00):
This is doest look quite right. Your Connection object should have next/prev links and then an array of patients
Grahame Grieve (May 23 2017 at 03:00):
first of all, you need to find somewhere to inject the paging control data. I chose one of several different possible ways here; there are others I expect we'll argue over. But you have to do something, if you're going to enable this. I just don't see the value on reverse reference resolution, only on the root searches
Grahame Grieve (May 23 2017 at 03:02):
well, you can show what you think it should look like, but I don't see how it can look like you describe, given the way that graphQL works
Josh Mandel (May 23 2017 at 03:03):
(yes, I'll be argue about this particular representation ;)) But when you say that you don't see me value... you're saying that there should be no way to get more than the first batch of things linked to from a top level result? Like, first 5 conditions in my example, and there's no value in every getting more?
Grahame Grieve (May 23 2017 at 03:03):
and reading this http://graphql.org/learn/pagination/ tells me nothing because I don't know whether those fragments are schema, request, or response
Grahame Grieve (May 23 2017 at 03:04):
define 'top level result'
Josh Mandel (May 23 2017 at 03:04):
Looking at the example at the bottom of that page: the left hand side is a query, and the right hand side is a response.
Josh Mandel (May 23 2017 at 03:05):
When I said "top level" just now, I'm referring to the query that finds patients and then for each patient finds conditions. "top level" meant the patients.
Grahame Grieve (May 23 2017 at 03:06):
ok. so I'm sceptical of the value in setting up paging for the conditions - it's work for both client and server. And those lists are inherently both shorter and more bounded than the general search.
Grahame Grieve (May 23 2017 at 03:18):
but now I understand the link a little better... I really don't like their terms at all (connection, edge)... and I don't begin to understand how they intend the cursor to work
Grahame Grieve (May 23 2017 at 03:47):
one option - more work for the server, but that's our usual choice - is to allow either. So
Condition(_reference : parameter, ... search parameters) { }
Grahame Grieve (May 23 2017 at 03:48):
or
ConditionConnection(_reference : parameter, ... search parameters, iteration parameters) { link {type, ref} totalCount offset pageSize node { ... fields.... } }
Grahame Grieve (May 23 2017 at 03:50):
but there'd have to be a rule that if you wanted to pursue the references on the nested queries, you'd have to iterate them directly, not in a nested fasion
Grahame Grieve (May 23 2017 at 03:51):
I still have real problems with this though. In my server, I actually have to remember each result set specifically, so that you can iterate it with confidence. I'm going to be doing a lot of this for nothing...
Mostafa Sholkamy (May 23 2017 at 09:42):
I think all the paging stuff belongs inside the Reference
data type
# A reference from one resource to another type Reference { id: ID extension: [Extension] reference: String _reference: Element display: String _display: Element resources(filter: JSON, .. any other parameters): ResourceInterface }
Mostafa Sholkamy (May 23 2017 at 09:44):
Then whenever a reference is called we use the Reference
type, it should be limited to a resource specific reference field
Grahame Grieve (May 23 2017 at 12:12):
Resource is 0..1 here, there's no paging to be done. It's only the reverse references that don't have a home that can be 0..*
Mostafa Sholkamy (May 23 2017 at 13:23):
ok, that is correct
Josh Mandel (May 23 2017 at 19:26):
there'd have to be a rule that if you wanted to pursue the references on the nested queries, you'd have to iterate them directly, not in a nested fasion
I think spelling this out directly would be good. I'm not 100% sure I understand what you mean by "iterate them directly". (Of course, an alternative is to say: if you want to page over these, you just issue a new query for Condition(patient: "123"){}
...)
Josh Mandel (May 23 2017 at 19:28):
In
ConditionConnection(_reference : parameter, ... search parameters, iteration parameters) { link {type, ref} totalCount offset pageSize
... what are the link.ref
properties? Full URLs to a page of FHIR REST API search results? Or a token that can be inserted into a follow-up graphql query?
Grahame Grieve (May 23 2017 at 20:11):
a token that can be used in a follow up query
Grahame Grieve (May 23 2017 at 20:49):
ok so wrote up where I think we are here:
Grahame Grieve (May 23 2017 at 20:49):
http://wiki.hl7.org/index.php?title=FHIR_and_GraphQL#Searching_resources
Grahame Grieve (May 23 2017 at 20:50):
I have not updated the reverse references section yet - I will when we have consensus about top level searching
Josh Mandel (May 23 2017 at 21:16):
This looks like a great approach for the top-level results.
Mostafa Sholkamy (May 23 2017 at 23:00):
In the primitive type mapping, I think every type should be mapped to a scalar type in GraphQL, instead of
String | everything else
Mostafa Sholkamy (May 23 2017 at 23:01):
if there is no corresponding one in the default scalar types in GraphQL, a custom scalar type should be declared and then it's the server issue to resolve it
Mostafa Sholkamy (May 23 2017 at 23:03):
Can we discuss the generate schema
in the open questions section?
Grahame Grieve (May 24 2017 at 01:44):
ok. updated the http://wiki.hl7.org/index.php?title=FHIR_and_GraphQL#Reverse_References section now
Grahame Grieve (May 24 2017 at 01:45):
why map to scalar instead of string?
Grahame Grieve (May 24 2017 at 01:46):
as for generate schema - I intend to generate a full graphQL schema for the entire specification, as an examplar for people to copy from / or use as a template for generating their own responses from their server. I think that would be a useful thing. And now that we've agreed on all the queries - well, I think we have ;-) - it's about time to generate the schema. If that all makes sense
Mostafa Sholkamy (May 24 2017 at 06:38):
For, example GraphQL doesn't have a Date type we can easily create a Date scalar type, why use a string for that?
We can also create a positiveInteger type to validate that a value is a positive integer. Or why did FHIR declare those primitive type at the first place?
nicola (RIO/SS) (May 24 2017 at 06:43):
How are we going handle extensions in graphql?
Grahame Grieve (May 24 2017 at 06:43):
just like any other content. there's no need to do anything special
Grahame Grieve (May 24 2017 at 06:44):
with regard to positiveInteger etc - we expect FHIR processors to natively know what those things are. That seems a wrong assumption to make in graphQL - and the key question has to be, what are these things in json, right
nicola (RIO/SS) (May 24 2017 at 06:48):
I mean, if i have Patient with dozen of extensions and i want to get only race
extension (specifying only what i need in graphql paradigm)?
{extension( race filter) { ..........}
?
Grahame Grieve (May 24 2017 at 06:49):
{ extension( url : "..") { valueCode } }
nicola (RIO/SS) (May 24 2017 at 06:49):
If i need couple of extensions - graphql aliasing?
Grahame Grieve (May 24 2017 at 06:50):
yes
Mostafa Sholkamy (May 24 2017 at 06:52):
scalar types in GraphQL also have their corresponding resolvers in the server too
Mostafa Sholkamy (May 24 2017 at 06:54):
the key question has to be, what are these things in json
For example date time is of type Date in JSON but that doesn't exist in GraphQL
Mostafa Sholkamy (May 24 2017 at 08:04):
So, For now all the discussion has been around querying a list of patients, but there have to be a query that returns a single patient too
Mostafa Sholkamy (May 24 2017 at 08:10):
Taking my schema here : https://github.com/shalkam/gql-fhir/blob/master/src/data/schema.graphql as a guide
So, if the root query type looks like this :
type Query { Patient: PatientQuery } type PatientQuery { find(any filter goes here): [Patient] findOne(id: ID!, ... plus any other filter ...): Patient }
So, we have find
type that returns a list of patients and findOne
that returns only one patient
Mostafa Sholkamy (May 24 2017 at 08:26):
Same goes for mutations
type Mutation { Patient: PatientMutation } type PatientMutation { remove(_id: ID!): Patient upsert(data: PatientInput!): Patient }
then a mutation will look like this:
mutation upsertPatient($data: PatientInput!) { patient { upsert(data: $data) { ...patient fields goes here... } } }
and a query
query find($filter: JSON){ patient { find(filter: $filter) { ...patient fields goes here... } } }
Mostafa Sholkamy (May 24 2017 at 08:27):
I think we should all agree how we should name the different crud operations and arguments used for them inside the GraphQL schema
Grahame Grieve (May 24 2017 at 20:07):
scalar types - chatting to graphQL guys - there's no solution for this. If the schema uses scalar types, then everyone in the picture just has to 'know' the scalar types magically
Grahame Grieve (May 24 2017 at 20:08):
i mean, custom scalar types...
Mostafa Sholkamy (May 24 2017 at 20:38):
What about the reference here : http://hl7.org/fhir/datatypes.html it states what is needed for each primitive type this can be a reference
Grahame Grieve (May 24 2017 at 22:42):
well, indeed, that's the reference.
Grahame Grieve (May 24 2017 at 22:42):
just not computable.
Grahame Grieve (May 24 2017 at 22:42):
but that's a graphQL issue
Grahame Grieve (May 26 2017 at 02:29):
ok, updated http://wiki.hl7.org/index.php?title=FHIR_and_GraphQL#Searching_resources
Grahame Grieve (May 26 2017 at 02:29):
before we talk about mutations, can we talk about directives?
Grahame Grieve (May 26 2017 at 02:32):
GraphQL says that you should support directives - "GraphQL implementations should provide the @skip and @include directives."
Grahame Grieve (May 26 2017 at 02:33):
we could say, 'yeah, but no', or we could say 'SHALL provide'. Or we could remain silent. Any opinions? And should we define any other directives? (I haven't seen any need)
Grahame Grieve (May 26 2017 at 21:37):
updated http://wiki.hl7.org/index.php?title=FHIR_and_GraphQL#Searching_resources again after actually implementing it
Grahame Grieve (May 26 2017 at 23:11):
and added actual working links for examples
Grahame Grieve (May 28 2017 at 21:14):
ok, schema - I added to the build to generate scheme files. So far, I've only done the static schema. see
http://build.fhir.org/types.graphql
http://build.fhir.org/patient.graphql
or http://build.fhir.org/[resource].graphql where resource name is all lowercase
Grahame Grieve (May 28 2017 at 21:15):
@Josh Mandel and @Mostafa Sholkamy please check the schema
Eric Haas (May 29 2017 at 00:54):
I think this example here.....
http://test.fhir.org/r3/Observation/example/$graphql?query={id,subject{reference,resource{...on%20Patient{birthDate}...on%20Practioner{practitionerRole{speciality}}}}code{coding{system,code}}}
should be this...
http://test.fhir.org/r3/Observation/example/$graphql?query={id,subject{reference,resource{...on%20Patient{birthDate}}}code{coding{system,code}}}
(remove the practitiionerRole reference)
Eric Haas (May 29 2017 at 00:55):
The result is the same
Grahame Grieve (May 29 2017 at 01:17):
well, it's not wrong - it's just that the example doesn't use that type.
Actually, the type is not legal, so I just updated to something that is
Josh Mandel (May 29 2017 at 20:22):
@Grahame Grieve how come properties have phrases_like_this
instead of phrasesLikeThis
?
Josh Mandel (May 29 2017 at 20:23):
Oh, I see -- just for search parameters.
Josh Mandel (May 29 2017 at 20:23):
You're using the FHIR standard names with _
--> -
to make them valid.
Grahame Grieve (May 29 2017 at 20:23):
y. servers have to reverse the conversion
Josh Mandel (May 29 2017 at 20:27):
This schema proposes two very similar ways to search patients, one returning [Patient]
and the other returning [PatientEdge]
. It might be better just to do searches that include the count/score/pagination details (like FHIR's REST search does today).
Josh Mandel (May 29 2017 at 20:27):
What's the use case for having the other one, too?
Josh Mandel (May 29 2017 at 20:29):
Also, in any case, we should be sure to preserve search parameters that come from Resource (_id
, _lastUpdated
, etc)
Grahame Grieve (May 29 2017 at 20:30):
I think it's more relevant in reverse reference searches. There's 3 differences:
- the returned graph is simpler
- in particular, the returned graph doesn't need to be considered with logic asking 'is there more pages to get'
- servers can fulfill the simpler search with much less resources, because they do not need to remember state about the searches
Grahame Grieve (May 29 2017 at 20:30):
_id is irrelevant. I'll update the generator to handle the others
Josh Mandel (May 29 2017 at 20:31):
_id
is relevant because it lets you get a list of named patients without having to alias each, and it's just a nice analogy to our existing search behavior.
Grahame Grieve (May 29 2017 at 20:31):
not following that
Josh Mandel (May 29 2017 at 20:32):
I want to get PatientList("_id": "1, 2, 3")
Josh Mandel (May 29 2017 at 20:32):
That way search parameters would work in a consistent fashion between our REST API and the grpahql API.
Josh Mandel (May 29 2017 at 20:32):
For the reverse search, even if a server doesn't want to implement support for pagination etc -- it's still important to communicate "this is not a complete list", which the Connection structure could/should let us say.
Grahame Grieve (May 29 2017 at 20:33):
I think you mean PatientList(id: [1, 2,3]) but ok.
Josh Mandel (May 29 2017 at 20:33):
[1,2,3]
isn't a valid string
Grahame Grieve (May 29 2017 at 20:34):
"1, 2, 3" is not a valid id
Josh Mandel (May 29 2017 at 20:34):
No, but that's how _id
and other search parms work in FHIR's REST API: they define a comma-separated list as a string.
Grahame Grieve (May 29 2017 at 20:34):
question is whether the composite syntax should apply or not.
Josh Mandel (May 29 2017 at 20:35):
I mean, being able to say "or" somehow is helpful. Do we have a better way?
Josh Mandel (May 29 2017 at 20:35):
If there is, I'd be happy to use that instead; I'm just missing it right now.
Grahame Grieve (May 29 2017 at 20:36):
yes we do. _filter. For syntactical reasons, most of the interesting FHIR search techniques are not possible in GraphQL, and I don't think we should bend over backwards to make them so - we should say, use _filter
Josh Mandel (May 29 2017 at 20:36):
We could define params like whatever
+ _in
for each search param, to provide an array form, like _id_in: ["1","2","3"]
Josh Mandel (May 29 2017 at 20:37):
The filter language is a bit obscure; it's a lot of baggage just to say "or".
Grahame Grieve (May 29 2017 at 20:38):
it's exactly the language used by other restful specifications, and it's not obscure to say _id eq 1 or Id eq 2
Josh Mandel (May 29 2017 at 20:38):
the two letter ops are obscure to me.
Josh Mandel (May 29 2017 at 20:38):
I haven't ever used another REST API with FHIR's filter syntax.
Grahame Grieve (May 29 2017 at 20:39):
pffft.
Josh Mandel (May 29 2017 at 20:39):
But I understand the idea came from elsewhere (which is good).
Josh Mandel (May 29 2017 at 20:39):
Anyway, overall I think this schema approach looks really nice. I'd try very hard to condense the PatientListType
and PatientConnectionType
.
Grahame Grieve (May 29 2017 at 20:40):
given that we have arrays in graphql, it's much cleaner to avoid the syntactical issues with ',' and escapes bu saying to use json arrays and escaping instead
Grahame Grieve (May 29 2017 at 20:40):
how you going to condense them? Force everyone to use the heavier weight Connection approach every time?
Josh Mandel (May 29 2017 at 20:41):
Any time you do a query that returns a list, you need to know if you're getting a complete result or just the the "first n matches", right?
Josh Mandel (May 29 2017 at 20:42):
I can't really think of a use case like "just give me some of a patient's allergies, dealer's choice"...
Grahame Grieve (May 29 2017 at 20:42):
if you say "list" you get everything or an error - that's what the wiki page says.
Grahame Grieve (May 29 2017 at 20:42):
I thought you reviewed all that and said you liked it...
Josh Mandel (May 29 2017 at 20:42):
I think I didn't understand this implication.
Josh Mandel (May 29 2017 at 20:43):
But that certainly helps!
Josh Mandel (May 29 2017 at 20:43):
Have we addressed sort order?
Josh Mandel (May 29 2017 at 20:43):
(for lists or connections?)
Grahame Grieve (May 29 2017 at 20:43):
works like the search for both
Josh Mandel (May 29 2017 at 20:43):
Like, there are _sort
params?
Grahame Grieve (May 29 2017 at 20:44):
I didn't generate that though did I?
Josh Mandel (May 29 2017 at 20:44):
This isn't reflected in the Patient schema, no
Josh Mandel (May 29 2017 at 20:44):
Or, not yet ;-)
Josh Mandel (May 29 2017 at 20:44):
That'll work fine though.
Grahame Grieve (May 29 2017 at 20:45):
I'll generate the inherited search parameters and the sort parameters
Josh Mandel (May 29 2017 at 20:45):
Super. graphql for FHIR will be massively convenient for a lot of folks, if it sees widespread support.
Josh Mandel (May 29 2017 at 20:46):
(And I think it's still probably possible to do a reasonable job of implementing the graphql API on top of the REST API, as a proxy in from of servers that don't support it; I should review what it'll take to get there based on the current definitions.)
Grahame Grieve (May 29 2017 at 20:48):
I effectively did that in my server. The only alteration I made to my base server was to create a direct path for the *List search, that doesn't do paging/caching. That was for efficiency, not for functionality. (plus found and fixed some bugs on the way)
Grahame Grieve (May 29 2017 at 20:57):
ah.. .and you need to know, in the proxy, how paging works on the server. To the client, it's opaque, but to correctly transfer between syntaxes, you need to know how to take the URL apart and reconstruct it
Grahame Grieve (May 30 2017 at 03:06):
ok updated the generated graphQL according to our discussion
Grahame Grieve (May 30 2017 at 06:47):
so. finally, time to talk about mutation. my preferred approach would be that you could update a resource directly, but:
Grahame Grieve (May 30 2017 at 06:56):
but nothing. I read something wrong. So create/update/delete.
Grahame Grieve (May 30 2017 at 07:04):
but so many questions - are a set of mutations a batch? a transaction? How can you create a set of related resources?
Grahame Grieve (May 30 2017 at 07:19):
duh. no multiple mutations
Grahame Grieve (May 30 2017 at 07:50):
I've been reading the graphQL spec about mutations, and am unclear on error handling. Here's questions I put on the graphQL chat:
Grahame Grieve (May 30 2017 at 07:50):
- if execution fails, should a server return 200 OK with { "error" : ["..."] }? or should it have a different response code?
- This forces a client have to handle HTTP errors (before you get to the graphQL processor), and also check for 200 OK + errors - why is that useful?
- under what conditions would your response include both data and errors, and what should a client do with that?
- the documentation helpfully says "If no data is returned, according to the GraphQL spec, the "data" field should only be included if the error occurred during execution" - I've read that several times, and I don't know what it means, either returning data if there is no data returned, or what the definition of 'during execution' is
Grahame Grieve (May 30 2017 at 09:17):
I just upgraded my server to fix a mistake in every response.
Grahame Grieve (May 30 2017 at 19:00):
and after dsicussion on the graphQL, chat, I've added a new section to the graphQL page:
Grahame Grieve (May 30 2017 at 19:00):
http://wiki.hl7.org/index.php?title=FHIR_and_GraphQL#Conformance
Grahame Grieve (May 31 2017 at 20:37):
I think it's time to move the wiki page to the spec itself. @Josh Mandel @Mostafa Sholkamy - do you agree? And is there enough interest for a connectathon stream? (Josh, I presume you see a cds-hooks interest here....)
nicola (RIO/SS) (Jun 01 2017 at 15:42):
@Grahame Grieve I do not see in wiki how to query specific extension?
Grahame Grieve (Jun 01 2017 at 20:53):
added an example
David Hay (Jun 15 2017 at 04:42):
Github are getting in on the act: https://githubengineering.com/the-github-graphql-api/
Grahame Grieve (Jun 15 2017 at 04:50):
thx.
Grahame Grieve (Jun 15 2017 at 04:50):
should we have a Connectathon stream on graphQL?
Eric Haas (Jun 15 2017 at 15:47):
+1 on stream and can one do a LastN like search with it? It was not clear to me whether this was possible?
Grahame Grieve (Jun 15 2017 at 21:48):
@Eric Browne h
Grahame Grieve (Jun 15 2017 at 21:48):
oops
Grahame Grieve (Jun 15 2017 at 21:49):
@Eric Haas yes - you can. Just add a _graphql parameter to the operation when you invoke it, and the graphql runs on the output. I've added an example to the wiki page, and my server will start supporting it next time I upgrade it
Grahame Grieve (Jun 15 2017 at 21:51):
I think it's time to move the graphQL stuff into the specification itself
Eric Haas (Jun 15 2017 at 22:01):
I agree. Is there a GForge
Grahame Grieve (Jun 15 2017 at 22:02):
probably not
Eric Haas (Jun 15 2017 at 22:05):
Grahame Grieve (Jun 15 2017 at 22:05):
is now. GF#13531
Grahame Grieve (Jun 15 2017 at 22:05):
lol
Eric Haas (Jun 15 2017 at 22:05):
NM withdrew mine
Grahame Grieve (Jun 20 2017 at 06:04):
http://wiki.hl7.org/index.php?title=201709_GraphQL
Grahame Grieve (Jun 20 2017 at 06:05):
if you're interested in participating, please register your interest directly on the wiki, or mention it here.
Grahame Grieve (Jun 20 2017 at 06:05):
I'm the track lead at the moment, but I'm looking for a volunteer to take this one on
Grahame Grieve (Jun 20 2017 at 06:08):
I have migrated the GraphQL documentation to here: http://build.fhir.org/graphql.html
Mostafa Sholkamy (Jul 11 2017 at 12:16):
@Grahame Grieve Does http://build.fhir.org/types.graphql includes all datatypes in FHIR?
and each resource like the patient's file http://build.fhir.org/patient.graphql only includes types for backbone elements?
Grahame Grieve (Jul 11 2017 at 12:31):
yes that's right
Mostafa Sholkamy (Jul 11 2017 at 19:15):
I've cleaned up those graphql files types.graphql
and patient.graphql
they had some errors and changed some stuff too like the adding PatientMutation
and PatientQuery
types
Mostafa Sholkamy (Jul 11 2017 at 19:15):
you can check it here https://gist.github.com/shalkam/5e68771783b941cc601d2a468589517e
Mostafa Sholkamy (Jul 28 2017 at 01:38):
I've set up a full stack example for a patient resource in node.js using graphql, mongoose and express
Feel free to check it out https://github.com/shalkam/gql-fhir-patient-example
Abbie Watson (Aug 29 2017 at 22:52):
Hi, releasing a proposal for an Apollo on FHIR architecture. Integrated database proxy with Meteor on FHIR backend that serves up GraphQL queries.
https://medium.com/@awatson1978/apollo-on-fhir-architecture-3d5bf4d0fc97
Apollo-on-FHIR-Architecture.png
Vadim Peretokin (Sep 23 2017 at 06:21):
https://github.com/facebook/graphql/issues/351 [GraphQL Patent Infringement Issues] just a heads up
Grahame Grieve (Oct 27 2017 at 08:36):
Follow up: http://www.healthintersections.com.au/?p=2740
Karlo Martinez (Jan 19 2018 at 15:02):
@Abigail Watson I read the article you wrote and found it helpful for my current project. What I found most interesting where the graphics. I wonder, what tool where used to create them?
Karlo Martinez (Jan 19 2018 at 15:07):
@Mostafa Sholkamy
I've set up a full stack example for a patient resource in node.js using graphql, mongoose and express
Feel free to check it out https://github.com/shalkam/gql-fhir-patient-example
Would it be possible that you forgot to push your commits to Github? I found the repository to be empty upon entering.
Karlo Martinez (Jan 19 2018 at 15:17):
Hi there, I am Karlo Martínez from Puerto Rico. I am looking to use FHIR in a GraphQL server implementation and am having trouble figuring out the spec and found, through reading the topic thread that there might already exists resources to make it happen. I have a couple of questions that will help me start in the right direction.
Where can I find the GraphQL Type and Schema definitions for the resources?
is there a particular reason why the wiki describes the usage in a REST-like manner? Meaning that there are multiple endpoints each for the different resources.
Eric Haas (Jan 20 2018 at 00:30):
have you read this
Karlo Martinez (Jan 22 2018 at 11:20):
Hi @Eric Haas . Yes, I have for the most part. I am familiar with GraphQL, contrary to FHIR which I just recently got involved due to my employment. I have read through the thread and found some answers. I have never seen a GraphQL API that has multiple endpoints such as it's described. And would have also expected to find url's to the schemas in the documentation from previous works.
Grahame Grieve (Jan 22 2018 at 12:45):
you don't need to make use of the multiple end-points - you can only use the base on if you want
Grahame Grieve (Jan 22 2018 at 12:47):
for the schema: http://build.fhir.org/patient.graphql , etc. I haven't got around to integrating all the schemas yet
Karlo Martinez (Jan 22 2018 at 13:47):
@Grahame Grieve
for the schema: http://build.fhir.org/patient.graphql , etc. I haven't got around to integrating all the schemas yet
Thanks, I went and downloaded each one. Kind of troublesome to do by hand. Also rearranged them to be sorted by category, I'd be happy to share a zip file with all the schema's for convenience.
Karlo Martinez (Jan 22 2018 at 13:49):
you don't need to make use of the multiple end-points - you can only use the base on if you want
Would this affect our chances of getting the FHIR public API to be HL7 certified, if there is such a thing?
Grahame Grieve (Jan 22 2018 at 18:51):
there is no such thing. but no, you choose what you want to implement - for now. We don't generally make rules like that - it's left to the implementation guides, and we haven't exploded implementation guides constraining graphql usage yet
nicola (RIO/SS) (Nov 08 2018 at 06:08):
GraphQL now is foundation - https://medium.com/@leeb/introducing-the-graphql-foundation-3235d8186d6d
Michele Korell (Jan 08 2019 at 13:09):
Hello, when we started our development on FHIR GraphQL, we found on github an interesting project from Asymmetrik. Their implementation give a complete GraphQL definition of FHIR resources.: https://github.com/Asymmetrik/graphql-fhir.
Robert Winterbottom (Jan 08 2019 at 13:30):
Hey @Michele Korell, thanks for checking us out. Just wanted to let everyone know that we are planning on open sourcing GraphQL definitions for all of R4 very soon, and a re-release of 3.0.1 and 1.0.2 with some fixes involving union types (End of the week or early next week). Hope you all find these useful and if you have any feedback, please feel free to reach out to me or @Jon Lee either here or via an issue on Github.
Lloyd McKenzie (Jan 08 2019 at 16:29):
Would this be something that would make sense to generate as a reference implementation alongside the Java, C#, Javascript and other reference implementations?
Robert Winterbottom (Jan 08 2019 at 18:03):
Yea absolutely
Robert Winterbottom (Jan 08 2019 at 18:13):
Anything we can do to help get that started?
Lloyd McKenzie (Jan 08 2019 at 18:26):
@Grahame Grieve, what would we need to be done (beyond an open license)?
Grahame Grieve (Jan 08 2019 at 19:49):
I'm not sure what this is. We already publish graphQL definitions of the resources.
Geoffrey BAUDIN (Jan 09 2019 at 15:10):
Please can you provide a link where definitions were published ? I means *.graphql files.
Michele Korell (Jan 10 2019 at 01:02):
I found some definitions of FHIR resource as graphql file (Example: http://build.fhir.org/observation.graphql) but it is available an endpoint that expose the whole schema? To allow a server work with remote schema definition, like is explained on Apollo GraphQL tools (https://www.apollographql.com/docs/graphql-tools/schema-stitching.html#remote-schemas).
Grahame Grieve (Jan 10 2019 at 10:14):
I don't think I gathered them into a whole schema. What is required in it?
Michele Korell (Jan 10 2019 at 10:24):
Actually I'm looking for GraphQL endpoint (like the example “[base]/$graphql“ defined at http://build.fhir.org/graphql.html#invoking) to execute an IntrospectionQuery and let me get the whole GraphQL schema. I try with http://test.fhir.org/r4/$graphql but i cannot execute any query. Only queries on selected resource are working, for example: http://test.fhir.org/r4/Patient/8/$graphql?query={id%20name{text,given,family}}
The following http query doesn't work:
POST /r4/$graphql HTTP/1.1
Host: test.fhir.org
Content-Type: application/json
{"query":"Patient(id:\"8\"){id name { text given family}}"}
Robert Winterbottom (Jan 17 2019 at 14:50):
If there is anything we can do to help with this, we would love to contribute where appropriate. Unfortunately (or fortunately if your a javascript developer), all of our schemas are written as JS files, not .graphql files so the files themselves are specific to the node.js ecosystem. You could start the server and run an introspectionQuery against it to get the full schema in .graphql syntax though. We could do this and include those GraphQL files on Github but they are pretty large for a full server.
I did notice something in the observation.graphql and bundle.graphql files that may cause issues when used in GraphQL. The BundleEntry contains a resource property of type Resource. While this is what is defined in the spec, in GraphQL, this means you can only include the exact resource object, so you would not be able to return Patient and Observation or any other, just what is defined here, http://build.fhir.org/resource.html.
Same thing with an Observation and any property of type Reference. We had to define them as strings on inputs when performing mutations, but on outputs, a.k.a. schemas, we define them as unions. For example, an Observation.subject can return with a resource of type patient, group, device, or location. So we have an inline union that checks the resource type and returns one of those four types to take advantage of result coercion.
Grahame Grieve (Jan 17 2019 at 15:07):
POST /r4/$graphql HTTP/1.1
Host: test.fhir.org
Content-Type: application/json
{"query":"Patient(id:\"8\"){id name { text given family}}"}
That's supposed to work
Grahame Grieve (Jan 17 2019 at 15:22):
apparently I overlooked implementing that. I will work on it
Grahame Grieve (Jan 17 2019 at 18:18):
no, this is actually a formatting issue. I'm expecting, from the graphql spec, to get this:
Grahame Grieve (Jan 17 2019 at 18:19):
{"query":"{ Patient(id:\"8\"){id name { text given family}} }"}
Grahame Grieve (Jan 17 2019 at 18:19):
- note wrapping {}. My parser is not knowing how to parse with out the {}
Rick Geimer (Jan 17 2019 at 18:20):
(deleted)
Grahame Grieve (Jan 17 2019 at 18:21):
yes that bit
Michele Korell (Mar 01 2019 at 00:09):
Hello, I've executed some test with http://test.fhir.org/r4/$graphql endpoint and it is working as described in a previus post. But I've tried to introspect GraphQL schema against the same endpoint but without success. Normally it is suppose to return graphql schema of available queries and mutations, but actually i get an empty json with { "data" : { } }. They are a particular reason that introspection is not supported?
By the way there is a new interesting project that contains all classes definitions in typescript of fhir resources (https://github.com/Ahryman40k/typescript-fhir-types). It is generated by using official fhir json definition (the one that can be download here: https://www.hl7.org/fhir/downloads.html) and we use it to wrap GraphQL fhir queries responses.
Grahame Grieve (Mar 01 2019 at 05:37):
it looks like I haven't got around to doing introspection. I'll investigate
Michele Korell (Mar 01 2019 at 15:08):
I think that GraphQL schema introspection permit to get the CapabilityStatement of the server, but directly with server's integrated graphql-tools. In this way we doesn't have to write some logic that can retrieve capabilities of following endpoints. Micro services can be connected between each others trough schema stitching and introspection allow delegation of some operations. For example in a system that manage procedure, but doesn't has locally informations about Patients, it can directly delegate the resolution to right endpoint (only if it provide GraphQL interface).
Interesting links (we implemented our system like hasura example):
- https://blog.hasura.io/the-ultimate-guide-to-schema-stitching-in-graphql-f30178ac0072/#0e66
- https://graphql.org/learn/introspection/
- https://www.apollographql.com/docs/graphql-tools/schema-stitching.html#mergeSchemas
Grahame Grieve (Mar 01 2019 at 18:49):
I understand why it would be useful
Zoltan Simon (Mar 01 2019 at 20:28):
Hi , I am just about on the journey of setting a hasura - fhirbase server for proof of concept... I have an questions on a similar topic in the fhirbase stream. The missing feature for doing it, is on hasura's backlog already. In the meantime I am looking for alternatives such us prisma.io. For that, I am trying to generate the graphql.types from json schemas... Btw is there already graphQL types officially released? I am also new to this domain so any advise or experience could be helpful. Thank you
Grahame Grieve (Mar 01 2019 at 22:05):
you can get grapql definitions for the json representation of the resources at http://build.fhir.org/observation.graphql (or similar pattern)
Michele Korell (Mar 01 2019 at 22:05):
We get the actual schema from build fhir server, for example you can get the procedure schema at http://build.fhir.org/procedure.graphql endpoint. Or you can donfload the Asymmetrik implementation from git (https://github.com/Asymmetrik/graphql-fhir), run the server and use graphql/utilities and use printSchema ( https://graphql.org/graphql-js/utilities/#printschema) to generate the whole schema in a single file. The only inconvenient is that the output file has 127'473 lines.
Zoltan Simon (Mar 01 2019 at 22:09):
Thx, You saved me a lot of time :) Let's see what will work (or not) on this "zero effort" server experiment.
Zoltan Simon (Mar 01 2019 at 22:21):
@Michele Korell - Thx, I found the Asymmetrik stack too. It looks like an "interpretation / implementation done". Using the #printschema tool would be a reverse engineering or kind of. I would go for a solution where I can have a "golden source" schema that I can load on the server. This way I would get better compliance. An option would be just go with the Asymmetrik stack and follow their way instead of building one. I am on the first phase, learning & understanding fhir, trying to convert magic to knowledge. I might end up on the stack anyway..
Michele Korell (Mar 01 2019 at 22:30):
We used asymmetrik implementation as mock server between front-end and back-end. We put json resources examples of our implementation guide at resource resolvers. The graphql server example is also cool because it implements the OAuth2 SMART strategy (https://github.com/Asymmetrik/graphql-fhir/blob/master/FAQ.md#authentication).
Zoltan Simon (Mar 01 2019 at 22:46):
Yes asymmetrik stack looks solid. I am working in the Danish space (NemID auth) and I am also planning to build a React App on top of the stack. This SMART strategy is talking about jquery and plain html and iframes, not sure how much can be applied. (I might misunderstand it, lot to learn in this space...)
Michele Korell (Mar 01 2019 at 22:54):
Our setup are Angular and iOS app at front-end and using apollo graphql client. So at backend we decided to provide the SMART on FHIR auth strategy, GraphQL interface and optional RESTful endpoint if needed for external providers.
Michele Korell (Mar 04 2019 at 07:30):
Hello, i've tried to run the graphql schemas get from build.fhir.org site with an Apollo GraphQL server but they are some problems:
- At the type ElementBase, property extension : [Extension] { <- this open bracket cause error.
- input type have the same name as type, this generate an error because it is a double generation. As is explained at https://graphql.org/learn/schema/#input-types for an input type we cannot mix with type, so when is a double declaration the system can't differentiate.
- Queries are defined as type. For example inside patient.graphql we can find:
type PatientReadType {
Patient(id : ID!) : Patient
}
But for GraphQL they are two special types, Query and Mutation who are the only can have this kind of declarations, something like this:
extend type Query {
Patient(id:ID!): Patient
}
And just define an empty base type Query inside types.graphql:
type Query {
_empty: String
}
(Has to be tested)
Robert Winterbottom (Mar 04 2019 at 14:46):
Hey @Michele Korell and @Zoltan Simon, I am the lead developer building the Asymmetrik GraphQL FHIR server example and would love to hear any feedback you guys have for us on how it's been working for you or if there is anything else we can add that would be helpful. I'll admit, the single schema is massive (I use Atom text editor and it frequently crashed trying to do syntax highlighting on that), would it be better if we offered a way to grab schemas for individual resources? We are generating a lot of code from structure definitions (everything in resources folder is 100% generated and everything else is more custom) so generating additional things would not be very difficult for us.
Michele Korell (Mar 04 2019 at 16:24):
Hey @Robert Winterbottom , I've a question about your generation, inside R4 release i see that you limit the resource extension for reference into a union, from which fhir definition you get these infos? Inside full JSON definition we didn't find that.
For example from your R4 schema:
"""
This observation is a group observation (e.g. a battery, a panel of tests, a set
of vital sign measurements) that includes the target as a member of the group.
"""
union ObservationhasMember_hasMember_Union = Observation | QuestionnaireResponse | MolecularSequence
We are just looking how to implement resources validation layer whit our internal FHIR implementation guide.
Robert Winterbottom (Mar 04 2019 at 17:31):
Ahh yes, this was a recent update in our code generator. Our first pass on code generation used JSON schemas but we found more useful information when parsing structure definitions. So in our V2, we download the JSON version of FHIR definitions from here, https://www.hl7.org/fhir/downloads.html, not the JSON schemas but the JSON representation of the structure definitions (for this case specifically profiles-resources.json and profiles-types.json). These include information specifying which types of references are allowed, which, in this case, you can see here, https://www.hl7.org/fhir/observation-definitions.html#Observation.hasMember. It specifies the type is reference, and specifically one of Observation, QuestionnaireResponse, or MolecularSequence.
Robert Winterbottom (Mar 04 2019 at 17:58):
Validation was actually one of the reasons we started moving away from JSON schemas, we just found the structure definitions have much more info and actually worked a lot better in our code generator. If you are going to be in Washington for DevDays at the Microsoft Campus, I believe my colleague Jon and myself are going to be giving a talk on code generation at a higher level and what problems we think it can solve.
Michele Korell (Mar 04 2019 at 19:30):
You did a very good job! I was thinking that you used the structure definition. Actually we are developing a lot of microservices and we rely on GraphQL schema stitching to distribute the types, queries and mutations.
For the DevDays unfortunately our hospital is based in Switzerland and at the moment is not planned to go at kind of events. Maybe in the future...
Robert Winterbottom (Mar 04 2019 at 20:54):
Nice, schema stitching is a very interesting concept. We generated a massive schema for the open source version but our code generator does some more advanced things, such as generating code for custom profiles to make a much smaller/lighter server implementation. I can add a note to look into exposing the files individually per resource for one of our upcoming sprints since it should be a light lift to add it. We are trying to add features consistently while working on our enterprise version for either the June dev days or the November one in Amsterdam.
Michele Korell (Mar 29 2019 at 23:19):
Hello,
I started to build an example server for Patient resource with Apollo GraphQL. I get the Patient GraphQL schema from http://build.fhir.org/patient.graphql. As reported before I had to correct a lot of error in the schema, add Patient to Query type to permit to execute patient query and spend a lot of time to correct base data types. Actually is just an example and it doesn't support full CRUD. I've published the result at https://github.com/michelekorell/patient-fhir-graphql and you can find the GraphQL schema at https://github.com/michelekorell/patient-fhir-graphql/blob/master/src/graphql/patient.ts
I think that it can be a good idea if we discuss about graphql specs and how define graphql to let working with common project like GraphCool, Prisma, Apollo, ... Actually the specs that can be found on build.fhir.org can't be used directly. I have the impression that schemas are automatically generated, so:
- there is a section in github that contain this code?
- We can participate to fix some problems?
Bye!
Josh Mandel (Mar 31 2019 at 01:06):
@Grahame Grieve I think you've done this generation for the spec?
Grahame Grieve (Mar 31 2019 at 02:30):
yes this is on my list to investigtae
Michele Korell (Apr 01 2019 at 06:25):
Actually we are looking how to generate the schema starting from resource sd. One of our colleague already developed a generator to create fhir resources from the json definitions, so I can look with him to add some templates to generate the graphql spec. This week I go to discuss with other implementers at our annual hl7 swiss meeting about graphql.
Grahame Grieve (Apr 01 2019 at 06:36):
you have an annual swiss hl7 meeting about graphQL?
Michele Korell (Apr 01 2019 at 06:37):
It is not about GraphQL, but Oliver Egger invite me to discuss about our work during the mini connectathon at morning session. How I wrote before it wasn't clear.
Grahame Grieve (Apr 01 2019 at 06:47):
ok thx. I will look into this tonight
Grahame Grieve (Apr 01 2019 at 09:00):
... and in types.graphql
Grahame Grieve (Apr 01 2019 at 09:00):
ok. I can easy fix teh ElementBase declaration
Grahame Grieve (Apr 01 2019 at 09:00):
input type have the same name as type,
where exactly is this error?
Michele Korell (Apr 01 2019 at 09:13):
This is a global problem, in GraphQL definition we cannot specify the same name for input and type because this create a circular reference. common implementations cannot handle this case. For example in my apollo graphql test implementation I removed all the input types to permit to use the schema. (see https://stackoverflow.com/a/41515879 as explanation)
Grahame Grieve (Apr 01 2019 at 09:14):
so what wasn't clear is where my schema actually does that
Michele Korell (Apr 01 2019 at 09:16):
Actually for example at patient.graphql whe have:
-
type Patient { ... } at line 3
and after: -
input Patient {...} at line 61
Grahame Grieve (Apr 01 2019 at 09:18):
uh that's a generation error -they are identical, no?
Grahame Grieve (Apr 01 2019 at 09:18):
no type vs input. so I need to namespace the input types?
Michele Korell (Apr 01 2019 at 09:19):
The specification advice to put Input after the resource name (https://graphql.org/learn/schema/#input-types)
Grahame Grieve (Apr 01 2019 at 09:21):
ok. I sorted that.
Grahame Grieve (Apr 01 2019 at 09:21):
so I don't understand your 3rd issue either
Michele Korell (Apr 01 2019 at 09:22):
I found other error at line 229 of patient.graphql: PatientUpdate(id: IDresource: Patient): PatientUpdate -> after ID type they is not comma before resource.
Grahame Grieve (Apr 01 2019 at 09:24):
k. anything more?
Michele Korell (Apr 01 2019 at 09:24):
I'm looking with a colleague
Grahame Grieve (Apr 01 2019 at 09:26):
k. I'll send you a regenerated patient.graphQl shortly.
Michele Korell (Apr 01 2019 at 09:26):
Maybe I miss understand how implements queries inside type definition.
Grahame Grieve (Apr 01 2019 at 09:26):
but also, seems like you want a single fhir.graphql for all resources?
Michele Korell (Apr 01 2019 at 09:28):
It can be useful to create a complete server with standard libs like apollo, but not required
Michele Korell (Apr 01 2019 at 09:29):
with node package graphql-tools we can load all .graphql separately
Grahame Grieve (Apr 01 2019 at 09:30):
Michele Korell (Apr 01 2019 at 09:32):
Starting from line 124 for query PatientList is a space after each argument and before the ':'
Grahame Grieve (Apr 01 2019 at 09:33):
there shouldn't be?
Michele Korell (Apr 01 2019 at 09:34):
Michele Korell (Apr 01 2019 at 09:35):
Now I'm trying to modify my sample Patient server to use it
Grahame Grieve (Apr 01 2019 at 09:36):
I feel as though it violates all specification logic that the space matters
Grahame Grieve (Apr 01 2019 at 09:37):
still, it's not hard to remove them:
Michele Korell (Apr 01 2019 at 09:37):
We have to ask to facebook they do like that
Grahame Grieve (Apr 01 2019 at 09:38):
Michele Korell (Apr 01 2019 at 09:41):
the parser of vscode like it better! thanks a lot. Now I try to integrate it inside my test server
Grahame Grieve (Apr 01 2019 at 09:43):
ok. let me know if there's more, and then we'll schedule this as an R4 technical correction
Michele Korell (Apr 01 2019 at 09:51):
line 90 input PatientContact was not generated as PatientContactInput
Michele Korell (Apr 01 2019 at 09:53):
same for input PatientCommunication and PatientLink
Michele Korell (Apr 01 2019 at 09:59):
I think is more complicated, by i corrected it by hand and actually all resources specified inside PatientInput has to be as input type. So for type HumanName i have to wrote an HumanNameInput that is used by PatientInput
Michele Korell (Apr 01 2019 at 10:00):
I have to fix by hand all data types before try to run my sample server
Michele Korell (Apr 01 2019 at 10:02):
They are some log when i try to run the apollo-server with this schema:
The type of PatientInput.generalPractitioner must be Input Type but got: [Reference].
The type of PatientInput.managingOrganization must be Input Type but got: Reference.
The type of PatientInput.link must be Input Type but got: [PatientLink].
Michele Korell (Apr 01 2019 at 10:04):
Once the schema is ok, I can implement a server that permit introspection of official fhir-graphql schema definitions.
Grahame Grieve (Apr 01 2019 at 12:13):
duh. I think I chased everything down here:
Grahame Grieve (Apr 01 2019 at 12:14):
Grahame Grieve (Apr 01 2019 at 12:14):
Michele Korell (Apr 01 2019 at 13:16):
Hello thanks a lot!
They are some small errors for the types.graphql:
- scalar is written starting with uppercase
- ElementBase there is no definition for ElementBaseInput
- at line 27 date scalar is defined a second time
- at line 33 the uri scalar is defined a second time
- at line 1072 url: null -> url: uri!
- at line 1126 url: nullInput! -> url: uri!
- at line 1183 given inside HumanName is not an array
- at line 1195 same for HumanNameInput
Michele Korell (Apr 01 2019 at 14:21):
Hello, here is the file i create starting from patient.graphql and types.graphql to let my sample server work. I've committed the last modification of my sample server on github.
patient-sample-srv.graphql
VP Herisse (May 14 2019 at 13:25):
(deleted)
VP Herisse (May 14 2019 at 13:28):
(deleted)
VP Herisse (May 14 2019 at 13:29):
Hello, I've executed some test with http://test.fhir.org/r4/$graphql endpoint and it is working as described in a previus post. But I've tried to introspect GraphQL schema against the same endpoint but without success. Normally it is suppose to return graphql schema of available queries and mutations, but actually i get an empty json with { "data" : { } }. They are a particular reason that introspection is not supported?
By the way there is a new interesting project that contains all classes definitions in typescript of fhir resources (https://github.com/Ahryman40k/typescript-fhir-types). It is generated by using official fhir json definition (the one that can be download here: https://www.hl7.org/fhir/downloads.html) and we use it to wrap GraphQL fhir queries responses.
Was looking for this all over google, Thank you Michele! :)
Mostafa Sholkamy (Jun 08 2019 at 12:15):
@Michele Korell I am interested in your efforts for generating GraphQL types out of JSON ( it would equal structure definition resource I think ).
Right now I am working on stuff that may this process easier it's for node.js for now, this is still in a very early stage both not completely done.
- graphql-fhir-directives https://github.com/shalkam/graphql-fhir-directives with aim to include all profiling capabilities into graphql schema.
it now has @card
which adds min
and max
for arrays and @binding
directives which gets a code system json convert the field into enum type.
- https://github.com/shalkam/graphql-fhir-primitive-types this one adds primitive fields as defined in FHIR specs along with their resolvers.
nicola (RIO/SS) (Jun 08 2019 at 18:26):
We started the implementation of GraphQL in Aidbox - interested in this topic as well.
Grahame Grieve (Jun 09 2019 at 00:53):
Why are you generating the graphql types?
Mostafa Sholkamy (Jun 09 2019 at 07:07):
@Grahame Grieve Most of the primitive data type in FHIR doesn't have their corresponding types in GraphQL, for example:-
- We have different kinds of Integers values like positiveInt
, unsignedInt
and plain integer
- Same goes for string
type we have also many sub-types basically with some regex on top
So, graphQL SDL (Schema definition language ) gives us the option to declare scalar
( = primitive ) types like this :-
scalar positiveInt
And a resolver for this type can be implemented for any graphQL server implementation in any language.
And example for node.js
import { GraphQLScalarType } from 'graphql' import { GraphQLError } from 'graphql/error' import { Kind } from 'graphql/language' export default new GraphQLScalarType({ name: 'positiveInt', description: 'an integer with value more than zero', serialize: value => { return value }, parseValue: value => { return value }, parseLiteral: ast => { if (ast.kind !== Kind.INT) { throw new GraphQLError( 'Query error: Can only parse integers got a: ' + ast.kind, [ast] ) } if (!(ast.value > 0)) { throw new GraphQLError('Query error: Not a valid positive integer', [ast]) } return ast.value } })
Notice we just add validation that it's an integer and the value is more zero.
So, this is a declarative straight-forward way to represent FHIR data types and eventually resources using purely GraphQL SDL without any programming languages involved.
Only later on developers will implement resolvers for these based on FHIR specs and their favorite programming language
Grahame Grieve (Jun 09 2019 at 07:09):
that wasn't quite what I was asking - we already defined graphql schema - see http://build.fhir.org/patient.graphql - why not use those?
Mostafa Sholkamy (Jun 09 2019 at 07:20):
Most of primitive types doesn't exist in GraphQL like positiveInt
, code
, oid
... etc
Mostafa Sholkamy (Jun 09 2019 at 07:23):
For me I may just use it even as a matter of naming to strictly follow FHIR specs, for example I may declare a scalar id
in lower case, and just use GraphQL default ID
scalar type for the resolver
SDL: scalar id Resolver: const { GraphQLID } = require('graphql') module.exports = GraphQLID
Grahame Grieve (Jun 09 2019 at 09:41):
I'm not sure that's an answer to my question?
Mostafa Sholkamy (Jun 09 2019 at 18:42):
that wasn't quite what I was asking - we already defined graphql schema - see http://build.fhir.org/patient.graphql - why not use those?
Not sure what do you mean by those
here, is it scalar types like :-
deceasedDateTime: dateTime language: code
or do you mean built-in GraphQL scalar types?
Grahame Grieve (Jun 09 2019 at 18:43):
why not use the graphQL definitions that are defined as part of the FHIR standard?
Mostafa Sholkamy (Jun 09 2019 at 20:13):
If we talk specifically about the patient.graphql
, it's incorrect as regard GraphQL syntax.
For these two fields for example:
deceasedDateTime: dateTime language: code
we need to declare two scalar types:
scalar dateTime scalar code
Otherwise it will through an error if I put this schema as a part of the server configuration
Grahame Grieve (Jun 09 2019 at 20:14):
well, let's fix that. are there other issues?
Mostafa Sholkamy (Jun 09 2019 at 20:33):
I will double check
Grahame Grieve (Jun 10 2019 at 13:05):
does any one know what the right mime type for the graphql schema is ?
Dan Connolly (Jun 10 2019 at 15:17):
I looked around, but I don't see a mime type for graphql schemas, @Grahame Grieve
Grahame Grieve (Jun 10 2019 at 15:36):
I'll ask on the graphql face book page
Robert Winterbottom (Jun 10 2019 at 16:15):
There is some information on that here, https://graphql.org/learn/serving-over-http/#post-request, in short, it mentions you should use application/json. However, another option available for post-requests is to use application/graphql. If using application/graphql then you should treat the post body as a graphql query string (however I do not think you can use variables with this approach so application/json is probably better for that reason)
Grahame Grieve (Jun 10 2019 at 17:27):
the schema is not valid json
Grahame Grieve (Jun 10 2019 at 17:28):
I am asking about the schema itself
Robert Winterbottom (Jun 10 2019 at 18:25):
ahh right, sorry, I misinterpreted that. Unfortunately application/graphql is for query strings so that would not fit either. In the javascript world, they are often treated as strings and then passed into parsers, so I'm not sure what the official mime type would/should be for a .graphql schema. Would be curious to hear what the facebook page says about that as well
Grahame Grieve (Jun 10 2019 at 20:26):
there is no mime type
Michele Korell (Jun 11 2019 at 10:05):
Hello, actually the schema I put in my demo https://github.com/michelekorell/patient-fhir-graphql is a merge of the specifications that we can found on build.fhir.org. Some time ago @Grahame Grieve made some fix and actually it work. The only change I made is to add the Query type that contains resource query. I think that in official FHIR graphql schemas are some little problem of specification with operation on a resource inside a type definition. But on my point of view the declaration of scalar type is normal. The types are the same specified inside FHIR definition and has to respect the FHIR regex and not to depend on facebook's base type definition. So we can guarantee the interoperability between GraphQL and RESTful interfaces.
After small search for mime type at official list I didn't find any specification about graphql. After looking our services requests we can see that a graphql query execute with a POST is an application/json with following structure
{ "operationName": "GetSomeThings", "query": "query getSome($var:type) {...}", "variables" : { "var": 123 } }
Grahame Grieve (Jun 13 2019 at 16:11):
@Michele Korell @nicola (RIO/SS) @Robert Winterbottom @Mostafa Sholkamy Are we interested in creating a set of test cases based on the resources included in the specifications so that we can check that the graphQL implementations are consistent?
Michele Korell (Jun 13 2019 at 16:29):
Yes, I'm really interested! We currently use a lot of graphql on our electronic patient record system!
nicola (RIO/SS) (Jun 13 2019 at 17:59):
Should we develop a test suit for that?
Michele Korell (Jun 13 2019 at 21:11):
The idea of the test is to provide multiples uses cases to submit to endpoint where where can perform simple resource crud operation and try to resolve more complex dependencies by using resource extension defined in Reference field?
I have just a question about FHIR GraphQL specification at chapter 3.1.2.8 Mutations, the create operation is intended to be used like:
type Mutation { PatientCreate(res: PatientInput): Patient }
and inside patient.graphql is specified like field argument
type PatientCreateType { PatientCreate(resource: PatientInput): PatientCreation }
In this case to make my demo I made some modification on Patient.graphql file. By the way I made an error by putting the PatientCreate operation inside query type, oups...
Robert Winterbottom (Jun 14 2019 at 00:19):
@Grahame Grieve I think that would be a great idea. Are you thinking some mock queries/scenarios and just documenting the results on the spec page?
Grahame Grieve (Jun 14 2019 at 01:08):
well, yes. I'm imagining a Json document with an array of objects each of which has a query (string) and either an error (String) or a json object that is the data output of the query. A client that knows how to follow the document could test any server
Robert Winterbottom (Jun 14 2019 at 12:55):
That sounds good to me. We have a test framework in place so something like that would be very useful for us in the CI process as well as for our end users.
Mostafa Sholkamy (Jun 14 2019 at 16:29):
@Grahame Grieve I've already done some tests on my own custom resources in node.js here: https://github.com/shalkam/gql-fhir-patient-example/blob/master/tests/patient/index.test.js.
So, Where to find schemas to tests? I only have http://build.fhir.org/patient.graphql because of the discussions we had ... I can start with this one.
If there are more please let me know
Michele Korell (Jun 14 2019 at 17:12):
@Robert Winterbottom @Grahame Grieve Actually we already have some UI tests on cypress ti intercept graphql queries and return mock data. For the future we plan to do the same think with nodejs backend. It can be a shared project, something like a web hook that permits to execute a test on selected endpoint and resources. At end of the operation it can return a mocha report about the test (or other format)
Grahame Grieve (Jun 15 2019 at 19:31):
so each of us will have different test frameworks, of course. What I want is to standardise the tests that they apply. With that in mind, I offer this as a starting position - can we agree to this format, and get this test passing on our servers?
Grahame Grieve (Jun 15 2019 at 19:32):
Grahame Grieve (Jun 15 2019 at 19:36):
I guess the first key question is - should the tests create the resources that they operate on? or should they assume a pre-configured read-only interface?
Grahame Grieve (Jun 15 2019 at 19:40):
@Michele Korell I see that there are 2 different rules made here. What should we do?
- the specification calls for the return of a simple patient; the location header and operation outcome header would be lost
- the schema anticipates a wrapper object that carries those and the resource
Definitely in conflict with each other; how to resolve?
Michele Korell (Jun 15 2019 at 19:53):
@Grahame Grieve your speaking about the test specification or the GraphQL query definition for resources?
Grahame Grieve (Jun 15 2019 at 19:54):
that is in response to your question about the mutation in the schema above. I'm not talking about the tests right now
Grahame Grieve (Jun 15 2019 at 19:56):
I'm looking at the issues with the generated schema - the scalar types and the complex types are all defined in types.graphql. The problem is that graphql doesn't define a way for one schema to reference another. (things like https://blog.apollographql.com/modularizing-your-graphql-schema-code-d7f71d5ed5f2 are all about js pre-processing).
So the options appear to be:
- add a documentation note to each resource schema noting the dependency on types.graphql
- duplicate types.graphql into every resource schema
- generate one single large combined schema
Thoughts?
Grahame Grieve (Jun 15 2019 at 20:00):
(note: there's a typo in http://build.fhir.org/types.graphql - Scalar not scalar - that will fixed once we resolve this question. Also, I'll add a download that includes all the graphql schema in a single zip as well)
Michele Korell (Jun 15 2019 at 20:04):
They are another differents ways with apollographql tools. for example with transform you can load multiples files and manipulate queries. Or maybe have an official endpoint that provide each FHIR version and compatible for introspection, we can perform some schema federation ( before was schema stitching ) to build our endpoint schema.
Grahame Grieve (Jun 15 2019 at 20:05):
... I think you mean, we should have a single schema
Grahame Grieve (Jun 15 2019 at 20:09):
or maybe: generate all the fragments, and also publish a single combined schema
Michele Korell (Jun 15 2019 at 20:15):
Have a big schema with all is simplier, but we lost the overview. In our hospital we made a service that only provide a big generated schema using introspection thecnics, but we found a lot of error and it is difficult to use. I like the idea to have Patient.graphql, but in this case we must have at least Scalar and complex types in a base schema and for the other resources we can use extension operation to do something like:
extend type Query { Patient(...) : Patient PatientList(...) : Bundle .... }
Grahame Grieve (Jun 15 2019 at 20:16):
I don't understand this. types.graphl is the base schema, but how does it get included? What does 'extend' have to do with that?
Michele Korell (Jun 15 2019 at 20:17):
Actually, types.graphql contains only scalars and complex type?
Grahame Grieve (Jun 15 2019 at 20:18):
right. it's your base schema
Michele Korell (Jun 15 2019 at 20:20):
So, if I have understand right GraphQL, to merge two .graphql files we have to define somewhere the type Query {...} and in all other .graphql files we can use extend type Query
Grahame Grieve (Jun 15 2019 at 20:20):
where is that documented?
Michele Korell (Jun 15 2019 at 20:21):
And for me the best place to define base Query and Mutation is inside types.graphql because in any case we need Scalars and complex types.
Wait a momen, i go search the doc
Michele Korell (Jun 15 2019 at 20:23):
Here: https://www.apollographql.com/docs/graphql-tools/generate-schema/#extending-types
Grahame Grieve (Jun 15 2019 at 20:25):
so there's nothing there about schema modularity. It might be that we should actually do that, though I'm not sure where that would be useful, but it doesn't help with the current question
Michele Korell (Jun 15 2019 at 20:27):
With apollo graphql-tools lib we can get multiples files in one executable schema.
Maybe @Robert Winterbottom can help us resolve these question, because asymmetrik worked a lot for their FHIR GraphQL server and have more experience than me.
Grahame Grieve (Jun 15 2019 at 20:28):
the apollo tools do it by pre-processing. I presume that leads to one large schema...
Michele Korell (Jun 15 2019 at 20:29):
In our implementation we use to load multiples schemas and merge with base types and scalars
Michele Korell (Jun 15 2019 at 20:38):
The GraphQL federation is a concept that i didn't study until now, but it can be a way to see what it could be done in case we have a big schema or multiples definitions. Our experience with a big schema is that is difficult to handle and find errors.
Michele Korell (Jun 15 2019 at 20:41):
I found an introduction chapter on apollographql federation: https://www.apollographql.com/docs/apollo-server/federation/introduction/
Michele Korell (Jun 15 2019 at 20:49):
But it is based on apollographql framework...
Grahame Grieve (Jun 15 2019 at 20:50):
Note that the _service field is never exposed at the gateway. This is soley done to compose the schema
Grahame Grieve (Jun 15 2019 at 20:50):
so, once again, private to Apollo
Grahame Grieve (Jun 15 2019 at 20:54):
Our experience with a big schema is that is .. find errors.
because it's big? or because there's errors to find?
Michele Korell (Jun 16 2019 at 15:28):
The problem of big schema is handle personal's IG restrictions
Michele Korell (Jun 16 2019 at 15:30):
Elsewhere our reference server work well with the big schema
Grahame Grieve (Jun 16 2019 at 20:39):
handle personal's IG restrictions
can you try this line again please
Robert Winterbottom (Jun 16 2019 at 21:32):
the apollo tools do it by pre-processing. I presume that leads to one large schema...
Yes from what I have seen with apollo tools that is correct. It essentially forces you to wrap those types as strings so they can be stitched together into one big schema (for your root schema) and then you can also use them as smaller pieces for instance queries (e.g. Patient/<patient-id>/$graphql).
I (or Asymmetrik currently) don't use Apollo tools because facebooks own JS library works really well for our case. We also autogenerate schemas individually so modularity is extremely simple. However, our schemas are not in the schema language so they are not portable to other languages, they are specific to graphql-js
.
Robert Winterbottom (Jun 16 2019 at 21:34):
As far as loading the types.graphql
, they need to be defined when they are used. In our case, we just require each module and all it's dependencies and they all work just fine, if you want to see what we did, here is an example of the patient resource, https://github.com/Asymmetrik/graphql-fhir/blob/master/src/resources/4_0_0/schemas/patient.schema.js. So if you are using Apollo, you may have to either load everything together with makeExecutableSchema
or redefine them in each schema where they are used.
Robert Winterbottom (Jun 16 2019 at 21:40):
@Grahame Grieve As far as the tests go, that setup file would work fine for us and be very easy to integrate.
As for whether or not the tests should create the resources or assume they are present and the API is read only. I like the idea of supporting read only but does that mean we would need to have the example resources present at all times in our system (so end users can run the tests against our implementations themselves)?
Grahame Grieve (Jun 16 2019 at 22:00):
so the upshot is: there is no support at the schema level for stitching. We should probably publish modular and stitched schema
Grahame Grieve (Jun 16 2019 at 22:01):
if you write the schema as read-only then you need a special test set up, so you can run the tests. Or you always have test resources - and only test resources available - which means, a special test set up.
Grahame Grieve (Jun 16 2019 at 22:01):
but if the test scripts create the resources, you still end up with test resources on the server.... so my take is that you need a special testing server anyway.
Grahame Grieve (Jun 16 2019 at 22:02):
I prefer to run the test against a pre-canned set up since I already have that pre-canned setup ;-)
Robert Winterbottom (Jun 17 2019 at 12:45):
Our testing framework has some convenient hooks for setting things like this up so this all sounds good to me
Grahame Grieve (Jun 17 2019 at 17:46):
ok. so we don't create the resources. But i might nominate the dependencies anyway in the json just to be clear. So any chance we can confirm that this test passes ok for @Robert Winterbottom and @Michele Korell (and does anyone have interest in this)?
Robert Winterbottom (Jun 17 2019 at 17:52):
Yea, I'll take a crack this afternoon at integrating it on our side and let you know how it goes
Grahame Grieve (Jun 17 2019 at 17:55):
ok thanks
Michele Korell (Jun 17 2019 at 19:37):
For me the idea is ok! I have just a doubt about the endpoint. Our implementation is based on single entry-point for all resources and not as example at resource: Patient/:id/$graphql
Did you think we can support scenarios where we run queries against base url: myfhirserver.graphql/r4 ?
What I try to say about IG is: for example we added the ! symbol where we want have parameters that in standard definition are optional. We did it in graphql so the engine check for us.
Our server are also based on facebook's js lib, the only difference from asymmetrik is that we integrate the graphql-tools lib from apollo. This permit us to manipulate multiples pieces of schema to make them executable and simplify schema stitching
Robert Winterbottom (Jun 17 2019 at 20:04):
@Grahame Grieve So I noticed a few minor things with the test script.
First was thetests.simple.url
was missing a trailing }
, so it should be like this instead: /Patient/example/$graphql?query={identifier{system,value}active,name{text,given,family}}
.
This still failed on our server because the query and results needed to include the datatype in them, so instead of query={...<return-fields>}
, I needed to change it to query={Patient{...<return-fields>}}
. I can't remember off the top of my head what the spec says so I'll need to look this up, but I do not think we are supposed to have an anonymous response, I think the response always needs to reference the data type, e.g. Patient.
Last, the tests.simple.output
was missing the identifier and active response fields, they are in the example patient I downloaded from https://www.hl7.org/fhir/patient-example.json. So I added those in. Our server also returned text:null
in some of the objects, like name. This does not cause the test to fail because of the matcher I am using in my tests.
However, after those changes, the tests work fine against my local server.
Robert Winterbottom (Jun 17 2019 at 20:07):
Also, I think we are in an interesting use case. Our server is open source and a facade, so the version on Github has no backend setup. To make this work, I setup a mock resolver that returned the patient-example.json
. I will probably add instructions for anyone implementing a server based on our open source version, that they need to update the test to work against their back end with their resolvers.
Robert Winterbottom (Jun 17 2019 at 20:09):
For me the idea is ok! I have just a doubt about the endpoint. Our implementation is based on single entry-point for all resources and not as example at resource: Patient/:id/$graphql
Did you think we can support scenarios where we run queries against base url: myfhirserver.graphql/r4 ?What I try to say about IG is: for example we added the ! symbol where we want have parameters that in standard definition are optional. We did it in graphql so the engine check for us.
Our server are also based on facebook's js lib, the only difference from asymmetrik is that we integrate the graphql-tools lib from apollo. This permit us to manipulate multiples pieces of schema to make them executable and simplify schema stitching
I agree, I think it would be nice to also have it able to test against the root schema. Could we add a property to the test snippet that signifies whether its an instance query against a single patient with id or whether it's against the root schema?
Grahame Grieve (Jun 17 2019 at 21:30):
ok I updated the tests. I added instance-tests and root tests
Grahame Grieve (Jun 17 2019 at 21:31):
This still failed on our server because the query and results needed to include the datatype in them, so instead of query={...<return-fields>}, I needed to change it to query={Patient{...<return-fields>}}
this is not what the FHIR spec currently says, and I don't see why that should be. The fact that it's Patient is already known by context, so there's no need to be explicit about that
Robert Winterbottom (Jun 18 2019 at 12:17):
This still failed on our server because the query and results needed to include the datatype in them, so instead of query={...<return-fields>}, I needed to change it to query={Patient{...<return-fields>}}
this is not what the FHIR spec currently says, and I don't see why that should be. The fact that it's Patient is already known by context, so there's no need to be explicit about that
I had issues with doing that in the past (which is why our server did it that way) but was trying it again last night and was able to make it work that way without issue. Should be fairly easy to upgrade our server to use it that way for that context.
Robert Winterbottom (Jun 18 2019 at 12:18):
For the root tests, I think you will need to include the Patient context in the results since the query can hit multiple data types
Grahame Grieve (Jun 18 2019 at 12:36):
indeed it does, no?
Robert Winterbottom (Jun 18 2019 at 12:59):
I dont see it in the results for root-tests
Robert Winterbottom (Jun 18 2019 at 14:47):
Hmm, @Grahame Grieve, For the instance queries in your implementation, do you have to specify a resolver for each field?
When I use queries like this: query={Patient{...<return-fields>}}
, it's easy for us to specify a Patient resolver that gets called once and returns the whole patient object. I realized through some more testing this morning that when I was switching our implementation to support query={...<return-fields>}
, it invokes the fieldResolver once for each field. I was just curious if your implementation supported a single resolver for the whole object versus one resolver per field.
Grahame Grieve (Jun 18 2019 at 17:49):
I don't know anything about resolvers. I don't see anything about them in the standard?
Grahame Grieve (Jun 18 2019 at 17:51):
you will need to include the Patient context in the results
I thought that this was it:
/$graphql?query={Patient(id:example){identifier{system,value}active,name{text,given,family}}}
Patient is specified explicitly
Robert Winterbottom (Jun 18 2019 at 18:16):
Ahh sorry, forgot to elaborate, so in that case (/$graphql?query={Patient(id:example){identifier{system,value}active,name{text,given,family}}}
) patient is identified in the query, but it's missing in the resulting data. When hitting the root schema, a query could also look like this:
/$graphql?query={Patient(id:example){active}Observation(id:example){active}}
So the results should look something like this:
{ "data": { "Patient": { "active": false }, "Observation": { "active": false } } }
Without having the Patient and observation in the results, there is no way the consumer can know exactly what data type the fields are related to. I think the test file is supposed to look like this:
{ "root-tests": { "simple": { "description": "Just a simple test of the basic graphQL engine: a simple query on a known patient (example, from the spec)", "url": "/$graphql?query={Patient(id:example){identifier{system,value}active,name{text,given,family}}}", "output": { "data": { "Patient": { "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" }] } } } } } }
Robert Winterbottom (Jun 18 2019 at 18:27):
I don't know anything about resolvers. I don't see anything about them in the standard?
They discuss them here, https://graphql.org/learn/execution/. Essentially, anything that takes an argument will need a resolver to resolve any encapsulated data based on the provided arguments. In the case of the instance query where there aren't any arguments provided via the graphql query, just the rest param, you have to use field resolvers. At least that's the case in JavaScript. I think I can write an abstraction so that anyone implementing something based on our solution, won't have to worry about that. This may be a Javascript only thing.
Robert Winterbottom (Jun 18 2019 at 18:40):
Also, should the search param be _id
instead of id
(query={Patient(_id:"example")
)? I do not see id
listed in the FHIR spec as a valid search parameter for patient
Grahame Grieve (Jun 18 2019 at 18:55):
oh. updated the tests for both issues.
Robert Winterbottom (Jun 18 2019 at 18:58):
Great thanks. I'll test it again a little later tonight
Michele Korell (Jun 18 2019 at 22:08):
Hello, actually I'm in holidays for one and half week. My wife forbidden me to take the pc with. So I go to start my test when I'm back.
Grahame Grieve (Jun 18 2019 at 22:10):
ok
Robert Winterbottom (Jun 19 2019 at 12:22):
Hello, actually I'm in holidays for one and half week. My wife forbidden me to take the pc with. So I go to start my test when I'm back.
Did you sneak away to write this message ;)
Robert Winterbottom (Jun 19 2019 at 12:25):
oh. updated the tests for both issues.
Looks like the JSON is missing some commas, i'll paste a working version below that fixes the commas and adds quotes to the id in the root-test (without the quotes the graphql parser is treating the _id as an enum)
Robert Winterbottom (Jun 19 2019 at 12:26):
{ "@type": "graphql-server-tests", "instance-tests": { "simple": { "description": "Just a simple test of the basic graphQL engine: a simple query on a known patient (example, from the spec)", "url": "/Patient/example/$graphql?query={identifier{system,value}active,name{text,given,family}}", "output": { "data": { "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" }] } } } }, "root-tests": { "simple": { "description": "Just a simple test of the basic graphQL engine: a simple query on a known patient (example, from the spec)", "url": "/$graphql?query={Patient(_id:\"example\"){identifier{system,value}active,name{text,given,family}}}", "output": { "data": { "Patient": { "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" }] } } } } } }
Grahame Grieve (Jun 19 2019 at 12:30):
fixed
Robert Winterbottom (Jun 19 2019 at 12:38):
Great thanks, works for me now!!
Grahame Grieve (Jun 19 2019 at 12:38):
great. time to add some more tests ;-)
Michele Korell (Jul 09 2019 at 08:06):
Hello,
did you already think how manage resource update when somehow ask partial resource via GraphQL and send back the same object with some changes? Is better to update only parameters that are present or replace the resource?
If someone make bad operations, it can erase some part of information.
What you think about that?
Robert Winterbottom (Jul 09 2019 at 16:51):
Hey Michele.
For our implementation, when users are doing any kind of mutations, we plan to only update the targeted resource with the provided properties and not modify any existing properties that are not provided. We think that replacing the full resource on a mutation could lead to accidental deletes of some properties and would also then force users to ask for the full object every time. However, after talking with Grahame and others in Seattle, we also plan to allow writes via REST since there are some things with writes that are much more difficult in GraphQL (e.g. input unions are not allowed in GraphQL) than in REST.
Grahame Grieve (Jul 10 2019 at 22:49):
my personal opinion is that graphQL writes are a nightmare. It's find to say 'accept the object with some changes" until you discover that there was a filtered list in there. now what?
Grahame Grieve (Jul 10 2019 at 22:49):
I know the graphQL people want to use their hammer so writes are going to be treated as a nail... but I think it's a very bad idea. POST/PUT/PATCH should be the go, even if that makes life more apparently difficult for the client
Michele Korell (Jul 12 2019 at 06:27):
We was thinking develop an update on only provided fields, but after some review we see that they are to much use cases. I think we have to really look to use REST interfaces inside our microservices environment and GraphQL only to query data for end user application.
Misha Kaletsky (Jul 17 2019 at 12:06):
@Grahame Grieve link seems to be dead - did these get moved to here? Using the commit hash url rather than master in case it happens again.
Grahame Grieve (Jul 17 2019 at 14:01):
they just got moved by @James Agnew
Grahame Grieve (Jul 17 2019 at 14:01):
Howard Kong (Sep 19 2019 at 15:20):
Is there a publicly available version of the graphQL-FHIR server that developers and try out (similar to http://hapi.fhir.org/)?
Grahame Grieve (Sep 19 2019 at 15:21):
both test.fhir.org and hapi.fhir.org implement graphql and are publicly available, and both are open source
Howard Kong (Sep 19 2019 at 15:36):
Thanks! I just tried, what is the graphql endpoint? I tried http://hapi.fhir.org/graphql, but got a 404.
Grahame Grieve (Sep 19 2019 at 15:39):
try the test server - the links to execute the statements are built right into the graphql page on http://build.fhir.org/graphql.html
James Agnew (Sep 19 2019 at 15:44):
Fwiw, here's a working query: http://hapi.fhir.org/baseR4/Patient/13/$graphql?query={name{text,given,family}}
Howard Kong (Sep 19 2019 at 15:52):
Now I get it. I was looking for a /graphql endpoint and was expecting a GraphiQL interface. That example link got me in the right direction. Thank you both!
James Agnew (Sep 19 2019 at 17:20):
heh- i do notice that the Content-Type
is wrong on the link I posted above. Always something.... :) Need to fix that.
Howard Kong (Sep 19 2019 at 20:52):
I tried to get some other data using that example, e.g., http://hapi.fhir.org/baseR4/Patient/14/$graphql?query={name{text,use,family,given},telecom{text,system}} or even http://hapi.fhir.org/baseR4/Patient/14/$graphql?query={name{text,use,family,given},gender} and got the same response as without the extra fields. Is there a schema associated with the graphql endpoint, something I can get via http://hapi.fhir.org/baseR4/$graphql?query={__schema {types {name}}} ?
Grahame Grieve (Sep 19 2019 at 20:53):
there should be, but I haven't got to that for test.fhir.org and I don't think that it's been done for hapi.fhir.org
Robert Winterbottom (Sep 20 2019 at 12:59):
@Howard Kong We also have one you can spin up with the option of enabling a Graphiql interface. It's an open source facade server so it's not connected to a data source and is not currently deployed. However you can easily get it up and running with a couple of npm/yarn commands. It's available at https://github.com/Asymmetrik/graphql-fhir
Howard Kong (Sep 23 2019 at 17:21):
Thanks @Robert Winterbottom !
Rik Smithies (Sep 26 2019 at 11:41):
@James Agnew I noticed that in Chrome, but it's ok in Postman, even with no headers specified.
natus (Oct 16 2019 at 22:44):
Hi GraphQL'ers . Is graphql powerful enough to support something (sorry for the non-standard yet usefull dialect):
( Condition(coding=xxx, recorded-date=2019) after(20 days) Medication(coding=yyy) ) and Patient(deaceasedBoolean=true, gender=male)
this means give me all dead male patients who had a condition 20 days after one medication. More generally do graphql handles complex operators between resources ? thanks a lot
Grahame Grieve (Oct 16 2019 at 23:54):
in principle it sounds doable. Did you try?
natus (Oct 17 2019 at 08:14):
No. I tried to master GraphQL a bit, but I didn´t find a way of expressing this.
I only have the search engine ready to eat that logic (complex relationis between fhir resources)
natus (Oct 19 2019 at 19:20):
any people experimented in GraphQL?
Robert Winterbottom (Oct 22 2019 at 13:40):
I can't see why this would not be doable. You may need to add additional arguments to your GraphQL definitions, but GraphQL allows you to define field level resolvers, which can aid in traversing relationships. You can also pass data between parent and child resolvers (check out this link, https://medium.com/paypal-engineering/graphql-resolvers-best-practices-cd36fdbcef55). With this particular query, you might need to think about how these resources are related in FHIR, e.g., who refers to who. A medication statement can point to a condition which can point to a patient, but patients do not point towards conditions. Typically in GraphQL you want to think in graphs, but there is no reason why you cannot do aggregations of the data behind the scenes and add a simple custom schema on top. I have done that for analytics and other things in the past.
There are a ton of articles about how to represent complex relationships in GraphQL, just try searching some and seeing if any design patterns jump out to you.
Michele Korell (Oct 23 2019 at 08:59):
Hello, our way is to pass a single string parameter that reflect the standard FHIR search. Behind the resolver can pass to desired connector, we have two case:
- the first one is that we are fetching data from a remote RESTful FHIR api, so we simple add the search string directly on path
- the second one is that we search data on our internal database and our parser is able to build SQL query that reflect the db structure to complete the resource.
natus (Oct 24 2019 at 19:00):
@Michele Korell could you elaborate on what use case you are solving with those two approaches ?
I also have in mind such syntax (which can be translated into low level database query or other fhir endpoints)
( Condition?coding=xxx&recorded-date=2019 after(patient, recorded-date, date, 20 days) Medication?coding=yyy ) AND Patient?deaceasedBoolean=true&gender=male )
@Robert Winterbottom thanks for the valuable pointers. I definitely have to look how this could be defined within Graphql dialect not to reinvent the wheel. Also I suspect graphQL is not as readible than the above syntax
Michele Korell (Oct 24 2019 at 20:46):
Michele Korell could you elaborate on what use case you are solving with those two approaches ?
@natus :
Actually we developed a standard interface template inTypescript that permits to us to call differents implementations of connector. At front of our microservices we have a GraphQL and REST routes. They call the logic of the microservice that is able using a general query builder to call the standard connector interface. In this way we are able to call databases or others REST/GraphQL APIs. In Switzerland a lot of healthcare software manufacturer still develop proprietary interfaces because they believe that oblige customers keep their solution, our workaround is to build an FHIR based abstraction layer. This layer is able to translate all queries between all employed technologies.
By the way, with our experience we found that GraphQL is very flexible for querying from FrontEnd application to a gateway. But for the communication between microservices we didn't found a good strategy to prevent lost of information if some fields are not in the mutation queries.
Michele Korell (Oct 24 2019 at 22:04):
@Grahame Grieve Actually I'm working on testing with the specification you provided and did you think that it can be useful specify test scenario with Gherkin syntax?
for example we can transform
"description" : "Just a simple test of the basic graphQL engine: a simple query on a known patient (example, from the spec)",
to
"description" : "Given a GraphQL patient endpoint When I call the \"url\" route Then I get the patient \"output\" data",
This is just a fast written example, but on our agility organisation we receive UserStories described in this way. Actually Cucumber is developed for a lot of frameworks (https://cucumber.io/docs/installation/). In our hospital we use SpecFlow to drive Appium test framework and Cypress for e2e web applications tests.
What do you think about that?
natus (Oct 26 2019 at 11:00):
@Michele Korell
By the way, with our experience we found that GraphQL is very flexible for querying from FrontEnd application to a gateway.
Good to know graphQL allows to federate switherland. I would be glad to have a deep look into this. By the way, I am not sure the use case I am looking for is covered by your design: joining resources together with complex criteria (counts, temporal, inner/outer/anti joins)
Michele Korell (Oct 27 2019 at 07:31):
@natus in this case I don't understand well what you want really do. Can you provide an example? Try to build the query on a FHIR REST test server and describe how it has to work on graphql.
Kendall Park (Dec 05 2019 at 20:24):
Do you guys know if it would be feasible to make a GraphQL adapter over a FHIR REST API (without GraphQL support)?
Grahame Grieve (Dec 05 2019 at 20:35):
I believe it's feasible
Kendall Park (Dec 05 2019 at 20:52):
I'm trying to figure out how much work it would be, and whether someone else is already attempting a similar project. There are existing resources for using GraphQL with REST API's (https://github.com/apollographql/apollo-link-rest).
To zoom out a bit, I'm trying to find a more expressive way to query an existing FHIR database. One option is to do a relational DB mirror (eg, fhirbase). Another option is GraphQL. The queries would be used for predictive modeling (training or inference). Like, "give me these specific lab results from Patient X within the last 24 hours."
Grahame Grieve (Dec 05 2019 at 20:54):
a graphQL proxy on a standard rest interface is very smart but has a real performance penalty that a direct DB approach wouldn't have
Josh Mandel (Dec 05 2019 at 20:54):
The requirements for training are substantially different than for inference. For training I'd be thinking more about bulk data extraction. For inference... I think it's important to lay out what your goals are. I sketched out a quick take on how wrapping FHIR REST with Graphql would work back in 2015 and was pretty happy with it functionally -- but this approach will never be faster than REST API access.
Kendall Park (Dec 05 2019 at 21:03):
The performance is going to be worse, but the relational mirror will come with its own headaches (eg, if you want run inference on a particular case on demand). You can use the proxy as a stand-in while you wait for GraphQL support in the original system. This is more about creating a sane and generalizable data science pipeline than it is about maximizing performance.
Kendall Park (Dec 05 2019 at 21:24):
If data scientists work directly with the REST API, they'll be making multiple API calls and sifting through a ton of excess data in their Jupyter notebook (or container the model is deployed in). It's a bit unwieldy.
Grahame Grieve (Dec 05 2019 at 21:44):
yes, data scientists need some ETL running. graphQL is an option. So is sql as discussed om #analytics on FHIR
Grahame Grieve (Dec 05 2019 at 21:45):
though I'm sure a general purpose reusable graphQL proxy would be something that people would like. The HAPI graphQL engine could be used for that - just have to map from the callbacks to the REST API
j k (Jun 04 2020 at 11:30):
Dear GraphQL-FHIR group, I would love to take a look at the graphql fhir schema, however the provided download link "http://build.fhir.org/fhir.graph.schema.zip" 404's.
Is it deprecated or has it just moved?
I hope this is the correct place to ask this question and apologize if it is not!
Jose Costa Teixeira (Jun 04 2020 at 11:32):
http://build.fhir.org/fhir.schema.graphql.zip
Jose Costa Teixeira (Jun 04 2020 at 11:32):
is this it?
j k (Jun 04 2020 at 11:36):
exactly! thanks for the quick response.
Andreea Dorca (Aug 27 2020 at 08:20):
Is there a library or something we could use to directly and easily convert GraphQL responses to FHIR resources? Or how could we do this using the JAVA language?
Lloyd McKenzie (Aug 27 2020 at 14:39):
See duplicate thread https://chat.fhir.org/#narrow/stream/179166-implementers/topic/GraphQL.20to.20FHIR
Last updated: Apr 12 2022 at 19:14 UTC