Flutterでopenapi-generator-cliを使っているとき、null-aware-elementsで失敗する際の対応

こんにちは、Rerurate_514と申します。
今回はこのエラーを修正した時の対応を書いたものです。
以下エラー。

task: [gen-api-from-openapi-dir] flutter pub run build_runner build --delete-conflicting-outputs
Deprecated. Use `dart run` instead.
0s json_serializable on 18 inputs: 9 skipped; lib/src/model/error.dart                                                       
0s copy_with_extension_gen on 18 inputs                                                                                      
0s source_gen:combining_builder on 18 inputs                                                                                 
                                                                                                                             
Building, incremental build.                                                                                                 
                                                                                                                             
log output for json_serializable on lib/src/model/error.dart                                                                 
W The language version (3.5.0) of this package (openapi) does not match the required range `^3.8.0`.                         
  Edit pubspec.yaml to include an SDK constraint of at least ^3.8.0.                                                         
  environment:                                                                                                               
    sdk: ^3.8.0                                                                                                              
E An error `FormatterException` occurred while formatting the generated source for                                           
    `package:openapi/src/model/error.dart`                                                                                   
  which was output to                                                                                                        
    `lib/src/model/error.json_serializable.g.part`.                                                                          
  This may indicate an issue in the generator, the input source code, or in the                                              
  source formatter.                                                                                                          
  Could not format because the source could not be parsed:                                                                   
  line 22, column 18 of .: This requires the 'null-aware-elements' language feature to be enabled.                           

  22 │         'error': ?instance.error,                                                                                     
     │                  ^                                                                                                    

log output for build_runner                                                                                                  
W SDK language version 3.11.0 is newer than `analyzer` language version 3.9.0. Run `flutter packages upgrade`.               
Log overflowed the console, switching to line-by-line logging.
  1s json_serializable on 18 inputs: 17 skipped, 1 same
  0s copy_with_extension_gen on 18 inputs; lib/openapi.dart
  0s copy_with_extension_gen on 18 inputs: 18 skipped
  0s source_gen:combining_builder on 18 inputs; lib/openapi.dart
  0s source_gen:combining_builder on 18 inputs: 18 skipped
  Running the post build.
  Writing the asset graph.
  Failed to build with build_runner in 2s with warnings; wrote 1 output.
Failed to update packages.
task: Failed to run task "gen-api": task: Failed to run task "gen-api-from-openapi-dir": exit status 1

経緯

まず私はopenapiの生成をhonoopenapi-zodを使用して行っておりました。
そして以下のようなコードを書いてopenapi.jsonを生成しました。

import { z } from "@hono/zod-openapi";
 
export const ErrorSchema = z.object({
    code: z.number().openapi({ example: 400 }),
    message: z.string().openapi({ example: "データの取得に失敗しました。" }),
    error: z.string().optional().openapi({ example: 'Bad Request' }),
}).openapi('Error');

ここで注目してほしいのはerroroptionalです。これはなくてもいいプロパティにつけるものですが、これが問題の引き金になりました。

ここで生成されたopenapi.jsonをFlutter側で使用してクラスを生成していきます。
そして、生成されたopenapiディレクトリの中でflutter pub run build_runner buildをしたところ、上記のようなエラーになりました。

これはnull-aware-elements構文がdartのsdkの3.8以上で実装されているのに、openapiで生成されるppubspec.yamlのsdkバージョンが

environment:
  sdk: '>=3.5.0 <4.0.0'

となっていて、3.5が下限になっているため、新しい構文が使用不可となってしまうことに起因します。

nullawareについては以下の記事でも見てください。

解決

まず、このコマンドを打ちます。

openapi-generator-cli author template -g dart-dio -o ./templates

これはopenapiの生成ファイルのテンプレートを集めたものです。

ここのpubspec.mustache以外は消します。


するとこうなると思います。
中身を見てみると、

name: {{pubName}}
version: {{pubVersion}}
description: {{pubDescription}}
homepage: {{pubHomepage}}
{{#pubRepository}}
repository: {{.}}
{{/pubRepository}}
{{#pubPublishTo}}
publish_to: {{.}}
{{/pubPublishTo}}
 
 
environment:
  sdk: '>={{^useJsonSerializable}}2.18.0{{/useJsonSerializable}}{{#useJsonSerializable}}3.5.0{{/useJsonSerializable}} <4.0.0'
 
dependencies:
  dio: '^5.7.0'
{{#useBuiltValue}}
  one_of: '>=1.5.0 <2.0.0'
  one_of_serializer: '>=1.5.0 <2.0.0'
  built_value: '>=8.4.0 <9.0.0'
  built_collection: '>=5.1.1 <6.0.0'
{{/useBuiltValue}}
{{#useEquatable}}
  equatable: '^2.0.7'
{{/useEquatable}}
{{#useJsonSerializable}}
  {{^skipCopyWith}}
  copy_with_extension: '^7.1.0'
  {{/skipCopyWith}}
  json_annotation: '^4.9.0'
{{/useJsonSerializable}}
{{#useDateLibTimeMachine}}
  time_machine: ^0.9.17
{{/useDateLibTimeMachine}}
 
dev_dependencies:
{{#useBuiltValue}}
  built_value_generator: '>=8.4.0 <9.0.0'
  build_runner: any
{{/useBuiltValue}}
{{#useJsonSerializable}}
  build_runner: any
  {{^skipCopyWith}}
  copy_with_extension_gen: ^7.1.0
  {{/skipCopyWith}}
  json_serializable: '^6.9.3'
{{/useJsonSerializable}}
  test: '^1.16.0'
 

となっているので、

environment:
  sdk: '>={{^useJsonSerializable}}2.18.0{{/useJsonSerializable}}{{#useJsonSerializable}}3.5.0{{/useJsonSerializable}} <4.0.0'

の部分を

environment:
  sdk: '>={{^useJsonSerializable}}2.18.0{{/useJsonSerializable}}{{#useJsonSerializable}}3.11.0{{/useJsonSerializable}} <4.0.0'

とでも書き換えておきます。
そして保存。

openapiの生成コマンドの引数に改変したテンプレートを使用するように追記します。
-t ./templates
自分が使っているのはこれ

openapi-generator-cli generate -i api-schema/openapi.json -g dart-dio -o openapi -c openapi-config.yaml -t ./templates

一旦生成されたディレクトリを消してから再生成すると、build_runnerのエラーが消えるかと思います。

余談

自分はtask.yamlでコマンドを管理していて、task gen-apiの一つですべて実行するようにしています。

  gen-api:
    cmds:
      - openapi-generator-cli validate -i api-schema/openapi.json
      - openapi-generator-cli generate -i api-schema/openapi.json -g dart-dio -o openapi -c openapi-config.yaml -t ./templates
      - task: gen-api-from-openapi-dir
 
  gen-api-from-openapi-dir:
    dir: ./openapi
    cmds: 
      - flutter pub run build_runner build --delete-conflicting-outputs

よかったら使ってみてください。