从 OpenAPI JSON 生成 dart 客户端代码时出错

问题描述 投票:0回答:1

我正在尝试使用 openapi-generator-cli 和 Dart-Dio 生成器来生成 OpenAPI API 的客户端代码。但是,我在生成过程中遇到了错误。提供的 API JSON 只是整个 API 的一小部分,我们已经使用 Angular 的 typescript-Angular 生成器成功生成了 API 客户端代码,没有任何问题。

由于此 API 客户端代码生成是作为包创建的,因此我认为除了使用 shell 脚本之外没有其他步骤可以重现它。您可能需要安装 openapi-generator-cliflutter

OpenAPI版本和

openapitools.json
内容

openapi-generator-cli
版本应该是
6.0.0

{
  "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
  "spaces": 2,
  "generator-cli": {
    "version": "6.6.0"
  }
}

我用作输入的 JSON 文件(只是实际 API 的一个片段):

{
    "openapi": "3.0.2",
    "info": {
        "title": "Some API",
        "description": "Some API description",
        "version": "1.0.0"
    },
    "paths": {
        "/token/{organization_id}": {
            "get": {
                "tags": ["Authentication"],
                "summary": "Get Token For Organization",
                "description": "Get a token for a specific organization",
                "operationId": "get_token_for_organization_token__organization_id__get",
                "parameters": [
                    {
                        "required": true,
                        "schema": { "title": "Organization Id", "type": "string" },
                        "name": "organization_id",
                        "in": "path"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Successful Response",
                        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TokenInfo" } } }
                    },
                    "422": {
                        "description": "Validation Error",
                        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }
                    }
                },
                "security": [{ "OAuth2PasswordBearer": [] }]
            }
        },
        "/": {
            "get": {
                "summary": "Read Root",
                "operationId": "read_root__get",
                "responses": {
                    "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "ValidationError": {
                "title": "ValidationError",
                "required": ["loc", "msg", "type"],
                "type": "object",
                "properties": {
                    "loc": {
                        "title": "Location",
                        "type": "array",
                        "items": { "anyOf": [{ "type": "string" }, { "type": "integer" }] }
                    },
                    "msg": { "title": "Message", "type": "string" },
                    "type": { "title": "Error Type", "type": "string" }
                }
            },
            "HTTPValidationError": {
                "title": "HTTPValidationError",
                "type": "object",
                "properties": {
                    "detail": { "title": "Detail", "type": "array", "items": { "$ref": "#/components/schemas/ValidationError" } }
                }
            },
            "TokenInfo": {
                "title": "TokenInfo",
                "required": ["access_token"],
                "type": "object",
                "properties": {
                    "access_token": { "title": "Access Token", "type": "string" },
                    "token_type": { "allOf": [{ "$ref": "#/components/schemas/TokenTypes" }], "default": "bearer" }
                }
            },
            "TokenTypes": { "title": "TokenTypes", "enum": ["bearer"], "type": "string", "description": "An enumeration." }
        },
        "securitySchemes": {
            "OAuth2PasswordBearer": {
                "type": "oauth2",
                "flows": {
                    "password": {
                        "scopes": { "system": "system", "user": "user", "mobile": "mobile" },
                        "tokenUrl": "/auth/token"
                    }
                }
            }
        }
    }
}

我用于生成代码的脚本:

cd packages/apis

echo "Removing old files..."
rm -rf client_api

echo "Generating client api..."
openapi-generator-cli generate -i "../../scripts/api_snippet.json" -g dart-dio -o client_api

cd client_api

echo "Adding dependencies..."
flutter pub add build_runner
flutter pub add analyzer:0.39.14

echo "Cleaning up..."
flutter clean
flutter pub cache repair
flutter pub run build_runner clean

echo "Getting dependencies..."
flutter pub get

echo "Running build_runner..."
dart pub run build_runner build --delete-conflicting-outputs

我也尝试过使用

dart
openapi 生成器,但这也没有成功。我想我想把它和
dart-dio
一起使用,因为这似乎是 flutter 社区最喜欢的选项。

运行命令后的日志:

Removing old files...
Generating client api...
[main] INFO  o.o.codegen.DefaultGenerator - Generating with dryRun=false
[main] INFO  o.o.c.ignore.CodegenIgnoreProcessor - Output directory (/path/to/cloned/repo/client_api) does not exist, or is inaccessible. No file (.openapi-generator-ignore) will be evaluated.
[main] INFO  o.o.codegen.DefaultGenerator - Generator 'dart-dio' is considered stable.
[main] INFO  o.o.c.languages.AbstractDartCodegen - Environment variable DART_POST_PROCESS_FILE not defined so the Dart code may not be properly formatted. To define it, try `export DART_POST_PROCESS_FILE="/usr/local/bin/dartfmt -w"` (Linux/Mac)
[main] INFO  o.o.c.languages.AbstractDartCodegen - NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).
[main] INFO  o.o.c.languages.DartDioClientCodegen - Environment variable DART_POST_PROCESS_FILE not defined so the Dart code may not be properly formatted. To define it, try `export DART_POST_PROCESS_FILE="/usr/local/bin/dartfmt -w"` (Linux/Mac)
[main] INFO  o.o.c.languages.DartDioClientCodegen - NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).
[main] INFO  o.o.codegen.InlineModelResolver - Inline schema created as Location_inner. To have complete control of the model name, set the `title` field or use the inlineSchemaNameMapping option (--inline-schema-name-mappings in CLI).
[main] INFO  o.o.codegen.utils.URLPathUtils - 'host' (OAS 2.0) or 'servers' (OAS 3.0) not defined in the spec. Default to [http://localhost] for server URL [http://localhost/]
[main] INFO  o.o.codegen.utils.URLPathUtils - 'host' (OAS 2.0) or 'servers' (OAS 3.0) not defined in the spec. Default to [http://localhost] for server URL [http://localhost/]
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/model/http_validation_error.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/test/http_validation_error_test.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/doc/HTTPValidationError.md
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/model/location_inner.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/test/location_inner_test.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/doc/LocationInner.md
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/model/token_info.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/test/token_info_test.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/doc/TokenInfo.md
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/model/token_types.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/test/token_types_test.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/doc/TokenTypes.md
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/model/validation_error.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/test/validation_error_test.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/doc/ValidationError.md
[main] INFO  o.o.codegen.utils.URLPathUtils - 'host' (OAS 2.0) or 'servers' (OAS 3.0) not defined in the spec. Default to [http://localhost] for server URL [http://localhost/]
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/api/authentication_api.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/test/authentication_api_test.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/doc/AuthenticationApi.md
[main] INFO  o.o.codegen.utils.URLPathUtils - 'host' (OAS 2.0) or 'servers' (OAS 3.0) not defined in the spec. Default to [http://localhost] for server URL [http://localhost/]
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/api/default_api.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/test/default_api_test.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/doc/DefaultApi.md
[main] INFO  o.o.codegen.utils.URLPathUtils - 'host' (OAS 2.0) or 'servers' (OAS 3.0) not defined in the spec. Default to [http://localhost] for server URL [http://localhost/]
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/pubspec.yaml
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/analysis_options.yaml
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/.gitignore
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/README.md
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/openapi.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/api.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/auth/api_key_auth.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/auth/basic_auth.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/auth/bearer_auth.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/auth/oauth.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/auth/auth.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/serializers.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/api_util.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/model/date.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/lib/src/date_serializer.dart
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/.openapi-generator-ignore
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/.openapi-generator/VERSION
[main] INFO  o.o.codegen.TemplateManager - writing file /path/to/cloned/repo/client_api/.openapi-generator/FILES
################################################################################
# Thanks for using OpenAPI Generator.                                          #
# Please consider donation to help us maintain this project 🙏                 #
# https://opencollective.com/openapi_generator/donate                          #
################################################################################
Adding dependencies...
"build_runner" was found in dev_dependencies. Removing "build_runner" and adding it to dependencies instead.
Resolving dependencies... 
+ _fe_analyzer_shared 61.0.0 (62.0.0 available)
+ analyzer 5.13.0 (6.0.0 available)
+ args 2.4.2
+ async 2.11.0
+ boolean_selector 2.1.1
+ build 2.4.1
+ build_config 1.1.1
+ build_daemon 4.0.0
+ build_resolvers 2.2.1
+ build_runner 2.4.6
+ build_runner_core 7.2.10
+ built_collection 5.1.1
+ built_value 8.6.1
+ built_value_generator 8.6.1
+ checked_yaml 2.0.3
+ code_builder 4.5.0
+ collection 1.18.0
+ convert 3.1.1
+ coverage 1.6.3
+ crypto 3.0.3
+ dart_style 2.3.2
+ dio 5.3.1
+ file 7.0.0
+ fixnum 1.1.0
+ frontend_server_client 3.2.0
+ glob 2.1.2
+ graphs 2.3.1
+ http_multi_server 3.2.1
+ http_parser 4.0.2
+ io 1.0.4
+ js 0.6.7
+ json_annotation 4.8.1
+ logging 1.2.0
+ matcher 0.12.16
+ meta 1.9.1
+ mime 1.0.4
+ node_preamble 2.0.2
+ one_of 1.5.0
+ one_of_serializer 1.5.0
+ package_config 2.1.0
+ path 1.8.3
+ pool 1.5.1
+ pub_semver 2.1.4
+ pubspec_parse 1.2.3
+ quiver 3.2.1
+ shelf 1.4.1
+ shelf_packages_handler 3.0.2
+ shelf_static 1.1.2
+ shelf_web_socket 1.0.4
+ source_gen 1.4.0
+ source_map_stack_trace 2.1.1
+ source_maps 0.10.12
+ source_span 1.10.0
+ stack_trace 1.11.1
+ stream_channel 2.1.2
+ stream_transform 2.1.0
+ string_scanner 1.2.0
+ term_glyph 1.2.1
+ test 1.24.5
+ test_api 0.6.1
+ test_core 0.5.5
+ timing 1.0.1
+ typed_data 1.3.2
+ vm_service 11.8.0
+ watcher 1.1.0
+ web_socket_channel 2.4.0
+ webkit_inspection_protocol 1.2.0
+ yaml 3.1.2
Changed 68 dependencies!
The current Dart SDK version is 3.0.6.

Because openapi depends on analyzer >=0.9.1 <0.42.0-nullsafety.0
  which doesn't support null safety, version solving failed.

The lower bound of "sdk: '>=0.8.8 <3.0.0'" must be 2.12.0 or higher to enable null safety.
For details, see https://dart.dev/null-safety
Cleaning up...
Deleting .dart_tool...                                                    1ms
Reinstalled 147 packages.
Reactivating melos 3.1.1...
Building package executables... 
Built melos:melos.
Installed executable melos.
Warning: Pub installs executables into $HOME/.pub-cache/bin, which is not on your path.
You can fix that by adding this to your shell's config file (.bashrc, .bash_profile, etc.):

  export PATH="$PATH":"$HOME/.pub-cache/bin"

Reactivated 1 package.
Deprecated. Use `dart run` instead.
Resolving dependencies... 
Cannot open file, path = '.dart_tool/package_config.json' (OS Error: No such file or directory, errno = 2)
Got dependencies.
Getting dependencies...
Resolving dependencies... 
  _fe_analyzer_shared 61.0.0 (62.0.0 available)
  analyzer 5.13.0 (6.0.0 available)
Got dependencies!
Running build_runner...
Deprecated. Use `dart run` instead.
Building package executable... (3.6s)
Built build_runner:build_runner.
[INFO] Generating build script completed, took 145ms
[INFO] Precompiling build script... completed, took 3.4s
[INFO] Building new asset graph completed, took 367ms
[INFO] Checking for unexpected pre-existing outputs. completed, took 0ms
[INFO] Generating SDK summary completed, took 2.3s
[SEVERE] built_value_generator:built_value on lib/src/model/token_info.dart:

This builder requires Dart inputs without syntax errors.
However, package:openapi/src/model/token_info.dart (or an existing part) contains the following errors.
token_info.dart:32:27: Expected an identifier.

Try fixing the errors and re-running the build.

[INFO] Running build completed, took 3.7s
[INFO] Caching finalized dependency graph completed, took 19ms
[SEVERE] Failed after 3.7s

生成的

pubspec.yaml
文件内容:

name: openapi
version: 1.0.0
description: OpenAPI API client
homepage: homepage

environment:
  sdk: '>=2.15.0 <3.0.0'

dependencies:
  dio: '^5.0.0'
  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'
  build_runner: ^2.4.6

dev_dependencies:
  built_value_generator: '>=8.4.0 <9.0.0'
  test: ^1.16.0

预期结果: 我希望 Dart 客户端代码能够成功生成,没有任何语法错误。

实际结果: 生成过程失败,并出现 token_info.dart 文件中的语法错误。

token_info.dart
文件的内容:

//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//

// ignore_for_file: unused_element
import 'package:openapi/src/model/token_types.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';

part 'token_info.g.dart';

/// TokenInfo
///
/// Properties:
/// * [accessToken] 
/// * [tokenType] 
@BuiltValue()
abstract class TokenInfo implements Built<TokenInfo, TokenInfoBuilder> {
  @BuiltValueField(wireName: r'access_token')
  String get accessToken;

  @BuiltValueField(wireName: r'token_type')
  TokenTypes? get tokenType;
  // enum tokenTypeEnum {  bearer,  };

  TokenInfo._();

  factory TokenInfo([void updates(TokenInfoBuilder b)]) = _$TokenInfo;

  @BuiltValueHook(initializeBuilder: true)
  static void _defaults(TokenInfoBuilder b) => b
      ..tokenType = const ._(TokenTypes.bearer);

  @BuiltValueSerializer(custom: true)
  static Serializer<TokenInfo> get serializer => _$TokenInfoSerializer();
}

class _$TokenInfoSerializer implements PrimitiveSerializer<TokenInfo> {
  @override
  final Iterable<Type> types = const [TokenInfo, _$TokenInfo];

  @override
  final String wireName = r'TokenInfo';

  Iterable<Object?> _serializeProperties(
    Serializers serializers,
    TokenInfo object, {
    FullType specifiedType = FullType.unspecified,
  }) sync* {
    yield r'access_token';
    yield serializers.serialize(
      object.accessToken,
      specifiedType: const FullType(String),
    );
    if (object.tokenType != null) {
      yield r'token_type';
      yield serializers.serialize(
        object.tokenType,
        specifiedType: const FullType(TokenTypes),
      );
    }
  }

  @override
  Object serialize(
    Serializers serializers,
    TokenInfo object, {
    FullType specifiedType = FullType.unspecified,
  }) {
    return _serializeProperties(serializers, object, specifiedType: specifiedType).toList();
  }

  void _deserializeProperties(
    Serializers serializers,
    Object serialized, {
    FullType specifiedType = FullType.unspecified,
    required List<Object?> serializedList,
    required TokenInfoBuilder result,
    required List<Object?> unhandled,
  }) {
    for (var i = 0; i < serializedList.length; i += 2) {
      final key = serializedList[i] as String;
      final value = serializedList[i + 1];
      switch (key) {
        case r'access_token':
          final valueDes = serializers.deserialize(
            value,
            specifiedType: const FullType(String),
          ) as String;
          result.accessToken = valueDes;
          break;
        case r'token_type':
          final valueDes = serializers.deserialize(
            value,
            specifiedType: const FullType(TokenTypes),
          ) as TokenTypes;
          result.tokenType = valueDes;
          break;
        default:
          unhandled.add(key);
          unhandled.add(value);
          break;
      }
    }
  }

  @override
  TokenInfo deserialize(
    Serializers serializers,
    Object serialized, {
    FullType specifiedType = FullType.unspecified,
  }) {
    final result = TokenInfoBuilder();
    final serializedList = (serialized as Iterable<Object?>).toList();
    final unhandled = <Object?>[];
    _deserializeProperties(
      serializers,
      serialized,
      specifiedType: specifiedType,
      serializedList: serializedList,
      unhandled: unhandled,
      result: result,
    );
    return result.build();
  }
}

将鼠标悬停在

part 'token_info.g.dart
上时出错:

Target of URI hasn't been generated: 'package:openapi/src/model/token_info.g.dart'.
Try running the generator that will generate the file referenced by the URI. dart([uri_has_not_been_generated](https://dart.dev/diagnostics/uri_has_not_been_generated))

TokenInfoBuilder
到处都带有红色下划线,并将鼠标悬停在其上时显示以下错误:

Undefined class 'TokenInfoBuilder'.
Try changing the name to the name of an existing class, or creating a class with the name 'TokenInfoBuilder'. dart([undefined_class](https://dart.dev/diagnostics/undefined_class))

作为免责声明,我必须承认,对于 Flutter,我更像是一个初学者。如果您对问题和提供的日志有任何疑问或建议,请随时询问。我将尽力解决任何疑问并努力寻找解决方案。感谢您花时间查看我的问题并提供任何帮助!

flutter dart openapi openapi-generator build-runner
1个回答
0
投票

尝试删除脚本中的这一行“flutter pub add build_runner”。

build_runner 需要在 dev_dependency 中注册。

© www.soinside.com 2019 - 2024. All rights reserved.