REST APIクライアントの作成
ToDo一覧を実装する際には、バックエンドのREST APIにアクセスする必要があります。ここでは、OpenAPIドキュメントを利用してREST APIのクライアントを作成します。
OpenAPIドキュメントの確認
REST APIをOpenAPI仕様で記述したOpenAPIドキュメントは、プロジェクト作成時に作成しています。(参考:OpenAPI - Specification)
バックエンドのrest-api-specification/openapi.yaml
ファイルがOpenAPIドキュメントになるため、内容を確認します。
例えば、ToDoの一覧を取得するためのREST APIは、次のように定義されています。
/api/todos:
get:
summary: ToDo一覧の取得
description: >
登録しているToDoを全て取得する。
tags:
- todos
operationId: getTodos
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Todo'
examples:
example:
value:
- id: 2001
text: やること1
completed: true
- id: 2002
text: やること2
completed: false
'403':
description: Forbidden
summary
やdescription
には、ドキュメント化したときの説明文を定義します。
tags
には、REST APIをグルーピングするための名前を定義します。ここでは、ToDo管理とユーザー認証のREST APIを区別するために使用します。このtags
を指定することで、OpenAPIドキュメントから様々な成果物を生成したりする際に、グルーピングされるようになります。例えば、REST APIのクライアントコードでは、tags
に指定した名前ごとにクラス(ここではTodosApi
)が生成されるようになります。
operationId
には、それぞれのREST APIを一意に識別するためのIDを定義します。これはクライアントを自動生成した際の関数名にもなるため、それを考慮して定義します。
responses
には、レスポンスを定義します。responses
にはステータスコードごとに定義します。JSON形式で返却するため、content
としてapplication/json
を定義します。
content
内のschema
には、レスポンスデータの形式を定義します。ここでは、配列を返すように定義し、配列の中については$ref
を使って共通で定義したコンポーネントを参照するよう定義します。複数のREST APIで扱うToDoレスポンスの形式が同じであるため、このような定義にしています。
参照先となる形式は、次のように定義しています。
components:
schemas:
Todo:
title: Todo
type: object
description: ToDo情報
properties:
id:
type: integer
description: ToDoのID
text:
type: string
description: ToDoのタイトル
completed:
type: boolean
description: ToDoのステータス
required:
- id
- text
- completed
additionalProperties: false
properties
には、このコンポーネントの項目を定義します。全ての項目が必ず必要であるため、required
には全ての項目を定義します。ここで定義していない項目が追加で返却されることは想定していないため、additionalProperties
にはfalse
を定義します。
content
内のexamples
に、実際に返却される例を定義します。
これらから、REST APIで返却されるJSONは、次のようなイメージになります。
{
[
{
"id": 2001,
"text": "やること1",
"completed": true
},
{
"id": 2002,
"text": "やること2",
"completed": false
}
]
}
クライアントコードの生成
REST APIのクライアントコードを、OpenAPIドキュメントから生成します。
クライアントコードの生成には、OpenAPI Generatorを使用します。OpenAPIが提供しているツールで、OpenAPIドキュメントから様々なものを生成することができます。TypeScript用のクライアントコードについても様々な実装を生成することができますが、ここではtypescript-fetch
を使用します。
OpenAPI Generatorはコンテナイメージでも提供されています。そのコンテナイメージを使用して実行するためのDocker Composeファイルとしてdocker-compose.api-gen.yml
を予め作成しているため、Docker Composeを使用してDockerコンテナ上で生成します。
frontend
ディレクトリで、次のコマンドを実行します。
$ docker-compose -f docker/docker-compose.api-gen.yml up
実行が完了すると、src
の下にbackend
ディレクトリが生成され、その配下にgenerated-rest-client
ディレクトリが生成されます。このgenerated-rest-client
配下に、自動生成されたクライアントコードが格納されています。
フロントエンドでREST APIを呼び出す際には、このクライアントコードを使用していきます。
クライアントコードのラッパーを作成
OpenAPIドキュメントからREST APIのクライアントコードを生成しましたが、使用時には同じ設定を行うことが多くなります。そこで、共通的な設定がされたクライアントコードを使用するために、生成したクライアントコードをラッピングしたBackendSerivce
を作成します。コンポーネントからREST APIにアクセスする際には、生成したクライアントコードは直接使用せずに、このBackendSerivce
を使用するようにします。
src/backend
ディレクトリにBackendService.ts
を作成します。
src/backend/BackendService.ts
import {
Configuration,
TodosApi,
Middleware,
UsersApi
} from './generated-rest-client';
const requestLogger: Middleware = {
pre: async (context) => {
console.log(`>> ${context.init.method} ${context.url}`, context.init);
},
post: async (context) => {
console.log(`<< ${context.response.status} ${context.url}`, context.response);
}
};
const configuration = new Configuration({
middleware: [requestLogger]
});
const todosApi = new TodosApi(configuration);
const usersApi = new UsersApi(configuration);
const signup = async (userName: string, password: string) => {
return usersApi.signup({ inlineObject2 : { userName, password }});
};
const login = async (userName: string, password: string) => {
return usersApi.login({ inlineObject3: { userName, password }});
};
const logout = async () => {
return usersApi.logout();
};
const getTodos = async () => {
return todosApi.getTodos();
};
const postTodo = async (text: string) => {
return todosApi.postTodo({ inlineObject: { text }});
};
const putTodo = async (todoId: number, completed: boolean) => {
return todosApi.putTodo({ todoId, inlineObject1: { completed }});
};
export const BackendService = {
signup,
login,
logout,
getTodos,
postTodo,
putTodo
};
生成されたクライアントコードでは、REST APIを呼び出すためにはTodosApi
等のAPIクラスのオブジェクトを生成する必要があります。生成時には設定オブジェクトを渡すことで、様々な設定をすることができます。
生成したクライアントコードでは、Middlewareと呼ばれる部品を作成することで、リクエストやレスポンスに対する共通的な処理を実装することができます。ここでは、開発時にREST APIの呼び出しを確認しやすいように、リクエストとレスポンスをコンソールにログ出力するMiddlewareを作成します。
なお、OpenAPIドキュメントにはToDoを削除するためのREST APIも定義されていますが、削除については後の演習にて自身で実装できるよう、ここでは作成しません。