GraphQL fragment JSON format - graphql

I'm attempting to read some data out of GitHub with their v4 (GraphQL) API. I've written a Java client that is working fine up until I start replacing some of the query with GraphQL fragments.
I was using GraphiQL to initially test my queries, and adding fragments was pretty simple in there. However, when translating to JSON, I haven't figured out the correct format. I've tried:
{ "query": "{ ... body_of_query ... } fragment fragname on Blob { byteSize text }" }
{ "query": "{ ... body_of_query ... }, fragment fragname on Blob { byteSize text }" }
{ "query": "{ ... body_of_query ... }", "fragment": "{fragname on Blob { byteSize text } }" }
EDIT: Adding for #Scriptonomy:
{
query {
search(first:3, type: REPOSITORY, query: \"language:HCL\") {
edges {
node {
... on Repository {
name
descriptionHTML
object(expression: \"master:\") {
... on Tree {
...recurseTree
}
}
}
}
cursor
}
pageInfo {
endCursor
hasNextPage
}
}
}
fragment recurseTree on Tree {
entries {
name
type
}
}
I'm sure it would be fun and all to keep throwing random variations on this, and my morning has been huge fun searching various GraphQL docs and blogs on fragments, and I may have even actually guessed the correct answer but had mismatched parens (I'm just using hardcoded JSON until I know the format -- perhaps not the wisest choice looking back on it).
I'm hoping that someone may know the correct format and set me on the correct course before I keel over from GraphQL-doc over-exposure.

Fragments are sent in the same property of the JSON body as the query itself. You can see an example for using fragments here.
A valid GraphQL request is usually either a GET request that encodes the query as URL query parameter, or a POST request with a JSON body. The JSON body has one required key, query and one optional field, variables. In your case, the JSON needs to look like this:
{
"query": "{\n query {\n search(first:3, type: REPOSITORY, query: \"language:HCL\") {\n edges {\n node {\n ... on Repository {\n name\n descriptionHTML\n object(expression: \"master:\") {\n ... on Tree {\n ...recurseTree\n }\n }\n }\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment recurseTree on Tree {\n entries {\n name\n type\n }\n}"
}
That is the JSON.stringify version of the verbatim query string in your question.
I recommend you to run queries from a GraphiQL instance connected to your GitHub GraphQL API and look into the network request. You can copy the GraphQL request as cuRL to see how the JSON body needs to look like.
If you still obtain a 400, please share some code, because that means your request was malformed, so it probably never hit the GraphQL parser in the first place.

There is no need to translate GraphQL Query to JSON. This would be your query:
"{ query { ... body_of_query ... } fragment fragname on Blob { byteSize text } }"

For future users, and people like me who stumbled upon this hurdle.
Query needs to be sent in the given order;
{ "query": "fragment fragname on Blob { byteSize text } methodName(ifMethodParam: paramVal){...fragname }" }
Hope this will help others.

Related

How to handle where clause in GraphQL Schema

I am new to GraphQL and creating a API Server using Flask and GraphQL,
Facing some issues while handling the "where" clause in GraphQL Request.
The basic Request and Response is working fine . please find a short snippet of the Schema I have designed
type data {
edges:[data_edges]
}
type QueryCustom {
data: data
}
type Query {
query: QueryCustom
}
Below mentioned basic request (Without the where clause) is working fine with this schema
query {
query {
data {
edges { .... }
But Getting an error when I am executing the Request with the where clause
query dataClosingSoon($month: Long) {
query{
data(where: { LastModifiedDate: { CALENDAR_MONTH: { value: { eq: $month } } } } ) {
edges { ....... }
Following is the response I get:
{
"errors": [
{
"locations": [
{
"column": 40,
"line": 1
}
],
"message": "Unknown type 'Long'."
},
{
"locations": [
{
"column": 9,
"line": 5
}
],
"message": "Unknown argument 'where' on field 'QueryCustom.data'."
}
]
}
I need to understand how to handle the where condition.
GraphQL is not SQL. You cannot use SQL clauses such as WHERE, LIKE, etc. in a GraphQL query.
You need to look at the schema to check how can you filter your query. These filters are pre-defined in the schema. You cannot create custom filters (at least in a basic sense) for a GraphQL query.
Edit:
If you want to use the query you are trying to send, your schema should look like something this:
type data {
edges:[data_edges]
}
type Query {
data(where: Filter!): data
}
input type Filter {
lastModifiedDate: // the type of this field
// Rest of the input fields
}
Note that your first query and the second query are totally different. Your second query is clearly wrong due to two reasons:
The Query type does not have a field called data. It only has one field called query. (I wouldn't add a field named query under the Query type though).
Your data field does not have any inputs. But your document (the GraphQL request) clearly does.

How to format NewRelic NerdGraph API calls from java/groovy client?

I'm trying to extract some metric data from NewRelic using NerdGraph API. It works perfectly while using curl, but I'm having problems with calling it from groovy/java client.
NerdGraph API request is as follows:
{
actor {
entitySearch(query: "name like 'my-service-name'") {
results {
entities {
tags {
key
values
}
guid
}
}
}
}
}
The following curl call works fine:
curl --location --request POST 'https://api.newrelic.com/graphql' --header 'API-Key: MY-API-KEY' --header 'Content-Type: application/json' --data-raw '{"query":"{\n actor {\n entitySearch(query: \"name like '\''my-service-name'\''\") {\n results {\n entities {\n tags {\n key\n values\n }\n guid\n }\n }\n }\n }\n}"}'
In my groovy code I'm trying to instantiate request like this:
String request = '''
{ "query": "{
actor {
entitySearch(query: "name like 'my-service-name'") {
results {
entities {
tags {
key
values
}
guid
}
}
}
}
}"
}
'''
..or this:
String request = '{"query":"{\n actor {\n entitySearch(query: \"name like \'my-service-name\'\") {\n results {\n entities {\n tags {\n key\n values\n }\n guid\n }\n }\n }\n }\n}"}'
Neither works. I'm getting https://api.newrelic.com/graphql -> 400 : Bad Request
How should I escape special characters (quote and double quote) to make it work?
I had a similar problem in C# and came to this question looking for answers. Hopefully you've found a solution, but for me the key was sending the data as a byte[] as opposed to a string...
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api.newrelic.com/graphql"))
{
string payload = #"{actor {account(id: NEWRELICACCOUNTID) {nrql(query: ""SELECT rate(count(*), 1 hour) AS 'RequestsPerHour' FROM Transaction TIMESERIES 1 hour FACET `Channel` EXTRAPOLATE SINCE 1 weeks ago"") {results}}}}";
request.Headers.TryAddWithoutValidation("API-Key", "MYAPIKEY");
request.Content = new ByteArrayContent(encoding.GetBytes(payload));
var response = await httpClient.SendAsync(request);
}
}
Hope this helps you or someone else!

How can I define type in gql query in Apollo Client?

My Apollo Server have following definition.
input MinMax{
min:Float
max:Float
}
input ScreenerInput{
fy:Int!
quarter:Int!
ltp:MinMax
eps:MinMax
pe:MinMax
netWorth:MinMax
paidUp:MinMax
reserve:MinMax
netProfit:MinMax
}
How can I define MinMax type in Apollo client to send variables for the MinMax type. Till now I was doing scalar types only so my query were simple.
My query type is screeenedCompanies(criteria:ScreenerInput!):[ScreenedCompanies]
if I query directly like below it works.
{
screeenedCompanies(criteria:{
fy:2075
quarter:2
eps:{
min:30
max:40
}
}){
sector
symbol
}
}
What I want is to query like this so that variables can be changed
query getScreenedCompanies($criteria:<What type should be here ?>){
{
screeenedCompanies(criteria:$criteria){
sector
symbol
}
}
}
After giving ScreenerInput as type my query looks like below
query getScreenedCompanies($criteria:ScreenerInput!){
screeenedCompanies(criteria:$criteria){
sector
symbol
}
}
my variables in apolloplayground look like below
{
"criteria": {
"fy": 2075
"quarter": 4
"ltp": {
"min": 345
"max": 400
}
}
}
I am receiving the following error
"error": {
"errors": [
{
"message": "Variable \"$criteria\" of required type \"ScreenerInput!\" was not provided."
It works the same way, as any scalar type in GQL. Just define them with the same input name as on the server(like MinMax or ScreenerInput in your case). You don't need to describe its shape on the client, server will validate it for you :)
And don't forget to add exclamation mark !, if parameter is required.

Is GitHub API returning an invalid result for the schema query?

https://facebook.github.io/graphql/draft/#sec-Schema-Introspection
type __Schema {
types: [__Type!]!
queryType: __Type!
mutationType: __Type
subscriptionType: __Type
directives: [__Directive!]!
}
type __Type {
kind: __TypeKind!
name: String
description: String
...
Information downloaded from https://developer.github.com/v4/guides/intro-to-graphql/#discovering-the-graphql-api (curl -H "Authorization: bearer token" https://api.github.com/graphql)
(beginning of the file
{
"data": {
"__schema": {
"queryType": {
"name": "Query"
},
"mutationType": {
"name": "Mutation"
},
"subscriptionType": null,
"types": [
{
"kind": "SCALAR",
"name": "Boolean",
...
Question:
I interpreted this so this GitHub schema result is invalid because queryType doesn't specify a kind which is nonNullable (kind: __TypeKind!)
Is this result violating the schema rules or am I missing something?
This response passes validation because a missing field is not the same thing as a field that returns null. A field will be missing from the response only if it wasn't requested in the first place.
If you go to GitHub's GraphQL Explorer, you can generate an introspection query yourself, request the kind field as part of the selection set of the queryType field and it will return the field with a non-null value.
{
__schema {
queryType {
kind
}
}
}
Response:
{
"data": {
"__schema": {
"queryType": {
"kind": "OBJECT"
}
}
}
}
Fetching the schema by making a GET request to some endpoint is convenient, but it's not the standard way to introspect the schema. Instead, you should make the request using whatever selection set is needed against the endpoint itself. The drawback of doing it this less conventional way is made apparent by this question. In this case, whatever introspection query GitHub is making for you under the hood is missing one or more fields that could otherwise be requested. Because you're not the one making the introspection query, you don't know what to expect in terms of the shape of the response.

Apollo Client Query Deduplication on Cached Object

I recently read an article about Apollo Client Caching on the official blog, with a screenshot
here.
According to the article, if the current query contains a cached object, along with other objects, the query will be deduplicated to only query the rest of the objects.
However, I did some testing by logging out queries on the server, which suggested that the query had not been partially deduplicated. Instead, the entire query got sent to the server.
Can anyone provide any insight on this. Thanks very much.
Test:
First query:
{
post(_id: 1) {
_id
title
}
}
Second query:
{
post(_id: 1) {
_id
title
}
author(_id: 1) {
_id
firstName
}
}
Intended outcome:
The secomd query received by the server only contains
author(_id: 1) {
_id
firstName
}
since post(_id: 1) has been cached after the first query is sent, according to the blog.
Actual outcome:
Server log: (the second query has NOT been deduplicated)
{
"operationName": null,
"variables": {},
"query": "{\n post(_id: 1) {\n _id\n title\n __typename\n
}\n}\n"
} /graphql 200 81 - 0.520 ms
{
"operationName": null,
"variables": {},
"query": "{\n post(_id: 1) {\n _id\n title\n __typename\n
}\n author(_id: 1) {\n _id\n firstName\n __typename\n }\n}\n"
} /graphql 200 140 - 0.726 ms
There is a subject called Query deduplication in Apollo-Client
that comes from Apollo-Link (the transport layer of Apollo-Client)
but what it does is deduplicate existing queries that are currently being fetched
Query deduplication can be useful if many components display the same data, but you don’t want to fetch that data from the server many times. It works by comparing a query to all queries currently in flight
you can read more about it here and here
But it doesn't relate so much to the cache.. I think what you're looking for is a better understanding of how cache is managed in Apollo-Client
So how is caching handled in Apollo-Client? you can find a more through article about it here from their official docs: apollo-client-caching
more specifically to your case i believe that if you would use watchQuery / query and make sure the fetchPolicy is cache-first then it might not resend the query
I hope this gives you better insight on caching in Apollo-Client

Resources