Next.js 9で3分で1からTypeScriptのReactサーバーとGraphQLサーバを立てよう

# 概要
* [Next.js 9](https://github.com/zeit/next.js)のAPI Routeに[GraphQL](https://github.com/apollographql/apollo-server)のエンドポイントを生やします
* Next.jsもGraphQLもTypescriptで書けます



# やり方
####1. 必要なパッケージをインストール

```terminal:terminal
yarn add apollo-server-micro graphql micro next@latest react@latest react-dom@latest
yarn add -D typescript @types/react
```

####2. テキトーにメインページを作る

`pages/index.tsx`を作り、テキトーにメインページを立ちあげる。**拡張子をtsxにしておくと、Next.js 9は勝手にTypescriptのtsconfig.jsonを用意してくれる**。


速さ⚡️を求めるならば、`tsconfig.json`を書く前に、サーバーを立ち上げる。

テキトーなメインページの例👇


```tsx:pages/index.tsx
export default ()=>(
    <p>ほげ</p>
)
```

Reactのコンポーネントを`export default`すればそれが配信される。画像などのファイルは`/static`配下に単に配置すれば配信される。

###### サーバー立ち上げ

```terminal:terminal
yarn next
```

###### 初回のターミナルのログの例

```terminal:terminal
~/W/next9 graphql ❯❯❯ yarn next
yarn run v1.15.2
warning package.json: No license field
$ '/███████████/██████████/next9 graphql/node_modules/.bin/next'
[ wait ]  starting the development server ...
[ info ]  waiting on http://localhost:3000 ...
We detected TypeScript in your project and created a tsconfig.json file for you.

Your tsconfig.json has been populated with default values.

[ info ]  bundled successfully, waiting for typecheck results ...
[ ready ] compiled successfully (ready on http://localhost:3000)
```

http://localhost:3000
<img width="616" alt="スクリーンショット 2019-07-09 13.55.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/adbc3f7b-6877-9e77-add1-fa71444a79a6.png">

※ Next.js 9からサーバーでプレレンダリングできていると、右下に⚡️マークがつくようになりました。


####3. テキトーにGraphQLサーバーを作る

`/pages/api`配下にはAPIのエンドポイントを生やせる。GraphQLのモックサーバを立てよう。

```/pages/api/index.ts
import { ApolloServer, gql } from 'apollo-server-micro';

// ここからGraphQLのモックの定義
const typeDefs = gql`
    type Query {
        hello: String
    }
`;

const resolvers = {
    Query: {
        hello: () => 'world',
    },
};

const apolloServer = new ApolloServer({ typeDefs, resolvers });

// ここから先はNext.jsが読みに行く領域
export default apolloServer.createHandler({path:"/api"});
export const config = {
    api: {
        bodyParser: false,
    },
};
```

サーバー再起動するまでもなく、APIが立ち上がる。

http://localhost:3000/api
<img width="927" alt="スクリーンショット 2019-07-09 13.59.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403150/03801dff-4af8-1e6d-858e-98da6e398fc1.png">

💃🕺嬉しい💃🕺

ここから、[ApolloClient](https://github.com/apollographql/apollo-client)を入れるなり、モックじゃないGraphQLサーバーをこしらえるなりすると良い。

**参考:** [Apollo Client + React 入門
](https://qiita.com/seya/items/e1d8e77352239c4c4897)
### 終わり


---------

# ポイント
####  tsconfig書く前に、サーバー立ち上げてしまおう。

Next.js 9からは、`tsx`をNext.jsが見えるどこかにおけば、勝手に以下の`tsconfig.json`が用意されてしまう。`tsc --init`したのが書き変わるのでさっさと立ち上げたいなら、`next`を先にする方が早い。

短絡的に言えば、`pages/index.tsx`書けばオッケー。

```js:tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": false,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve"
  },
  "exclude": [
    "node_modules"
  ],
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ]
}
```

#### apollo-serverはmicro用のやつを使う。

`pages/api`配下で (req, res)を受け取る関数を`export default`すれば、APIサーバが立つという寸法。

```ts
export default (req, res) => {
  res.setHeader('Content-Type', 'application/json')
  res.statusCode = 200
  res.end(JSON.stringify({ name: 'Nextjs' }))
}
```

デフォルトのres,req（ただし幾らかミドルウェアが入っている）をいじるより、Zeit▲の[micro](https://github.com/zeit/micro)でマイクロサービスを`/pages/api`にもさもさ生やせば、賑やかになると思う。これはご機嫌。

**参考**:[next.js/examples/api-routes-micro/](https://github.com/zeit/next.js/tree/canary/examples/api-routes-micro)

ということで、`apollo-server-ナンチャラ`は、`apollo-server-micro`を使うっぽいなあってのは、[API Route](https://github.com/zeit/next.js#api-routes)の見た目にわかった。しかし、GraphQLサーバを立たせるに当たって2点ハマりポイントがあった。


##### ハマり1. graphQLサーバのパスをちゃんと指定する。
`apollo-server`はデフォルトで`localhost:3000/graphql`にサーバーを立たせようとする。

一方で、Next.js 9はAPIを単純な設定ならば`localhost:3000/api`配下にしか生やせない。したがって、`apollo-server-micro`の`createHandler`にオプションを指定する。

```ts
const apolloServer = new ApolloServer({ typeDefs, resolvers });

const handler = apolloServer.createHandler({path:"/api"});
```

この`handler`を`export default`すれば、graphQLサーバが立つもんだと思ったらそうはいかない。

##### ハマり2. export const config={option}ちゃんとする

```ts
export default handler;
```
したところで`GraphQL Playground`が動いているので、見た感じAPIが機能しているように思えるが、スキーマをダウンロードできない、クエリを投げられないで、まともに動いていない。

これは、`Next.js 9`が自動で設定している`bodyParser`が原因らしい。数時間時間を潰してしまった。

`Next.js 9`のAPI routesは備え付けで少しのミドルウェア([cokkieやquery、bodyをreqに生やすことができるやつ](https://github.com/zeit/next.js#api-middlewares))が入っており、その中で、`bodyParser`はデフォルトでonであり、`req`をパースしてしまう。

しかし、API配下で、`Next.js 9`に設定を伝える方法があるのでこのようにすると、クエリも投げられるし、スキーマもダウンロードできるようになる。以下のconfigは決め打ちで。

```ts
export default apolloServer.createHandler({path:"/api"});

export const config = {
    api: {
        bodyParser: false,
    },
};
```

**参考** [next.js/examples/api-routes-graphql/](https://github.com/zeit/next.js/tree/canary/examples/api-routes-graphql)

# まとめ
* 恐ろしく楽チンにNextのサーバーとGraphQLのサーバを立てられるようになった。