🍺

Node.js + fastify4 + TypeScript + SwaggerでRESTサーバを構築する

2022/12/28に公開

概要

Node.js、fastify4、TypeScript、Swaggerで簡単なサンプルを作ってみたので共有します。
サンプルコード: https://github.com/swmokyun/sample-fastify4-typescript-swagger

目的

  • とにかくラクにRESTサーバを作りたい
  • pythonでもいいけどフロントエンドでNext.jsとかつかうからNode.jsで言語を統一したい
  • TypeScriptで型の恩恵を受けたい
  • SwaggerでRESTスキーマまわりのあれこれをラクしたい

expressよりfastifyがいいらしい

Node.jsでサーバといえばexpressと思ってたけど、最近ではKoa.jsとかfastifyが有力候補らしい。fastifyの方がtypescriptまわりがいい感じにサポートされているっぽいのでこっちをチョイス。

https://www.fastify.io/

fastify-swaggerがいい感じ

調べた感じではfastify-swaggerを使うとtypescriptで型補完しながらスキーマ定義が記述できるっぽい。これは素晴らしい。
https://github.com/fastify/fastify-swagger

typeboxでさらにいい感じ

typeboxを使うとfastifyでスキーマ定義と関数の型を共通化できる。これはさらに素晴らしい。
https://www.fastify.io/docs/latest/TypeScript/#json-schema

サンプル

公式を参考にGETやqueryのサンプルを追加したのが以下になります。
また、各モジュールのバージョンは以下になっています。fastifyはバージョンがあがると結構APIが変わるっぽいので注意。

"@fastify/swagger": "^8.2.1",
"@fastify/swagger-ui": "^1.3.0",
"@sinclair/typebox": "^0.25.16",
"fastify": "^4.10.2"
import { Static, Type } from "@sinclair/typebox"
import Fastify from "fastify"

const runFastify = async () => {
  const fastify = Fastify({
    logger: true,
  })

  await fastify.register(require("@fastify/swagger"))
  await fastify.register(require("@fastify/swagger-ui"), {
    routePrefix: "/documentation",
    staticCSP: true,
    transformSpecificationClone: true,
  })

  /**
   * test_post
   */
  const User = Type.Object({
    name: Type.String(),
    mail: Type.Optional(Type.String({ format: "email" })),
  })
  type UserType = Static<typeof User>

  fastify.post<{ Body: UserType; Reply: UserType }>(
    "/test_post",
    {
      schema: {
        body: User,
        response: {
          200: User,
        },
      },
    },
    (req, rep) => {
      const { body: user } = req
      rep.status(200).send(user)
    }
  )

  /**
   * test get, querystring
   */
  const ErrorResponse = Type.Object({
    msg: Type.String(),
  })
  type ErrorResponseType = Static<typeof ErrorResponse>

  fastify.get<{ Querystring: UserType; Reply: UserType | ErrorResponseType }>(
    "/test_get",
    {
      schema: {
        querystring: User,
        response: {
          200: User,
          400: ErrorResponse,
        },
      },
    },
    (req, rep) => {
      const { query: user } = req
      if (user.name.length < 3) {
        rep.status(400).send({ msg: "name is too short" })
      } else {
        rep.status(200).send(user)
      }
    }
  )

  /**
   * start fastify
   */
  await fastify.ready()
  fastify.listen({ port: 3000 }, function (err, address) {
    if (err) {
      fastify.log.error(err)
      process.exit(1)
    }
  })
}

runFastify()

http://localhost:3000/documentation でSwaggerからAPIの確認やJSONスキーマの出力が可能。とっても便利で開発が捗ります。

Discussion