🍖

Node.js環境で、PythonのFastAPIみたいなOpenAPIドキュメント自動生成を求めて、Fastifyに手を出してみる

2021/07/15に公開

やりたかったこと

Node.jsでAPIを書いたら、OpenAPIドキュメントを自動生成して欲しい

背景

APIを書く場合に使うFrameworkにおいてPythonではDjangoやFlaskが有名ですが、最近注目されているFrameworkにFastAPIというものがあります。FastAPIは、動作がNode.js並に早いとか習得が容易といった特徴もありますが、コードを書くと自動でOpenAPIドキュメントを作ってくれてwebインターフェースも用意してくれる機能がとても便利です。
詳しくは知りたい方は、ドキュメントを読んでください。
https://fastapi.tiangolo.com/ja/features/

同じことがNode.jsで作ったAPIでもできないかなーと思って調べてみました。

Fastify使ったらできた

Fastify + fastify-swaggerでできました。
https://www.fastify.io
https://github.com/fastify/fastify-swagger

適当に作ったサンプル

https://github.com/k-ibaraki/fastify-swagger-sample

やったこと

導入

fastifyとfastify-swaggerをインストール

npm i fastify
npm i fastify-swagger

最低限の実装

とりあえず動くように書く

import * as fastify from 'fastify'
import fastifySwagger from 'fastify-swagger'

const server: fastify.FastifyInstance = fastify.fastify({ logger: true })

server.register(fastifySwagger, {
  routePrefix: '/docs',
  openapi: {},
  exposeRoute: true,
})
server.get('/ping', async (request, reply) => {
  return { pong: 'it worked!' }
})

server.listen(3000)

起動して、ブラウザから http://127.0.0.1:3000/docs にアクセスしたら動いた。

クエリパラメータを渡せるようにしてみる

queryとresponseのschemaを定義して、指定してあげる。
TSの型定義でハマった。とりあえず動くようにはした。正しい書き方を知りたい。

// queryとresponseのschemaを定義する
const schema1: fastify.RouteShorthandOptions = {
  schema: {
    querystring: {
      type: 'object',
      properties: {
        test_query: {
          type: 'number',
        },
      },
    },
    response: {
      200: {
        type: 'object',
        properties: {
          test_response: {
            type: 'number'
          },
        },
      },
    },
  },
}
// デフォルトだとqueryのTSとしての型定義がunknownなので、定義してあげる
interface Request1 extends fastify.RequestGenericInterface {
  Querystring: {
    test_query: number
  }
}
server.get<Request1, unknown, fastify.FastifySchema>('/querytest', schema1, async (request, reply) => {
  return { test_response: request.query.test_query }
})

動いた

パスパラメータを渡せるようにしてみる

クエリパラメータとほぼ同じ

// paramsとresponseのschemaを定義する
const schema2: fastify.RouteShorthandOptions = {
  schema: {
    params: {
      type: 'object',
      properties: {
        test_param: {
          type: 'string',
        },
      },
    },
    response: {
      200: {
        type: 'object',
        properties: {
          test_response2: {
            type: 'string'
          },
        },
      },
    },
  },
}
// デフォルトだとParamsのTSとしての型定義がunknownなので、定義してあげる
interface Request2 extends fastify.RequestGenericInterface {
  Params: {
    test_param: string
  }
}

server.get<Request2, unknown, fastify.FastifySchema>('/paramstest/:test_param', schema2, async (request, reply) => {
  return { test_response2: request.params.test_param }
})

動いた

所感

  • 結構いい感じに使えそう。想定通りOpenAPIドキュメントを自動生成してくれる。
  • Fastifyはexpressに使い勝手が近いのでとっつきやすいが、expressと比べるとマイナーなので情報が少ないのがツラい。特にTSの型がツラい。いい書き方が分からんのでサンプルが欲しいが、公式ドキュメントは基本JS。
  • Fastifyのschema定義とTSの型定義で同じことを2重に書いてる。無駄に感じる。型定義はTSの世界で完結させたい。
    • そういう意味だと、NestJSを使うのがいいのかもしれない。

Discussion