我正在尝试使用 openapi-generator-cli 和 Dart-Dio 生成器来生成 OpenAPI API 的客户端代码。但是,我在生成过程中遇到了错误。提供的 API JSON 只是整个 API 的一小部分,我们已经使用 Angular 的 typescript-Angular 生成器成功生成了 API 客户端代码,没有任何问题。
由于此 API 客户端代码生成是作为包创建的,因此我认为除了使用 shell 脚本之外没有其他步骤可以重现它。您可能需要安装 openapi-generator-cli 和 flutter。
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 pub add build_runner”。
build_runner 需要在 dev_dependency 中注册。