2022/02/11
GraphQLを触ってみました〜REST APIとGraphQLの決定的な違い
GraphQLとは
GraphQL は、アプリケーション・プログラミング・インタフェース (API) 向けのクエリ言語とサーバーサイドランタイムの両方を指します。クライアントがリクエストしたデータだけを提供することを優先します。
GraphQL は、API の速度、柔軟性、開発者にとっての使いやすさを向上させるために設計されました。GraphiQL と呼ばれる統合開発環境 (IDE) にデプロイすることもできます。GraphQL は REST の代わりに、データを複数のデータソースから取得するリクエストを 1 つの API 呼び出しで構成できます。
REST APIとは
REST APIとは、Webシステムを外部から利用するためのプログラムの呼び出し規約(API)の種類の一つで、「REST」(レスト)と呼ばれる設計原則に従って策定されたもの。RESTそのものは適用範囲の広い抽象的なモデルだが、一般的にはRESTの考え方をWeb APIに適用したものをRESTful APIと呼んでいる。
REST APIの例
一般公開されているThe Star Wars APIを(SWAPI)使って説明します。
Luke Skywalkerの情報を取得する場合、URI(エンドポイント)は以下になります。
https://swapi.dev/api/people/1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | { "name": "Luke Skywalker", "height": "172", "mass": "77", "hair_color": "blond", "skin_color": "fair", "eye_color": "blue", "birth_year": "19BBY", "gender": "male", "homeworld": "https://swapi.dev/api/planets/1/", "films": [ "https://swapi.dev/api/films/1/", "https://swapi.dev/api/films/2/", "https://swapi.dev/api/films/3/", "https://swapi.dev/api/films/6/" ], "species": [], "vehicles": [ "https://swapi.dev/api/vehicles/14/", "https://swapi.dev/api/vehicles/30/" ], "starships": [ "https://swapi.dev/api/starships/12/", "https://swapi.dev/api/starships/22/" ], "created": "2014-12-09T13:50:51.644000Z", "edited": "2014-12-20T21:17:56.891000Z", "url": "https://swapi.dev/api/people/1/" } |
C-3POの情報を取得する場合、URI(エンドポイント)は以下になります。
https://swapi.dev/api/people/2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | { "name": "C-3PO", "height": "167", "mass": "75", "hair_color": "n/a", "skin_color": "gold", "eye_color": "yellow", "birth_year": "112BBY", "gender": "n/a", "homeworld": "https://swapi.dev/api/planets/1/", "films": [ "https://swapi.dev/api/films/1/", "https://swapi.dev/api/films/2/", "https://swapi.dev/api/films/3/", "https://swapi.dev/api/films/4/", "https://swapi.dev/api/films/5/", "https://swapi.dev/api/films/6/" ], "species": [ "https://swapi.dev/api/species/2/" ], "vehicles": [], "starships": [], "created": "2014-12-10T15:10:51.357000Z", "edited": "2014-12-20T21:17:50.309000Z", "url": "https://swapi.dev/api/people/2/" } |
REST APIのデメリット
多くの情報が返ってきますが、仮にアプリケーションで必要となるデータが名前(name)のみだった場合、それ以外のデータは不要なデータとなります。こういったデータはメモリに積まれるため、APIの使い方次第ではメモリリークにも繋がります。つまり、本当に必要なデータのみだけでなく不要なデータもレスポンスとして返されることがあります。
GraphQLをNode.jsとexpressでためしてみる
server/app.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | const express = require('express'); const {graphqlHTTP} = require('express-graphql'); const schema = require('./schema/schema'); const app = express(); // bind express with graphql app.use('/graphql', graphqlHTTP({ schema, graphiql:true })); app.listen(4000, () => { console.log('now listening for requests on port 4000'); }); |
server/schema/schema.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | //const { resolveObjMapThunk } = require("graphql"); const graphql = require ('graphql'); const _ = require('lodash'); const{ GraphQLObjectType, GraphQLString, GraphQLSchema, GraphQLID, GraphQLInt, GraphQLList } = graphql; //dummy data var books = [ { name: 'Name of the Wind', genre: 'Fantasy', id: '1', authorId: '1' }, { name: 'The Maze Runner', genre: 'Sci-Fi', id: '2', authorId: '2' }, { name: 'The Long Earth', genre: 'Sci-Fi', id: '3', authorId: '3' }, { name: 'The Maze Runner 2', genre: 'Sci-Fi', id: '4', authorId: '2' }, { name: 'The Colour of Magic', genre: 'Fantasy', id: '5', authorId: '3' }, { name: 'The Light Fantastic', genre: 'Fantasy', id: '6', authorId: '3' }, { name: 'The Maze Runner 3', genre: 'Sci-Fi', id: '7', authorId: '2' }, { name: 'Name of the Wind 2', genre: 'Fantasy', id: '8', authorId: '1' }, { name: 'Name of the Wind 3', genre: 'Fantasy', id: '9', authorId: '1' }, ]; var authors = [ { name: 'Patrick Rothfuss', age: 44, id: '1' }, { name: 'James Dashner', age: 42, id: '2' }, { name: 'Terry Pratchett', age: 66, id: '3' } ]; /// const BookType = new GraphQLObjectType({ name:'Book', fields:()=>({ id:{type:GraphQLID}, name:{type:GraphQLString}, genre:{type:GraphQLString}, author:{ type:AuthorType, resolve(parent,args){ console.log(parent); return _.find(authors, { id: parent.authorId }); } } }) }); const AuthorType = new GraphQLObjectType({ name:'Author', fields:()=>({ id:{type:GraphQLID}, name:{type:GraphQLString}, age:{type:GraphQLInt}, books:{ type:new GraphQLList(BookType), resolve(parent,args){ return _.filter(books, { authorId: parent.id }); } } }) }); const RootQuery = new GraphQLObjectType({ name:'RootQueryType', fields:{ book:{ type:BookType, args:{id:{type:GraphQLID}}, resolve(parent,args){ args.id //code to get data from db / other source return _.find(books, { id: args.id }); } }, author:{ type:AuthorType, args:{id:{type:GraphQLID}}, resolve(parent,args){ return _.find(authors, { id: args.id }); } }, books:{ type:new GraphQLList(BookType), resolve(parent,args){ return books; } }, authors:{ type:new GraphQLList(AuthorType), resolve(parent,args){ return authors; } } } }) module.exports = new GraphQLSchema({ query:RootQuery }) |
実行結果
コメント(//dummy data)の下に、本と作家の配列を書いています。
特定の作家の情報を取得するとき
特定の本の情報を取得するとき
GraphQLを使うメリット
- GraphQLを使うと、1回のHTTPリクエストで複数の異なる種類のデータを受け取ることが可能に
RESTなどのように - レスポンスのデータを使ってさらにリクエストを送る、といったことを何往復も繰り返す必要がなくなる
過剰なデータ取得を抑えられる - クライアントの変更に伴う新たなエンドポイント作成の必要がなくなる(GraphQLは基本的に単一のエンドポイント )
Author Profile
スターフィールド編集部
SHARE