😀

Next.jsでGraphQLサーバーを実装する方法

2021/04/02に公開

Next.jsはバージョン9でDynamic Routesが追加されてとても便利になりました。

ページのファイルを動的に読み込んでくれるだけではなく、Dynamic RoutesのおかげでAPIの追加も気軽になりました。

これにより決められたディレクトリにパスとなる任意のファイル名でコードを配置すると自動的にルーティングの設定ができます。

Next.jsを使ってGraphQLサーバーを実装する機会があったので、コードと合わせて作り方を紹介したいと思います。

Next.jsでのAPI実装方法

Next.jsでAPIを定義するにはpages/apiディレクトリにファイルを追加します。

例えば/api/usersというルーティングを設定したい場合は/pages/api/users.jsというファイル名で下記のようなコードです。

export default async (req, res) => {
  const data = 'User API'
  
  res.json(data) // dataはレスポンスしたいデータ
}

これで/api/usersにアクセスすると「User API」というデータが返ってくるようになります。

GraphQL用のファイルを追加

pages/apiディレクトリでAPIの実装ができることを利用して、GraphQLもapiディレクトリに実装します。

まずはpages/api/graphql.jsを下記のコードで作ります。

import { graphql, GraphQLSchema, GraphQLObjectType, GraphQLID, GraphQLString, GraphQLInt } from 'graphql'

const UsersType = new GraphQLObjectType({
  name: 'UsersType',
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
  })
})

const UsersQuery = {
  type: UsersType,
  args: {},
  resolve: async (parent, args, context, info) => {
  	const data = [
      { id: 1, name: 'User1'},
      { id: 2, name: 'User2'},
    ]
    return data
  }
}

const schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'RootQuery',
    fields: () => ({
      users: UsersQuery
    })
  })
})

export default async (req, res) => {
  const query = req.body.query
  const variables = req.body.variables
  const response = await graphql(schema, query, null, null, variables) //

  res.setHeader(`Content-Type`, `application/json; charset=utf-8`)

  return res.end(JSON.stringify(response))
}

これで/api/graphqlにGraphQLのクエリを送るとレスポンスを得られるようになります。

TypeとQueryの定義も一つのファイルに書いていますが、実際に使う時はtypesやqueriesなどに適切にファイルを分割することになります。

GraphQLのメソッドをPOSTに限定する

Next.jsでAPIを定義すると紹介した方法では、リクエストがGETでもPOSTでも同じ処理が走ってしまいます。

そこでメソッドを判定してPOSTのみで処理が走るようにします。

export default async (req, res) => {
  if (req.method === 'POST') {
  	const query = req.body.query
    const variables = req.body.variables
    const response = await graphql(schema, query, null, null, variables) //

    res.setHeader(`Content-Type`, `application/json; charset=utf-8`)

    return res.json(response)
  }
}

reqオブジェクトでリクエスト時のmethodが取得できます。

これはNext.jsの公式でも紹介されていて今ところ、メソッドをわけるにはreq.methodの値を見て分岐させるしかないようです。

<ExternalLink url="https://nextjs.org/docs/api-routes/introduction" title="Introduction - Documentation | Next.js" />

GrapQLのように1つのメソッドだけ定義したり、コード量が少なければ直接書いても良いと思います。

ですがREST APIのようにGET、POST、PUT、DELETEなどURLが同一でいくつかのアクションに分かれる時は適宜ファイルを分割するのがいいと思います。

まとめ

Dynamic RoutesがサポートされるようになってNext.jsはグンと使いやすくなりました。

ページの実装と合わせてAPIも平行して手軽に開発できるのは大きなメリットです。

React.jsのフレームワークは他にもいくつかありますが、Next.jsは積極的に使っていきたいと思います。

Discussion