nuxt3とapollo(4系)でGraphQL Serverを実装

# 概要
- nuxt3とapollo-serverの4系でGraphQLサーバを実装するサンプルを書いた。（2022/11/20 08:52:28）
- まちがってたらごめんね

# 準備
- nuxt3のプロジェクトを作成する。
```
$ npx nuxi init nuxt-app
$ cd nuxt-app
```

- apolloサーバとgraphqlをインストールする。
```
npm install @apollo/server graphql --save
```

# server/routes に tsファイルを置いてみる

- 名前は graphql.ts とかにしてみる

``` typescript: apollo.ts
import { readBody, getHeaders, H3Event } from "h3";
import {
  ApolloServer,
  HeaderMap,
  HTTPGraphQLRequest,
  ContextThunk,
  BaseContext,
} from "@apollo/server";

// schema
const typeDefs = `
type Book {
  title: String
  author: String
}
type Query {
  books: [Book]
}
`;

//  data
const books = [
  {
    title: "The Awakening",
    author: "Kate Chopin",
  },
  {
    title: "City of Glass",
    author: "Paul Auster",
  },
];

//  resolver
const resolvers = {
  Query: {
    books: () => books,
  },
};

//
//  sample query
//    query { books{ title author} }
//
//  test url
//    curl --request GET --header 'content-type: application/json' \
//      --url 'http://localhost:3000/api/apollo?query=%7Bbooks%7Btitle%7D%7D'
//
//    curl --request POST --header 'content-type: application/json' \
//      --url 'http://localhost:3000/api/apollo' --data '{"query":"query{books{title}}"}'

// initialize GraphQL server
//process.env.NODE_ENV = "production";
const apolloServer = new ApolloServer({
  typeDefs,
  resolvers,
  introspection: process.env.NODE_ENV !== "production",
});
apolloServer.start();

// execute request
const executeRequest = async (event: H3Event) => {
  //console.log("apollo: run event handler");
  const { req, res } = event.node;

  //  conver headers h3->apollo
  const apolloHeaders = new HeaderMap();
  const h3Headers = getHeaders(event);
  for (const k in h3Headers) {
    apolloHeaders.set(k, h3Headers[k] || "");
  }

  // build request object
  const query = req.url ? req.url.split("?", 2)[1] : "";
  const method = req.method || "GET";
  const httpGraphQLRequest: HTTPGraphQLRequest = {
    method,
    headers: apolloHeaders,
    search: method === "GET" ? query : "",
    body: method === "GET" ? "" : await readBody(event),
  };
  // context
  const context: ContextThunk<BaseContext> = async () => {
    return {};
  };

  // execute request
  const httpGraphQLResponse = await apolloServer.executeHTTPGraphQLRequest({
    httpGraphQLRequest,
    context,
  });

  // write response
  if (httpGraphQLResponse.body.kind === "complete") {
    res.end(httpGraphQLResponse.body.string);
  } else {
    for await (const chunk of httpGraphQLResponse.body.asyncIterator) {
      res.write(chunk);
      if (typeof (res as any).flush === "function") {
        (res as any).flush();
      }
    }
    res.end();
  }
};

console.log("apollo server initialized.");
export default defineEventHandler(executeRequest);
```

# 起動してURLにアクセス
- 起動
```
$ npm run dev
```
- http://localhost:3000/graphql

開発環境ならイントロスペクションが開くので

```
query { books{ title author} }
```

とか送信してみる。

# 結果
```
{
  "data": {
    "books": [
      {
        "title": "The Awakening",
        "author": "Kate Chopin"
      },
      {
        "title": "City of Glass",
        "author": "Paul Auster"
      }
    ]
  }
}
```

# おしまい
- おしまい。

# 今後
- nuxt3で特定のrouteへの接続をwebsocketにupgradeしたい