FlutterでSwagger(openapi-generator)を使う方法

Flutterを使いアプリを作るのに、、APIと連携する部分はswaggerから自動生成したいと考え、openapi-generatorを使うことにしました。
ちなみに、Flutterは、始めたばかりでよくわからず、なんとなく動けばいいかくらいでやってます。。

いくつか参考になりそうなページがあったのですが、その中でも、
[Flutter Swagger統合](https://future-architect.github.io/articles/20210511b/)が、わかりやすくサンプルコードもあったのでこちらを参考に実装してみました。

## 試した環境
* Flutter 2.5.3
* Dart 2.14.4
* Swagger 3.0.0

## 事前準備
通信するAPIを事前に作っておいて、それをローカルで起動します。
URL：http://localhost:31180/user
メソッド：POST
リクエスト：なし
で実行する簡易的なAPIを用意しました。
swaggerも作成します。
実際のswaggerから、今回必要な箇所を抜粋したのが以下です。

```yaml:swagger.yaml
openapi: 3.0.0
info:
  title: sample
  version: '1.0'
  description: sample
  contact:
    name: murapon
servers:
  - url: 'http://localhost:31180'
tags:
  - name: user
paths:
  /user:
    post:
      operationId: post-user
      tags:
        - user
      summary: ユーザー登録
      description: ユーザーを作成し、uuid等を返す
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/response_user_post'
components:
  schemas:
    response_user_post:
      title: response_user_post
      description: ユーザー作成APIのレスポンスモデル
      type: object
      properties:
        uuid:
          type: string
          description: UUID
        password:
          type: string
          description: パスワード
      required:
        - uuid
        - password
```

## ライブラリーのインストール
openapi-generatorインストール
こちらは参考にした[ページ](https://future-architect.github.io/articles/20210511b/)通りインストールするだけです。

## swaggerからflutter用コードを生成
事前に、静的なページを表示するFlutterアプリは作っていたので、そこに生成しました。

```sh
openapi-generator generate -i ./openapi/definitions/sample.yaml -g dart -o ./openapi/generated/client/
```

で入れられます。
ここも[参考ページ](https://future-architect.github.io/articles/20210511b/)通りです。sample.yaml部分は、作ったswaggerファイル名に書き換えてください。
生成したら、
```sh flutter pub get
```
を実行してください。

## APIの実行コードの作成
APIを実行するコードは、参考ページのをそのまま使うとエラーになったので、以下のように変えました。

```dart:api.dart
import 'package:openapi/api.dart';

class sample {

  test() async {
// ① ベースとなるAPIクライアント生成
    var client = ApiClient(basePath: "http://10.0.2.2:31180");
// ヘッダを追加したい場合はクライアントに設定可能
//  client.addDefaultHeader("key", "value");

// ② APIクライアントラッパーを生成
// APIレスポンスをモデルに変換してくれる
    var api = UserApi(client);

// ③ レスポンスボディのみが欲しい場合は${HTTPメソッド名+パス名}のメソッドをcall
    ResponseUserPost user = await api.postUser('');
    print(user.toJson());
  }
}
```

まず、①の接続先URLが、localhostになっていたのですが、Androidシミュレータだとうまくいかなったので、
https://sunnyday-travel-aso-6487.ssl-lolipop.jp/programing/flutter/socketexception/
を参考に、10.0.2.2に変えました。
あと、③のapi.healthGet();が、パス名+HTTPメソッド名という並びになってたのですが、実際に生成されたソースを見ると、HTTPメソッド名+パス名という逆順になっていたのでそこを変えました。
（ライブラリーのバージョンの違いによる？）
また、レスポンスボディを取得するのが、valueだとうまくいかず、生成されたソースにあるtoJsonを使うと取得することができました。

APIを実行したい画面を表示しているソースに

```dart:samle_page.dart
Widget build(BuildContext context) {
・・・
  try{
    var a = new sample();
    a.test();
  } catch (e) {
    print(e.toString());
  }
・・・
}
```
のように書くと、とりあえず動くことを確認できます。
try,catchはなくてもいいのですが、あるとエラーを検出してくれます。
APIで返される項目名や型が、swaggerの定義と違うと処理できないのですが、その時のエラーは、try,catchを使ってないと検出できませんでした。

## HTTPステータスコードをチェックしたい時
レスポンス結果だけを取得したい場合は、

```dart
ResponseUserPost user = await api.postUser('');
```
と、**postUser**を使うとよいのですが、エラー時などにHTTPステータスコードをチェックし処理を変えたい場合は、

```dart
ResponseUserPost user = await api.postUserWithHttpInfo('');
```
と、**postUserWithHttpInfo**を使うとよいです。
httpステータスは、**postUserWithHttpInfo.statusCode**、レスポンスの中身は、**postUserWithHttpInfo.body**などとレスポンス内容を取得できます。
[HttpStatusクラス](https://api.dart.dev/stable/2.8.2/dart-io/HttpStatus-class.html)を使って、

```dart
ResponseUserPost user = await api.postUserWithHttpInfo('');
if(user.statusCode == HttpStatus.unauthorized) {
    // 認証に失敗したらログイン画面へ遷移する
}
```
などと言った処理も書くことができます。

## おまけ
他にもメソッドやら、定数が自動生成されていて、いろいろ使い方ができそうなので見てみるとよいかと思います。初心者でも比較的読みやすいかと思います。