47
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SWR(React Hooks)とaspidaで型安全にREST APIをfetchする

Posted at

TypeScript 4.1 で使えるようになる template string types が話題ですね
人類の悲願である Swagger/OpenAPI から静的型操作のみで使える型安全なクライアントを作製した猛者も現れました

この記事では template string types とは全く関係ない、上記ツイートでいうところの「 AST によるコード生成」によって型安全な HTTP リクエストを実現する「aspida」と Vercel 社製の React Hooks である「SWR」を組み合わせて使う方法を紹介します

Next.js + TypeScript のインストール

せっかく SWR を使うので同じ Vercel 社製の Next.js で React の環境構築を進めていきます
yarn を使っていますが、 npm でもインストール可能です

$ npx create-next-app next-ts # "next-ts" の部分は好きなディレクトリ名で
$ cd next-ts
$ yarn add --dev typescript @types/react @types/node # Next.js のTS化に必要なモジュールを追加

pages ディレクトリに生成される index.js ファイルの拡張子を tsx に変えると Next.js に TypeScript 環境だと認識されます

pages/index.js -> pages/index.tsx

dev コマンドで tsconfig.jsonnext-env.d.ts が生成されてアプリが起動します

$ yarn dev

http://localhost:3000 で以下の画面が開けるはずです

キャプチャ.PNG

API の型定義生成と aspida のインストール

通常、 aspida は自分で型定義ファイルを記述してからコード生成コマンドで HTTP クライアントを作るのですが、今回はネットに公開されている Petstore の Swagger から一発で生成します

$ npx openapi2aspida -i https://petstore.swagger.io/v2/swagger.json

Next.js のルートディレクトリで上記のコマンドを打つと、 api ディレクトリに型定義ファイル一式と HTTP クライアント ($api.ts) が生成されます

キャプチャ3.PNG

ディレクトリ名が API のエンドポイントに対応しています
これらのファイルをアプリケーションで扱うために aspida と SWR のモジュールを追加します

$ yarn add @aspida/fetch @aspida/swr swr

SWR と aspida で型安全に fetch する

今回は Petstore の API でクエリを付けて簡単に GET 出来る以下のエンドポイントを叩くコードを書いていきます

キャプチャ4.PNG

pages/index.tsx の冒頭に以下のコードを追記します
return 以降は元のままです

pages/index.tsx
import Head from 'next/head'
import useAspidaSWR from '@aspida/swr'
import aspida from '@aspida/fetch'
import api from '../api/$api'
import styles from '../styles/Home.module.css'

const client = api(aspida())

export default function Home() {
  const { data, error } = useAspidaSWR(
    client.pet.findByStatus, // GET: /pet/findByStatus
    { query: { status: ['pending', 'sold'] }}
  )

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>

  console.log(data)

  return (
    <div className={styles.container}>
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
...

たったこれだけで返り値の data に Pet[] という型が推論されていることがわかります
当然 query にも型が強制されていて status には ("available" | "pending" | "sold")[] が必須です

キャプチャ2.PNG

console に出力するだけなので画面は変わりませんが、以下のように配列でペットの情報を取得出来ています

キャプチャ1.PNG

useAspidaSWR の返り値は SWR そのものです
第一引数のクライアントからパス文字列を取り出して、第二引数のクエリとともに SWR に cache key として渡しています

const { data, error } = useAspidaSWR(
  client.pet.findByStatus, // GET: /pet/findByStatus
  { query: { status: ['pending', 'sold'] }}
)

GET: /pet/{petId} のようなパス変数を取るエンドポイントはアンダースコアで始まる関数を使います
query が不要なエンドポイントなので引数は一つだけです

const { data, error } = useAspidaSWR(client.pet._petId(123))

今回は Swagger から生成しましたが、 aspida を使うと社内 API にも比較的手軽に型定義が出来るのでぜひ試してみてください
aspida 解説記事:HTTPリクエストを型安全にする手法とOSS

useAspidaSWR に SWR 本来のオプションを渡す方法などはリポジトリの README を読んでください
GitHub: @aspida/swr

47
18
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
47
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?