How can I execute an instance query in graphql-fhir? - hl7-fhir

This issue is migrated from a question on our Github account because we want the answer to be available to others. Here is the original question:
Hello,
Following is the InstanceQuery I tried
http://localhost:3000/3_0_1/Questionnaire/jamana/$graphql?query={id}
I am receiving back response as Cannot query field \"id\" on type \"Questionnaire_Query\"
So what is the right format I should try ?
https://build.fhir.org/graphql.html has a sample as http://test.fhir.org/r3/Patient/example/$graphql?query={name{text,given,family}}.Its working in their server. I cannot get the response When I try similarly in our graphql-fhir.

Original answer from Github:
We are using named queries since we are using express-graphql. I do not believe that is valid syntax. Also, the url provided does not seem to work, I just get an OperationOutcome saying the patient does not exist, which is not a valid GraphQL response.
Can you try changing your query from:
http://localhost:3000/3_0_1/Questionnaire/jamana/$graphql?query={id}
to this:
http://localhost:3000/3_0_1/Questionnaire/jamana/$graphql?query={Questionnaire{id}}
When writing the query, you need to provide the return type as part of the instance query. You should get a response that looks like similar to this(if you have implemented your resolver you will have data and not null):
{
"data": {
"Questionnaire": {
"id": null
}
}
}
and from a later comment:
If you are getting null then you are doing it correctly, but you haven't wrote a query or connected it to a data source. You still need to return the questionnaire in the resolver.
Where you are seeing this:
instance: {
name: 'Questionnaire',
path: '/3_0_1/Questionnaire/:id',
query: QuestionnaireInstanceQuery,
},
You are seeing the endpoint being registered with an id parameter, which is different from a GraphQL argument. This is just an express argument. If you navigate to the questionnaire/query.js file, you can see that the QuestionnaireInstanceQuery query has a different resolver than the standard QuestionnaireQuery. So in your questionnaire/resolver.js file, if you want both query and instance query to work, you need to implement both resolvers.
e.g.
// This is for the standard query
module.exports.getQuestionnaire = function getQuestionnaire(
root,
args,
context = {},
info,
) {
let { server, version, req, res } = context;
// Do query and return questionnaire
return {};
};
// This one is for a questionnaire instance
module.exports.getQuestionnaireInstance = function getQuestionnaireInstance(
root,
args,
context = {},
info,
) {
let { server, version, req, res } = context;
// req.params.id is your questionnaire id, use that for your query here
// queryQuestionnaireById does not exist, it is pseudo code
// you need to query your database here with the id
let questionnaire = queryQuestionnaireById(req.params.id);
// return the correct questionnaire here, default returns {},
// which is why you see null, because no data is returned
return questionnaire;
};

Related

How to find path to a field in a graphql query

I am very new to graphql. I have a following graphql query for an example:
query pets {
breed(some arguments)
{
name
items
{
owner(some arguments)
{
items
{
ID
ownerSnumber
country
address
school
nationality
gender
activity
}
}
name
phoneNumber
sin
}
}
}
Is it possible to parse a gql query and get the path of a field in the query?
For example I would like to get the path of 'ID'. For example from the above query, is it possible to get the path where the ID is: owner.items.ID
With https://graphql.org/graphql-js/ it exposes a fourth argument called resolve info. This field contains more information about the field.
Have a look at GraphQLObjectType config parameter type definition:
With a good start from the earlier answer, relying on the ResolveInfo you could do something like a recursive check going from child to parent:
export const getFieldPath = (path: Path): string => {
if (!path.prev) return `${path.key}`
return `${getFieldPath(path.prev)}.${path.key}`
}
And later in your resolver you could use it like:
const myFieldResolver = (parent, args, ctx, info) => {
const pathOfThisResolversField = getFieldPath(info.path)
// use your pathOfThisResolversField
return yourFieldResolvedData
};
Worth noting though, the solution above will include every node all the way to the query root, rather than just the ones you mentioned owner.items.ID

Different query for same __typename data returns undefined on Apollo Graphql from cache

I am fairly new to Apollo and Graphql and I quite don't know what I am doing wrong. I will try to explain my problem with some simplified code but if I am missing some information please let me know and I will update it.
I have an Apollo client instance consuming an external (Directus CMS) graphql API not modifiable by me.
The thing is I am querying a paginated (infinite scroll) of posts with offset and limit variables and the data returned is correct. I am using the following typePolicy in order to merge results arrays in my inMemoryCache. This code is from an example in the Apollo Docs:
posts {
const merged = existing ? existing.slice(0) : [];
const postIdToIndex = Object.create(null);
if (existing) {
existing.forEach((post, index) => {
postIdToIndex[readField("id", post)] = index;
});
}
incoming.forEach((post) => {
const id = readField("id", post);
const index = postIdToIndex[id];
if (typeof index === "number") {
// Merge the new post data with the existing post data.
merged[index] = mergeObjects(merged[index], post);
} else {
// First time we've seen this post in this array.
postIdToIndex[id] = merged.length;
merged.push(post);
}
});
return merged;
}
and this is a simplified version of my query:
query($offset: Int $limit: Int) {
posts(limit: $limit offset: $offset) {
id
name
}
}
With this merge function and query I get my pagination right and everything loads correctly. But when I try to query a single instance of post that queries also additional fields from it with the following query:
query($offset: Int $limit: Int $post_id: Int) {
posts(filter:{id:{_eq: $post_id}}) {
id
name
other_data
}
}
This returns undefined constantly when using useQuery() although i can see that is coming through my merge funtion and merging objects with the mergeObjects() function. If I use a fetchPolicy of no-cache in this query, the data returns correctly so it has something to do with the cache.
I hope someone can lead me in the right direction so I can fix this problem.
Thank you everyone in advance!!

The base64 hash of my node id is not what I expect

I am using the graphql-go library along with graphql-go/relay. I am trying to write some basic tests for my API, and am having some trouble with the base64 encoding mechanism. When I execute a simple query for viewer id, the viewer encoded id is wrong.
I am hardcoding the db call to retrieve the first user with id 1:
func TestGetViewer(t *testing.T) {
// Empty and fill the db for consistency
prepDb()
query := `
query {
viewer {
id
}
}
`
// The schema contains a viewer entry point that returns a userType:
// userType = graphql.NewObject(graphql.ObjectConfig{
// Name: "User",
// Description: "A user",
// Fields: graphql.Fields{
// "id": relay.GlobalIDField("User", nil),
// },
// })
schema := gql.NewSchema(db)
// graphql.Do is called by graphql.Execute. I'm trying to get
// closer to what is actually called in order to debug
result := graphql.Do(graphql.Params{
Schema: schema,
RequestString: query,
})
// The return data from our query
data := result.Data.(map[string]interface{})
// The relay.GlobalIDField in our schema should be calling this method
// under the hood, however, as you'll see it returns something different
id := relay.ToGlobalID("User", "1")
// prints map[viewer:map[id:VXNlcjo= username:janedoe]]
// notice the last character of the id
fmt.Println(data)
// prints VXNlcjox
fmt.Println(id)
The graphql.Do returns something that is really close, but the last character of the encoded id is different from what is returned by relay.ToGlobalID. It instead shows the last character padded with =. And when I try to run relay.FromGlobalID("VXNlcjo="), it is able to figure out that its type is User, but it returns an empty string for ID. Whereas, if I replace the = with x, it returns the correct object.
I'm new to Go, and to these concepts, so any ideas or help would be greatly appreciated!
I'm a big ol' dummy and neglected to write the json field tags when defining my User struct to retrieve data from the db. Single capitalization is okay, but since I capitalize both I and D, it wasn't resolving properly and was passing an empty string for the id. Below is corrected:
type User struct {
ID int `json:"id"`
}
Rookie mistake! But maybe it can be helpful to others.

How to access query path properties in a resolver? GraphQL

I have a database with the following structure.
I'm writing a GraphQL resolver for the bottom-most node (the "rows" node).
As the image shows, each "rows" node corresponds to a specific path. (Company)->(DB)->(Table)->(rows)
A Query would be of the form:
{
Company(name: "Google") {
Database(name: "accounts") {
Table(name: "users") {
rows
}
}
}
}
Question: How can I include/access Company.name, Database.name, Table.name information in the rows resolver so that I can determine which rows node to return?
In other words: I know I can access Table.name using parent.name, but is there a way to get parent.parent.name or parent.parent.parent.name?
If there isn't a way to access ancestor properties, should I use arguments or context to pass these properties manually into the rows resolver?
Note: I can't use the neo4j-graphql-js package.
Note: This is the first simple example I thought of and I understand there are structural problems with organizing data this way, but the question still stands.
You can extract the path from the GraphQLResolveInfo object passed to the resolver:
const { responsePathAsArray } = require('graphql')
function resolver (parent, args, context, info) {
responsePathAsArray(info.path)
}
This returns an array like ['google', 'accounts', 0, 'user']. However, you can also pass arbitrary data from parent resolver to child resolver.
function accountResolver (parent, args, context, info) {
// Assuming we already have some value at parent.account and want to return that
return {
...parent.account,
message: 'It\'s a secret!',
}
}
function userResolver (parent, args, context, info) {
console.log(parent.message) // prints "It's a secret!"
}
Unless message matches some field name, it won't ever actually appear in your response.

How can I do a WpGraphQL query with a where clause?

This works fine
query QryTopics {
topics {
nodes {
name
topicId
count
}
}
}
But I want a filtered result. I'm new to graphql but I see a param on this collection called 'where', after 'first', 'last', 'after' etc... How can I use that? Its type is 'RootTopicsTermArgs' which is likely something autogenerated from my schema. It has fields, one of which is 'childless' of Boolean. What I'm trying to do, is return only topics (a custom taxonomy in Wordpress) which have posts tagged with them. Basically it prevents me from doing this on the client.
data.data.topics.nodes.filter(n => n.count !== null)
Can anyone direct me to a good example of using where args with a collection? I have tried every permutation of syntax I could think of. Inlcuding
topics(where:childless:true)
topics(where: childless: 'true')
topics(where: new RootTopicsTermArgs())
etc...
Obviously those are all wrong.
If a custom taxonomy, such as Topics, is registered to "show_in_graphql" and is part of your Schema you can query using arguments like so:
query Topics {
topics(where: {childless: true}) {
edges {
node {
id
name
}
}
}
}
Additionally, you could use a static query combined with variables, like so:
query Topics($where:RootTopicsTermArgs!) {
topics(where:$where) {
edges {
node {
id
name
}
}
}
}
$variables = {
"where": {
"childless": true
}
};
One thing I would recommend is using a GraphiQL IDE, such as https://github.com/skevy/graphiql-app, which will help with validating your queries by providing hints as you type, and visual indicators of invalid queries.
You can see an example of using arguments to query terms here: https://playground.wpgraphql.com/#/connections-and-arguments

Resources