3
0

React+TypeScriptでOpenAPIを使ってRESTで通信

お仕事でAndroid+kotlinサーバサイドでOpenAPIを使ってREST通信のアプリを開発していたのですが、ひょんなことからWebアプリも開発することになりました。
ここ10数年くらいはサーバサイドばかりでフロントエンドやってなかったのですが、折角ならReact+TypeScrptで作ってみようと思い立ちました。

サーバサイドは今までと同じように、kotlin + sprintBoot3 + OpenAPIです。

OpenAPIのインタフェース(json、yaml)の作り方は変わりません。上記の記事の②の方法、サーバサイドの実装から作ります。

この時に1点注意しなければならないのは、サーバサイド側のControllerクラスのアノテーションの付け方で、

@RestController
class MyController(private val service: MyService) {

    @Tag(name = "mySearch")
    @Operation(
       ・・・・
    )
    @PostMapping(・・・)
    fun mySearch(@RequestBody request: MyRequest): ResponseEntity<MyResponse> {

@Tagアノテーションを付けないと、React側のTyepScriptのスタブのクラス名がControllerのクラス名になってしまいます。Controllerのクラス名が長い場合は@Tagアノテーションで指定してやります。@TagはそのControllerクラスの全てのメソッドで統一したほうがいいです。Controllerクラスを跨いで重複はできません。

React側でやること

Reactのプロジェクトを作成する

npxでTypeScript付でReactのプロジェクトを作ります。

npx create-react-app {プロジェクト名} --template typescript

OpenAPI Generatorのinstall

OpenAPI Generatorをinstallします。今回はHTTPクライアントライブラリにaxiosを使いますのでaxiosもinstallします。

cd {プロジェクト名}
npm install @openapitools/openapi-generator-cli -g  
npm install axios

OpenAPIのスタブの生成

OpenAPIのインタフェース定義(json、またはyaml)はサーバサイドで生成して、Reactの任意のフォルダにコピーしておきます。上記の記事を参考にしてください。ここでは仮に、

{プロジェクトRoot}/apiDoc/MyApplication.json

に置いたと仮定します。OpenAPIのスタブを生成するには、以下のように実行します。

npx @openapitools/openapi-generator-cli generate -i .\apiDocs\MyApplication.json -g typescript-axios -o src/openapi-generated
  • -i でOpenAPIのインタフェース定義(json、またはyaml)のパスを指定
  • -o で生成したスタブの出力先のフォルダを指定します
  • -g で生成するスタブのタイプを指定します。

この生成するスタブのタイプというのが、OpenAPI Generatorの公式ページを見ると、TypeScriptだけでもこれだけあります。

  • typescript (experimental)
  • typescript-angular
  • typescript-aurelia
  • typescript-axios
  • typescript-fetch
  • typescript-inversify
  • typescript-jquery
  • typescript-nestjs (experimental)
  • typescript-node
  • typescript-redux-query
  • typescript-rxjs

ぱっと見、どれにしたらいいのかわかりませんね。色々調べてChatGPTにも聞いてみた結果、axiosが良さそうということで、typescript-axiosにしました。

typescript-axiosの場合は上記のようにnpmでaxiosのinstallが必要になります。

スタブの出力先のフォルダには以下のようなファイルができているはずです。
image.png

OpenAPIのインタフェース定義の内容はほとんどがapi.tsで網羅されています。

OpenAPIインタフェースを非同期RESTで呼び出す。

さて、OpenAPIインタフェースを非同期RESTで呼び出すには

import {
  Configuration,
  MySearchApi,
  MySearchRequest,
  MySearchResponse
} from '../../openapi-generated';

const config= new Configuration({
  basePath: process.env.REACT_APP_API_BASE_PATH,
})
const myClient = new MySearchApi(config);

configのbasePathは.envから取得します。MySearchApiをconfigを引数にnewします。

RESTを呼び出す関数は、非同期関数で、以下の様になります

export async function mySearch(searchText: string): Promise<sting> {
  const request: MySearchRequest = {
    searchText: searchText,
  }
  return myClient.mySearch(request)
    .then((response) => {
      console.log(response.status);
      return response.data.seachResult;
    })
    .catch((error) => {
      console.log(`error=${error}`);
      throw error;
    });
}

そして、この非同期関数を呼び出す側の関数は以下の様になります。

    try{
      const result = await mySearch(searchText);
      // 何らかの処理
    } catch(error: unknown) {
      const axiosError = error as AxiosError;
      if (axiosError.response && axiosError.response.status === 400) {
        console.log('見つかりませんでした');
      } else {
        console.log('エラーが発生しました。');
      }
    }

React + TypeScriptでOpenAPIを使って見た感想

他でも同じですが、OpenAPIを使えばサーバサイドとクライアントでインタフェースのズレによる不可解な事象というのは起こりません。

また、REST通信は非同期なので、非同期関数(async)とそれを呼び出す(await)のふたつの関数が必要になりますが、独自で非同期通信を実装するよりは簡単だと思います。

サーバサイドが同じで、クライアントがAndroid(kotlin)、Web(JavaScript、TypeScript)、Java、go、PHP、Python・・・等々、色々な言語に対応できます。

是非、React + TypeScriptでOpenAPIを使って見てください。

3
0
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
3
0