Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

A Simple and Isomorphic GraphQL Client for JavaScript

License

NotificationsYou must be signed in to change notification settings

f/graphql.js

Repository files navigation

graphql.js: lightweight graphql client

Lightest GraphQL client with intelligent features.


Bower versionNPM versionBuild Status

Originally inspired byRobert Mosolgo's blog post

Features

  • Too small, 4k gzipped.
  • No dependencies, plain vanilla JavaScript.
  • Plug & Play.
  • Isomorphic.
  • Runs on most browsers.
  • You don't need to install Node.js ecosystem on your computer.
  • Query merging to reduce request number.

Overview

GraphQL is based on a very simple HTTP transaction, which sends a request to an endpointwithquery andvariables.

Many libraries requirecomplex stacks to make that simple request.In any project you don't useReact,Relay, you'll need a simplerclient which manages your query and makes a simple request.

// Connect...vargraph=graphql("/graphql")// Prepare...graph.fragment({user:`on User {    id,    name  }`})constallUsers=graph(`query { allUsers { ...user } }`)constcreateUser=graph(`mutation (@autodeclare) {  createUser($firstName, $lastName) { ...user }}`)awaitcreateUser({firstName:"John",lastName:"Doe"})constusers=awaitallUsers()console.log(users)// {//   "allUsers": [{ "id": 1, "name": "John Doe" }]// }

Installation

You can downloadgraphql.js directly, or you can useBower orNPM.

CDN

<scriptsrc="//cdn.jsdelivr.net/npm/graphql.js@0.6.6/graphql.min.js"></script>

Download for Browser

Using NPM

npm install graphql.js --save# oryarn add graphql.js

Using with Rails Asset Pipeline

You can use GraphQL.js with Rails Asset Pipeline usinggraphqljs-rails.

Using

GraphQL.js isisomorphic. You can use it in bothbrowser and Node.js.

Use in Browser

<scriptsrc="/path/to/graphql.js"></script>

Use in Node.js

vargraphql=require('graphql.js')

Or usingimport

importgraphqlfrom'graphql.js'

Connection

Create a simple connection to your GraphQL endpoint.

vargraph=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 }"}})

Executing Queries and Mutations

graph will be a simple function that acceptsquery andvariables 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 resultconsole.log(response)}).catch(function(error){// response is originally response.errors of query resultconsole.log(error)})

Prepare Query for Lazy Execution

You can prepare queries for lazy execution. This will allow you to reuse your queries withdifferent variables without any hassle.

varlogin=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"})

Direct Execution with.run and ES6 Template Tag

If 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.

Prefix Helpers

You can prefix your queries by simply calling helper methods:.query,.mutate or.subscribe

varlogin=graph.query(`($email: String!, $password: String!) {  auth(email: $email, password: $password) {    ... on User {      token    }  }}`)varincrement=graph.mutate`increment { state }`varonIncrement=graph.subscribe`onIncrement { state }`

Automatic Declaring with@autodeclare or{declare: true}

Declaring primitive-typed (String,Int,Float,Boolean) variables in query were alittle 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.

varlogin=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) {...onUser {token    }  }}

You can also pass{declare: true} option to the.query,.mutate and.subscribe helper:

varlogin=graph.query(`auth(email: $email, password: $password) {  ... on User {    token  }}`,{declare:true})

This will also create the same query above.

Detecting IDs

Variable names with matching/_id/i pattern will be declared asID 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!
varuserById=graph.query(`(@autodeclare) {  user(id: $id) {    email  }}`)userById({id:15})

The example above will generate following query:

query ($id:ID!) {user(id:$id) {email  }}

SolvingInteger andFloat Problem

Let's say you have arating query that accepts an argument with aFloat argument namedrating.GraphQL.js will declare10 value asInteger since it casts usingvalue % 1 === 0 ? 'Int' : 'Float' check.

varrate=graph.query(`(@autodeclare) {  rating(rating: $rating) {    rating  }}`)rate({rating:10})

In this case, you must use! mark to force your type to beFloat as below:

rate({"rating!Float":10})

This will bypass the casting and declarerating asFloat.

Advanced Auto Declaring

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 usingalwaysAutodeclare setting.

vargraph=graphql("http://localhost:3000/graphql",{alwaysAutodeclare:true})

After you enablealwaysAutodeclare 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 }")

Auto Declaring Custom Types

You can define custom types when defining variables by using a simple"variable!Type" notation.It will help you to make more complex variables:

varregister=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

Fragments make your GraphQL more DRY and improves reusability. With.fragment method, you'llmanage your fragments easily.

Simple Fragments

While constructing your endpoint, you can predefine all of your fragments.

vargraph=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 andwill add them to the bottom of your query.

graph.query(`{ allUsers { ...userInfo } }`)

Nested Fragments

You can nest your fragments to keep them organized/namespaced.

vargraph=graphql("/graphql",{fragments:{user:{info:`on User { id, name, surname, avatar }`}}})

Accessing them is also intuitive:

graph.query(`{ allUsers { ...user.info } }`)

Using Fragments in Fragments

You can reuse fragments in your fragments.

graph.fragment({user:"on User {name, surname}",login:{auth:"on User {token, ...user}"}})

Lazy Fragments

You can also add fragments lazily. So you can use your fragments more modular.

// Adds a profile fragmentgraph.fragment({profile:`on User {    id    name(full: true)    avatar  }`})varallUsers=graph.query(`{  allUsers {    ... profile  }}`)allUsers().then(...)

Also you can addnested 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 } }`)

Getting Fragments by Path

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:

fragmentlogin_erroronLoginError {reason}

Using Fragments in Tag Query

You can use fragments lazily using ES6 template tag queries.

varuserProfileToShow=graph.fragment('user.profile')graph`query { ...${userProfileToShow} }`

Query Building

You can create queries using.qlES6 template tag.

// Add some fragments...graph.fragment({username:{user:`on User {      username    }`,admin:`on AdminUser {      username,      administrationLevel    }`}})// Get any fragment with its path...varadmin=graph.fragment('username.admin')// Build your query with using fragment paths or dynamic template variables.varquery=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}fragmentusername_useronUser {username}fragmentusername_adminonAdminUser {username,administrationLevel}

Query Merging: Merge Multiple Queries into One Request

merge

This GIF shows abefore/after case to make an example how query merging changes the performance.

graphql.js supportsquery 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:

varfetchPost=graph.query(`{  post(id: $id) {    id    title    text  }}`)varfetchComments=graph.query(`{  commentsOfPost: comments(postId: $postId) {    comment    owner {      name    }  }}`)

Normally, we make requests as following:

varpostId=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:

ss1

Use.merge(mergeName, variables) command to put them into a merge buffer:

varpostId=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 withbuildPage name, and append the queries to that buffer. You need to usecommit(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:

ss2

This will create the following merged query generated bygraphql.js:

query ($merge024533__id:ID!,$merge141499__postId:ID!) {merge024533_post: {post(id:$merge024533__id) {idtitletext    }  }merge141499_commentsOfPost: {comments(postId:$merge141499__postId) {commentowner {name      }    }  }}

And variables will be generated, too:

{"merge024533__id":123,"merge141499__postId":123}

Themerge{number} aliases won't be passed into your responses, since they will be used for initial seperation.

⚠️Important Restriction: You cannot use multiple root fields using query merging.⚠️Important Restriction: Autodeclaration is on by default, do not usealwaysAutodeclare: true.

Debugging

You can passdebug: true to options parameter to get a console output looks like following:

[graphql]: POST http://localhost:3000/graphql  QUERY: query ($email: String!, $password: String!) {    auth(email: $email, password: $password) {      .. login_auth    }  }  fragment info on User { hasPin }  fragment login_auth on User { token, ...info }  VARIABLES: {    "email": "john@doe.com",    "password": "123123"  }  sending as form url-data

Advanced

Using with Vue.js

Create aGraphQLProvider.js.

importgraphqlfrom'graphql.js';/* eslint-disable no-underscore-dangle */exportdefault{install(Vue,url,options){Vue.mixin({created(){this._graph=graphql(url,options);},});Object.defineProperty(Vue.prototype,'$graph',{get(){returnthis._graph;},});},};

And then you can use this with your Vue app:

importVuefrom'vue';importGraphQLProviderfrom'./GraphQLProvider';Vue.use(GraphQLProvider,'http://localhost:3000/graphql',{headers:{// headers...},});// ... in your Vue VMdata(){return{hello:'',};},methods:{makeSomeQuery(){this.$graph.query(`{hello}`).then(response=>{this.hello=response.hello;});},}

Change POST Method

As default, GraphQL.js makes a POST request. But you can change the behavior by settingasJSON.

vargraph=graphql("http://localhost:3000/graphql",{asJSON:true});

Using withgraphql-tag

graphql-tag converts GraphQL query strings to AST. You can usegraphql-tag with GraphQL.js

graph.query(gql`query { name }`)

Usinggraphql-tag will not allow you to useauto declaration andnested fragments syntaxes since these are not valid query syntax for GraphQL but only for this library.

Change Url Anywhere

You can change url anywhere withsetUrl method.

vargraph=graphql("http://localhost:3000/graphql",{asJSON:true});// Change urlgraph.setUrl('http://www.example.com')// Run querygraph.query(`{ name }`)

Todo App Example

A CRUD ToDo app example code to show how to use GraphQL.js. An implementation can be found atf/graphql.js-demo

vargraph=graphql("/graphql",{alwaysAutodeclare:true,fragments:{todo:`on Todo {      id      text      isCompleted    }`}})functiongetTodos(){returngraph.query.run(`allTodos {    ...todo  }`)}functionaddTodo(text){returngraph.mutate(`todoAdd(text: $text) {    ...todo  }`,{text:text})}functionsetTodo(id,isCompleted){returngraph.mutate(`todoComplete(    id: $id,    status: $isCompleted  ) {    ...todo  }`,{id:id,isCompleted:isCompleted})}functionremoveTodo(id){returngraph.mutate(`todoRemove(    id: $id  ) {    ...todo  }`,{id:id})}

License

MIT License

Copyright (c) 2018 Fatih Kadir Akın

Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THESOFTWARE.


[8]ページ先頭

©2009-2025 Movatter.jp