Browse by type

Lightest GraphQL client with intelligent features.
Originally inspired by Robert Mosolgo's blog post
GraphQL is based on a very simple HTTP transaction, which sends a request to an endpoint
with query and variables.
Many libraries require complex stacks to make that simple request. In any project you don't use React, Relay, you'll need a simpler client which manages your query and makes a simple request.
// Connect...
var graph = graphql("/graphql")
// Prepare...
graph.fragment({
user: `on User {
id,
name
}`
})
const allUsers = graph(`query { allUsers { ...user } }`)
const createUser = graph(`mutation (@autodeclare) {
createUser($firstName, $lastName) { ...user }
}`)
await createUser({
firstName: "John",
lastName: "Doe"
})
const users = await allUsers()
console.log(users)
// {
// "allUsers": [{ "id": 1, "name": "John Doe" }]
// }
You can download graphql.js directly, or you can use Bower or NPM.
<script src="https://github.com/f/graphql.js/raw/v0.6.8/cdn.jsdelivr.net/npm/graphql.js@0.6.6/graphql.min.js"></script>
npm install graphql.js --save
# or
yarn add graphql.js
You can use GraphQL.js with Rails Asset Pipeline using graphqljs-rails.
GraphQL.js is isomorphic. You can use it in both browser and Node.js.
<script src="https://github.com/f/graphql.js/raw/v0.6.8/path/to/graphql.js"></script>
var graphql = require('graphql.js')
Or using import
import graphql from 'graphql.js'
Create a simple connection to your GraphQL endpoint.
var graph = graphql("http://localhost:3000/graphql", {
method: "POST", // POST by default.
headers: {
// headers
"Access-Token": "some-access-token"
// OR "Access-Token": () => "some-access-token"
},
fragments: {
// fragments, you don't need to say `fragment name`.
auth: "on User { token }",
error: "on Error { messages }"
}
})
graph will be a simple function that accepts query and variables as parameters.
graph(`query ($email: String!, $password: String!) {
auth(email: $email, password: $password) {
... auth # if you use any fragment, it will be added to the query.
... error
}
}`, {
email: "john@doe.com",
password: "my-super-password"
}).then(function (response) {
// response is originally response.data of query result
console.log(response)
}).catch(function (error) {
// response is originally response.errors of query result
console.log(error)
})
You can prepare queries for lazy execution. This will allow you to reuse your queries with different variables without any hassle.
var login = graph(`query ($email: String!, $password: String!) {
auth(email: $email, password: $password) {
... on User {
token
}
}
}`)
// Call it later...
login({
email: "john@doe.com",
password: "my-super-password"
})
.run and ES6 Template TagIf your query doesn't need any variables, it will generate a lazy execution query by default. If you want to run your query immediately, you have three following options:
// 1st option. create and run function.
graph(`...`)()
graph.query(`...`)()
graph.mutate(`...`)()
//...
// 2nd option. create and run function with `run` method.
graph.run(`...`)
graph.query.run(`...`)
graph.mutate.run(`...`)
// 3rd option. create and run function with template tag.
graph`...`
graph.query`...`
graph.mutate`...`
I don't recommend using this. Using it too much may break DRY. Use lazy execution as much as possible.
You can prefix your queries by simply calling helper methods: .query, .mutate or .subscribe
var login = graph.query(`($email: String!, $password: String!) {
auth(email: $email, password: $password) {
... on User {
token
}
}
}`)
var increment = graph.mutate`increment { state }`
var onIncrement = graph.subscribe`onIncrement { state }`
@autodeclare or {declare: true}Declaring primitive-typed (String, Int, Float, Boolean) variables in query were a
little bothering to me. That's why I added an @autodeclare keyword or {declare: true} setting to the processor.
It detects types from the variables and declares them in query automatically.
var login = graph.query(`(@autodeclare) {
auth(email: $email, password: $password) {
... on User {
token
}
}
}`)
login({
email: "john@doe.com", // It's String! obviously.
password: "my-super-password" // It is, too.
})
This will create following query:
query ($email: String!, $password: String!) {
auth(email: $email, password: $password) {
... on User {
token
}
}
}
You can also pass {declare: true} option to the .query, .mutate and .subscribe helper:
var login = graph.query(`auth(email: $email, password: $password) {
... on User {
token
}
}`, {declare: true})
This will also create the same query above.
Variable names with matching /_id/i pattern will be declared as ID type. Following examples will be declared as IDs:
id: 1 will be declared as $id: ID!post_id: "123af" will be declared as $post_id: ID!postID: 3 will be declared as $postID: ID!postId: 4 will be declared as $postId: ID!You can disable auto ID declaration by adding an ! to the end of the variable name:
id!: 1 will be declared as $id: Int!post_id!: "123af" will be declared as $post_id: String!And, explicitly given types are prioritized.
postID!CustomId: 3 will be declared as $postID: CustomId!postId!UUID: 4 will be declared as $postId: UUID!var userById = graph.query(`(@autodeclare) {
user(id: $id) {
email
}
}`)
userById({
id: 15
})
The example above will generate following query:
query ($id: ID!) {
user(id: $id) {
email
}
}
Integer and Float ProblemLet's say you have a rating query that accepts an argument with a Float argument named rating.
GraphQL.js will declare 10 value as Integer since it casts using value % 1 === 0 ? 'Int' : 'Float' check.
var rate = graph.query(`(@autodeclare) {
rating(rating: $rating) {
rating
}
}`)
rate({
rating: 10
})
In this case, you must use ! mark to force your type to be Float as below:
rate({
"rating!Float": 10
})
This will bypass the casting and declare rating as Float.
Beside you can pass {declare: true} to helpers:
graph.query("auth(email: $email, password: $password) { token }", {declare: true})
Also you can enable auto declaration to run by default using alwaysAutodeclare setting.
var graph = graphql("http://localhost:3000/graphql", {
alwaysAutodeclare: true
})
After you enable alwaysAutodeclare option, your methods will try to detect types of variables and declare them.
// When alwaysAutodeclare is true, you don't have to pass {declare: true} option.
graph.query("auth(email: $email, password: $password) { token }")
You can define custom types when defining variables by using a simple "variable!Type" notation.
It will help you to make more complex variables:
var register = graph.mutate(`(@autodeclare) {
userRegister(input: $input) { ... }
}`)
register({
// variable name and type.
"input!UserRegisterInput": { ... }
})
This will generate following query:
mutation ($input: UserRegisterInput!) {
userRegister(input: $input) { ... }
}
Fragments make your GraphQL more DRY and improves reusability. With .fragment method, you'll
manage your fragments easily.
While constructing your endpoint, you can predefine all of your fragments.
var graph = graphql("/graphql", {
fragments: {
userInfo: `on User { id, name, surname, avatar }`
}
})
And you can use your fragments in your queries. The query will pick your fragments and will add them to the bottom of your query.
graph.query(`{ allUsers { ...userInfo } }`)
You can nest your fragments to keep them organized/namespaced.
var graph = graphql("/graphql", {
fragments: {
user: {
info: `on User { id, name, surname, avatar }`
}
}
})
Accessing them is also intuitive:
graph.query(`{ allUsers { ...user.info } }`)
You can reuse fragments in your fragments.
graph.fragment({
user: "on User {name, surname}",
login: {
auth: "on User {token, ...user}"
}
})
You can also add fragments lazily. So you can use your fragments more modular.
// Adds a profile fragment
graph.fragment({
profile: `on User {
id
name(full: true)
avatar
}`
})
var allUsers = graph.query(`{
allUsers {
... profile
}
}`)
allUsers().then(...)
Also you can add nested fragments lazily, too:
graph.fragment({
login: {
error: `on LoginError {
reason
}`
}
})
graph.fragment({
something: {
error: `on SomeError {
messages
}`
}
})
graph.query(`{ login {... login.error } }`)
graph.query(`{ something {... something.error } }`)
You can call fragment string by using .fragment method. You have to pass path string to get the fragment.
graph.fragment('login.error')
This will give you the matching fragment code:
fragment login_error on LoginError {
reason
}
You can use fragments lazily using ES6 template tag queries.
var userProfileToShow = graph.fragment('user.profile')
graph`query { ... ${userProfileToShow} }`
You can create queries using .ql ES6 template tag.
// Add some fragments...
graph.fragment({
username: {
user: `on User {
username
}`,
admin: `on AdminUser {
username,
administrationLevel
}`
}
})
// Get any fragment with its path...
var admin = graph.fragment('username.admin')
// Build your query with using fragment paths or dynamic template variables.
var query = graph.ql`query {
...username.user
...${admin}
}`
// Use query anywhere...
$.post("/graphql", {query: query}, function (response) { ... })
graph.ql will generate this query string:
query {
... username_user
... username_admin
}
fragment username_user on User {
username
}
fragment username_admin on AdminUser {
username,
administrationLevel
}

This GIF shows a before/after case to make an example how query merging changes the performance.
graphql.js supports query merging that allows you to collect all the requests into one request.
Assume we've these queries on server, define them just like before we do:
var fetchPost = graph.query(`{
post(id: $id) {
id
title
text
}
}`)
var fetchComments = graph.query(`{
commentsOfPost: comments(postId: $postId) {
comment
owner {
name
}
}
}`)
Normally, we make requests as following:
var postId = 123
// This will send a request.
fetchPost({ id: postId }).then(function (response) {
console.log(response.post)
})
// This also will send a request.
fetchComments({ postId: postId }).then(function (response) {
console.log(response.commentsOfPost)
})
This will make two requests:

Use .merge(mergeName, variables) command to put them into a merge buffer:
var postId = 123
// This won't send a request.
fetchPost.merge('buildPage', { id: postId }).then(function (response) {
console.log(response.post)
})
// This also won't send a request.
fetchComments.merge('buildPage', { postId: postId }).then(function (response) {
console.log(response.commentsOfPost)
})
These will create a buffer with buildPage name, and append the queries to that buffer. You need to use commit(mergeName) to merge the buffer and send to the server, the response will be consolidated:
// This will send a merged request:
graph.commit('buildPage').then(function (response) {
// All base fields will be in response return.
console.log(response.post)
console.log(response.commentsOfPost)
})
And this will create only one request:

This will create the following merged query generated by graphql.js:
```graphql query ($merge024533__id: ID!, $merge141499__postId: ID!) { merge024533_post: { post(id: $merge024533__id) {
$ claude mcp add graphql.js \
-- python -m otcore.mcp_server <graph>