Write GraphQL queries as objects instead of strings
This is a better implementation of the GraphQL query API via NodeJS, created as a wrapper of Got. It works like a transpiler, with a built in HTTPRequest Client (Got), allowing you to write your GraphQL queries as Javascript Objects instead of strings.
Built because manipulating strings is a real pain.
Table of Contents
Install
$ npm install gotql
Or
$ yarn install gotql
Basic Usage
const gotQl = require('gotql')
const query = {
operation: {
name: 'users',
fields: ['name', 'age', 'id']
}
}
const options = {
headers: {
"Authorization": "Bearer <token>"
},
debug: false,
useHttp2: false
}
gotQL.query('mygraphqlendpoint.com.br/api', query, options)
.then(response => console.log(response.data))
.catch(console.error)
What is it?
GotQL is a better interface for GraphQL queries. It provides a way for developers to run queries using JSON instead of strings. Which is a way more usable data format than the string itself.
See more on: https://hasura.io/blog/fluent-graphql-clients-how-to-write-queries-like-a-boss/
Motivation
Manipulating strings is very smelly, even on dynamically typed languages. So, in order to avoid things such as this:
Which can be translated to something waay more readable in a JSON format like this:
const mutation = {
operation: {
name: 'addLog',
args: {
logType: literal`status_change`, // Enum Value
fromState: variables.fromState,
toState: variables.toState,
idUser: variables.idUser,
idCampaign: variables.idCampaign,
owner: {
ownerType: variables.ownerType,
username: variables.username,
picture: variables.picture,
name: variables.name,
id: variables.id
}
},
fields: [ 'uuid' ]
}
}
This is why GotQL was created.
API
gotQl.query(graphQLEndpoint, query, [options])
- Description: Performs a graphQL query
GraphQLEndpoint
- Type:
string
- Description: The GraphQL endpoint to query on
query
- Type:
object
- Description: The JSON-typed query following the json-query format
options
See option object for more information.
gotQl.mutation(graphQLEndpoint, query, [options])
- Description: Performs a graphQL mutation
GraphQLEndpoint
- Type:
string
- Description: The GraphQL endpoint to query on
query
- Type:
object
- Description: The JSON-typed query following the json-query format
options
See option object for more information.
gotQl.parser(query, type)
- Description: Parses a JSON-Like query and returns the query's string
query
- Type:
object
- Description: The JSON-typed query following the json-query format
type
- Type:
string
- Description: Must be either
'query'
or'mutation'
Option Object
Both gotql.query
and gotql.mutation
accept an optional user option object with the following API:
- Type:
object
- Description: The option object with the following properties.
- errorStatusCode: Default HTTP status code to be returned on error
- Type:
number
- Type:
- headers: Additional headers to be sent
- Type:
object
, in the form of[headerName: string]: headerValue: string
- Type:
- gotInstance: Customized Got instance to be used when calling the endpoint
- Type:
got
. Internally this will be called asgot.post(prependHttp(endPoint), gotPayload)
- Type:
- useHttp2: Boolean defining if the call should be made using HTTP2, defaults to
false
(see release 11 of got)- Type:
boolean
- Type:
- errorStatusCode: Default HTTP status code to be returned on error
Note: GotQL uses
debug
internally as default debugger, so you can set debug levels by setting theDEBUG
environment variable. These are the current levels:
gotql:info
gotql:info:parser
gotql:info:runner
gotql:errors
Returns
All methods return a string
like this:
const response = 'query { test { name args } }'
The JSON query format
The JSON format gotQL uses is a simple and intuitive description based on the anatomy of a GraphQL query blog post.
This is a generic model of a JSONLike query:
const query = {
name?: string,
operation: {
name: string,
alias?: string,
args?: { [argName: string]: any } | {
[argName: string]: {
value: string,
escape: boolean
}
},
fields: (string | {
[fieldName: string]: [{
args?: { [argName: string]: any } | {
[argName: string]: {
value: string,
escape: boolean
}
},
fields?: (string | { [fieldName: string]: [any] })[]
}]
})[]
},
variables?: {
[varName: string]: {
type: string,
value: string
}
}
}
Description
- Query:
- Type:
object
- Description: The full query object
- Properties:
- name: [optional]: Query name
- Type:
string
- Type:
- variables: [optional] Query variable declaration
- Type:
object
with signature like[varName: string]: { type: string, value: string }
- Properties:
- varName: Variable name
- Type:
string
- Type:
- type: Variable type. Can be a GraphQL definition of type (i.e:
string!
)- Type:
string
- Type:
- value: Variable value
- Type:
any
- Type:
- varName: Variable name
- Type:
- operation: The query operation (action that will be executed)
- Type:
object
- Properties:
- name: The operation name
- Type:
string
- Type:
- alias: [optional] An alias to give the operation
- Type:
string
- Type:
- args: [optional] The operation args
- Type:
[argName: string]: any
or a detailed arg object- Simple args: An
object
where the key is the argument name and its value. Accepts variables in the format ofargName: '$value'
- Example:
args { name: 'myName' }
- Example:
- Detailed args: A tagged template. This will give more control over escaping (mostly to use enums). Argument name should be the key
- Type:
tagged template
- Examples:
args: { status: literal`an_enum` }
should outputoperation (status: an_enum)...
- Type:
- Simple args: An
- Type:
- fields: The field list to get back from the operation
- Type: An
array
ofobject
(to use nested fields) orstring
, or both. - Properties (for nested fields):
- Type:
object
where the field name is the key - fields: Recursive definition, accepts another array just like the fields above.
- args: [optional] The field args
- Type:
[argName: string]: any
or a detailed arg object- Simple args: An
object
where the key is the argument name and its value. Accepts variables in the format ofargName: '$value'
- Example:
args { name: 'myName' }
- Example:
- Detailed args: A tagged template. This will give more control over escaping (mostly to use enums). Argument name should be the key
- Type:
tagged template
- Examples:
args: { status: literal`an_enum` }
should outputoperation (status: an_enum)...
- Type:
- Simple args: An
- Type:
- Type:
- Type: An
- name: The operation name
- Type:
- name: [optional]: Query name
- Type:
Examples
Simple query
const query = {
operation: {
name: 'users',
fields: ['name', 'age']
}
}
Outputs:
query { users { name age } }
Named query
const query = {
name: 'myQuery',
operation: {
name: 'users',
fields: ['name', 'age']
}
}
Outputs:
query myQuery { users { name age } }
Query with simple args
const query = {
operation: {
name: 'users',
args: {
name: 'Joe'
},
fields: ['name', 'age']
}
}
Outputs:
query { users(name: "Joe") { name age } }
Query with variables
const query = {
variables: {
name: {
type: 'string!',
value: 'Joe'
}
},
operation: {
name: 'users',
args: {
name: '$name'
},
fields: ['name', 'age']
}
}
Outputs:
query ($name: string!) { users(name: $name) { name age } }
Variables are sent on a separate object to graphQL.
{
"variables": { "name": "Joe" }
}
Nested fields
const query = {
operation: {
name: 'users',
fields: [
'name',
'age',
{
friends: {
fields: ['name', 'age']
}
}
]
}
}
Outputs:
query { users { name age friends { name age } } }
Recursive fields can go forever.
Enum and literal args
Enum or literal values should not be escaped, to do that, GotQL has a helper called literal
which can be used to tell the query that value will not be escaped:
const { literal } = require('gotql')
const query = {
operation: {
name: 'users',
args: {
type: literal`internal`
},
fields: ['name', 'age']
}
}
The code above outputs:
query { users(type: internal) { name age } }
The literal
helper is just a shorthand to the old-style {value: string, escape: boolean}
object like below:
const query = {
operation: {
name: 'users',
args: {
type: {
value: 'internal',
escape: false
}
},
fields: ['name', 'age']
}
}
If literal
is omitted, or if escape
is set to true
, the output would be:
query { users(type: "internal") { name age } }
Note: Variables such as described here will not be recognized. If the arg object is not an
[argName]: value
, variables will not pass through the definition check (GotQL warns if a variable is not declared but used on operation).
Contributing to this project
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
Hey! If you want to contribute, please read the contributing guidelines
Contributors
Code Contributors
This project exists thanks to all the people who contribute. [Contribute].
Financial Contributors
Become a financial contributor and help us sustain our community. [Contribute]
Individuals
Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]