LoginSignup
2
0

More than 3 years have passed since last update.

Rails + apipieでDartのクライアントコードを生成する

Posted at

背景

こちらの記事の続きです。

Docker+Rails6+apipieを使ってAPI定義をSwagger UIに表示 - Qiita

Dart/Flutterでアプリ開発をするメンバーに上記の定義ファイルを送ったところ、「Dartのクライアントコードを自動生成できない」と言われてしまいました。

今回はDartのクライアントコードを自動生成することをゴールに、apipieの設定を書き換えます。

環境

Ruby: 2.7.1
Rails: 6.0.3

Flutter/Dartとは?

Flutterについてざっくりまとめるとこんな感じでしょうか。

  • モバイルアプリフレームワークの1つ
  • Googleが開発
  • Dartという言語を使う

ReactNativeなどはWeb系経験者がアプリに手を出しやすくするものだが、DartはWeb系の経験がなくとも手を出しやすい、ようです。

また、DartはTypeScriptと似たaltJSです。
基本的にFlutter用の言語で、altJSとして使うんだったらTypeScriptを使うほうが良さげ、なようです。

cf. Flutterとは何か? 使うメリットや特徴を理解する (1/4):CodeZine(コードジン)

apipieの調整

さて実装面。
アプリ担当からは以下のエラーを受け取りました。

E/flutter (17797): [ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: ApiException 500: Exception during deserialization. (Inner exception: ApiException 500: Could not find a suitable class for deserialization)
E/flutter (17797): 
E/flutter (17797): #0      ApiClient._deserialize (package:openapi/api_client.dart:57:5)
E/flutter (17797): #1      ApiClient._deserialize.<anonymous closure> (package:openapi/api_client.dart:50:43)
E/flutter (17797): #2      MappedIterator.moveNext (dart:_internal/iterable.dart:392:20)
E/flutter (17797): #3      MapBase._fillMapWithIterables (dart:collection/maps.dart:83:39)
E/flutter (17797): #4      new LinkedHashMap.fromIterables (dart:collection/linked_hash_map.dart:127:13)
E/flutter (17797): #5      ApiClient._deserialize (package:openapi/api_client.dart:49:26)
E/flutter (17797): #6      ApiClient.deserialize (package:openapi/api_client.dart:67:12)
E/flutter (17797): #7      UsersApi.postApiV1UsersToken (package:openapi/api/users_api.dart:77:49)

当方Dartは未経験でして、エラーを見てもなんのこっちゃだったので、アプリ担当に定義ファイルをいじってもらい動くようにしてもらいました。

その結果、以下3つが主な原因とわかりました。

  • basePathの指定がない
  • "additionalProperties": falseに指定している
  • レスポンスにtitleがない

basePathを指定する

api_base_urlが空欄だと警告がでるそうなので追加します。

apipie.rb
-  config.api_base_url            = ""
+  config.api_base_url            = "/api"

前回の記事 にて、わざわざapi_base_urlを消していたようです。。

"additionalProperties": falseに指定している

additionalPropertiesとは、「propertiesで指定したプロパティ以外も受け付けるかどうか」を指定するオプションのようです。

trueならpropertiesに記載がないプロパティも受け付けるが、falseだとダメなようです。

cf. OpenAPIのadditional_propertyオプションってなに?

クライアントコード生成時にエラーが起きた原因は、これがfalseになっていたから、のようです。

apipieでは初期値がfalseのため、trueに設定しましょう。

apipie.rb
+ config.swagger_allow_additional_properties_in_response = true

cf. Swagger-Specific Configuration Parameters

なお、レスポンスする全てのプロパティ(status, messageなど意図して返すもの)を含んでいる状態で生成を試みてもエラーは起きるようです。
(ここは未解決...)

レスポンスにtitleがない

API定義(swagger.json)にtitleがない場合、クラス名がInlineResponse200となってしまうようです。

swagger.json
            "schema": {
               "type": "object",
+              "title": "Token",
               "properties": {

apipieのリファレンスを見ても該当箇所にtitleを追加する記述は見つかりませんでした...。

が、 Response Description に似た実装があり、試したところうまくいきました!

api/v1/users_controller.rb

+  def_param_group :user_login_token do
+    property :status, Integer, desc: "status code"
+    property :message, String
+    property :detail, String, desc: "user token"
+  end

 api :POST, "/v1/users/token", "get access token"
  description "ログイン認証をしてトークンを返す"
  formats ["json"]
  param :email, String, desc: "メールアドレス", required: true
  param :password, String, desc: "パスワード", required: true
-  returns code: 200, desc: "return user token"
+  returns :user_login_token, desc: "return user token"
  error code: 401, desc: "Unauthorized."

以上の修正をすることで、Dartのクライアントコードを生成できるようになりました。

余談:ブラウザからDartのクライアントコードを作る

  1. Swagger Editor にAPI定義ファイルをペーストする
  2. ヘッダーのGenerate Clientからdartを選択する

という方法で、クライアントコードを生成できます。
今回程度の動作確認であれば十分できますね。

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