Awesome
<h1 align="center"> <br> <img width="360" height="" src="https://cdn.rawgit.com/khaosdoctor/gotql/main/media/gotql.svg" alt="GotQL"> <br> <br> <br> </h1><h1 align="center"> <a href="https://opencollective.com/gotql" alt="Financial Contributors on Open Collective"> <img src="https://opencollective.com/gotql/all/badge.svg?label=financial+contributors" /> </a> <a href="https://github.com/khaosdoctor/gotql/actions?query=workflow%3A%22Build+and+Publish%22"> <img src="https://github.com/khaosdoctor/gotql/workflows/Build%20and%20Publish/badge.svg" /> </a> <a href="https://standardjs.com"> <img src= "https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="JavaScript Style Guide"> </a> </h1>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
<!-- TOC --> <!-- /TOC -->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 :smile:
Contributors
Code Contributors
This project exists thanks to all the people who contribute. [Contribute]. <a href="https://github.com/khaosdoctor/gotql/graphs/contributors"><img src="https://opencollective.com/gotql/contributors.svg?width=890&button=false" /></a>
Financial Contributors
Become a financial contributor and help us sustain our community. [Contribute]
Individuals
<a href="https://opencollective.com/gotql"><img src="https://opencollective.com/gotql/individuals.svg?width=890"></a>
Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]
<a href="https://opencollective.com/gotql/organization/0/website"><img src="https://opencollective.com/gotql/organization/0/avatar.svg"></a> <a href="https://opencollective.com/gotql/organization/1/website"><img src="https://opencollective.com/gotql/organization/1/avatar.svg"></a> <a href="https://opencollective.com/gotql/organization/2/website"><img src="https://opencollective.com/gotql/organization/2/avatar.svg"></a> <a href="https://opencollective.com/gotql/organization/3/website"><img src="https://opencollective.com/gotql/organization/3/avatar.svg"></a> <a href="https://opencollective.com/gotql/organization/4/website"><img src="https://opencollective.com/gotql/organization/4/avatar.svg"></a> <a href="https://opencollective.com/gotql/organization/5/website"><img src="https://opencollective.com/gotql/organization/5/avatar.svg"></a> <a href="https://opencollective.com/gotql/organization/6/website"><img src="https://opencollective.com/gotql/organization/6/avatar.svg"></a> <a href="https://opencollective.com/gotql/organization/7/website"><img src="https://opencollective.com/gotql/organization/7/avatar.svg"></a> <a href="https://opencollective.com/gotql/organization/8/website"><img src="https://opencollective.com/gotql/organization/8/avatar.svg"></a> <a href="https://opencollective.com/gotql/organization/9/website"><img src="https://opencollective.com/gotql/organization/9/avatar.svg"></a>