diff --git a/packages/dynamite/dynamite/lib/src/builder/client.dart b/packages/dynamite/dynamite/lib/src/builder/client.dart index e5490b4d..51e5bf5e 100644 --- a/packages/dynamite/dynamite/lib/src/builder/client.dart +++ b/packages/dynamite/dynamite/lib/src/builder/client.dart @@ -183,19 +183,19 @@ Iterable buildTags( for (final operationEntry in pathEntry.value.operations.entries) { final httpMethod = operationEntry.key.name; final operation = operationEntry.value; - final operationId = operation.operationId ?? toDartName('$httpMethod-${pathEntry.key}'); + final operationName = operation.operationId ?? toDartName('$httpMethod-${pathEntry.key}'); final parameters = [ ...?pathEntry.value.parameters, ...?operation.parameters, ]..sort(sortRequiredParameters); - final name = toDartName(filterMethodName(operationId, tag ?? '')); + final name = toDartName(filterMethodName(operationName, tag ?? '')); var responses = >{}; if (operation.responses != null) { for (final responseEntry in operation.responses!.entries) { final statusCode = int.tryParse(responseEntry.key); if (statusCode == null) { - print('Default responses are not supported right now. Skipping it for $operationId'); + print('Default responses are not supported right now. Skipping it for $operationName'); continue; } final response = responseEntry.value; @@ -205,7 +205,7 @@ Iterable buildTags( } if (responses.length > 1) { - print('$operationId uses more than one response schema but we only generate the first one'); + print('$operationName uses more than one response schema but we only generate the first one'); responses = Map.fromEntries([responses.entries.first]); } } @@ -251,7 +251,7 @@ Iterable buildTags( spec, state, toDartName( - '$operationId-${parameter.name}', + '$operationName-${parameter.name}', uppercaseFirstCharacter: true, ), parameter.schema!, @@ -277,20 +277,26 @@ Iterable buildTags( buildPatternCheck(result, parameter).forEach(code.writeln); buildParameterSerialization(result, parameter).forEach(code.writeln); } - resolveMimeTypeEncode(operation, spec, state, operationId, operationParameters).forEach(code.writeln); + resolveMimeTypeEncode(operation, spec, state, operationName, operationParameters).forEach(code.writeln); for (final responseEntry in responses.entries) { final response = responseEntry.key; final statusCodes = responseEntry.value; TypeResult? headersType; + if (response.headers != null) { - final identifier = - '${tag != null ? toDartName(tag, uppercaseFirstCharacter: true) : null}${toDartName(operationId, uppercaseFirstCharacter: true)}Headers'; + final identifierBuilder = StringBuffer(); + if (tag != null) { + identifierBuilder.write(toDartName(tag, uppercaseFirstCharacter: true)); + } + identifierBuilder + ..write(toDartName(operationName, uppercaseFirstCharacter: true)) + ..write('Headers'); headersType = resolveObject( spec, state, - identifier, + identifierBuilder.toString(), openapi.Schema( (final b) => b ..properties.replace( @@ -306,14 +312,20 @@ Iterable buildTags( ); } + final identifierBuilder = StringBuffer() + ..write(operationName) + ..write('-response'); + if (responses.entries.length > 1) { + identifierBuilder + ..write('-') + ..write(responses.entries.toList().indexOf(responseEntry)); + } + final dataType = resolveMimeTypeDecode( response, spec, state, - toDartName( - '$operationId-response${responses.entries.length > 1 ? '-${responses.entries.toList().indexOf(responseEntry)}' : ''}', - uppercaseFirstCharacter: true, - ), + toDartName(identifierBuilder.toString(), uppercaseFirstCharacter: true), ); var path = pathEntry.key; diff --git a/packages/dynamite/dynamite/lib/src/builder/generate_schemas.dart b/packages/dynamite/dynamite/lib/src/builder/generate_schemas.dart new file mode 100644 index 00000000..17a6c46f --- /dev/null +++ b/packages/dynamite/dynamite/lib/src/builder/generate_schemas.dart @@ -0,0 +1,25 @@ +import 'package:code_builder/code_builder.dart'; +import 'package:dynamite/src/builder/resolve_type.dart'; +import 'package:dynamite/src/builder/state.dart'; +import 'package:dynamite/src/helpers/dart_helpers.dart'; +import 'package:dynamite/src/models/openapi.dart' as openapi; + +Iterable generateSchemas( + final openapi.OpenAPI spec, + final State state, +) sync* { + if (spec.components?.schemas != null) { + for (final schema in spec.components!.schemas!.entries) { + final identifier = toDartName(schema.key, uppercaseFirstCharacter: true); + + resolveType( + spec, + state, + identifier, + schema.value, + ); + } + } + + yield* state.output; +} diff --git a/packages/dynamite/dynamite/lib/src/builder/imports.dart b/packages/dynamite/dynamite/lib/src/builder/imports.dart index 9e4f5e51..7b7cddc2 100644 --- a/packages/dynamite/dynamite/lib/src/builder/imports.dart +++ b/packages/dynamite/dynamite/lib/src/builder/imports.dart @@ -24,7 +24,7 @@ List generateImports(final AssetId outputId, final State state) => [ Directive.import('package:meta/meta.dart'), Directive.import('package:universal_io/io.dart'), const Code(''), - if (state.resolvedTypes.isNotEmpty) ...[ + if (state.hasResolvedBuiltTypes) ...[ Directive.part(p.basename(outputId.changeExtension('.g.dart').path)), const Code(''), ], diff --git a/packages/dynamite/dynamite/lib/src/builder/state.dart b/packages/dynamite/dynamite/lib/src/builder/state.dart index 5154683b..13ef0eb8 100644 --- a/packages/dynamite/dynamite/lib/src/builder/state.dart +++ b/packages/dynamite/dynamite/lib/src/builder/state.dart @@ -7,4 +7,11 @@ class State { final output = []; final resolvedTypes = {}; final resolvedInterfaces = {}; + + /// Wether the state contains resolved types that need the built_value generator. + bool get hasResolvedBuiltTypes => resolvedTypes + .where( + (final type) => type is TypeResultEnum || (type is TypeResultObject && type.className != 'ContentString'), + ) + .isNotEmpty; } diff --git a/packages/dynamite/dynamite/lib/src/openapi_builder.dart b/packages/dynamite/dynamite/lib/src/openapi_builder.dart index 4a777760..0c1a67c6 100644 --- a/packages/dynamite/dynamite/lib/src/openapi_builder.dart +++ b/packages/dynamite/dynamite/lib/src/openapi_builder.dart @@ -6,13 +6,11 @@ import 'package:checked_yaml/checked_yaml.dart'; import 'package:code_builder/code_builder.dart'; import 'package:dart_style/dart_style.dart'; import 'package:dynamite/src/builder/client.dart'; +import 'package:dynamite/src/builder/generate_schemas.dart'; import 'package:dynamite/src/builder/imports.dart'; -import 'package:dynamite/src/builder/resolve_type.dart'; import 'package:dynamite/src/builder/serializer.dart'; import 'package:dynamite/src/builder/state.dart'; -import 'package:dynamite/src/helpers/dart_helpers.dart'; import 'package:dynamite/src/models/openapi.dart' as openapi; -import 'package:dynamite/src/models/type_result.dart'; import 'package:version/version.dart'; class OpenAPIBuilder implements Builder { @@ -58,50 +56,13 @@ class OpenAPIBuilder implements Builder { final state = State(); - final output = ListBuilder(); - - if (spec.components?.schemas != null) { - for (final schema in spec.components!.schemas!.entries) { - final identifier = toDartName(schema.key, uppercaseFirstCharacter: true); - if (schema.value.type == null && schema.value.ref == null && schema.value.ofs == null) { - output.add( - TypeDef( - (final b) => b - ..name = identifier - ..definition = refer('dynamic'), - ), - ); - } else { - final result = resolveType( - spec, - state, - identifier, - schema.value, - ); - if (result is TypeResultBase) { - output.add( - TypeDef( - (final b) => b - ..name = identifier - ..definition = refer(result.name), - ), - ); - } - } - } - } - // Imports need to be generated after everything else so we know if we need the local part directive, // but they need to be added to the beginning of the output. - final clients = generateClients(spec, state); - final serializer = buildSerializer(state); - final imports = generateImports(outputId, state); - - output - ..addAll(imports) - ..addAll(clients) - ..addAll(state.output) - ..addAll(serializer); + final output = ListBuilder() + ..addAll(generateClients(spec, state)) + ..addAll(generateSchemas(spec, state)) + ..addAll(buildSerializer(state)) + ..insertAll(0, generateImports(outputId, state)); final patterns = [ RegExp( diff --git a/packages/dynamite/dynamite_end_to_end_test/lib/headers.openapi.dart b/packages/dynamite/dynamite_end_to_end_test/lib/headers.openapi.dart new file mode 100644 index 00000000..366d7991 --- /dev/null +++ b/packages/dynamite/dynamite_end_to_end_test/lib/headers.openapi.dart @@ -0,0 +1,393 @@ +// ignore_for_file: camel_case_types +// ignore_for_file: discarded_futures +// ignore_for_file: public_member_api_docs +// ignore_for_file: unreachable_switch_case +import 'dart:typed_data'; + +import 'package:built_value/built_value.dart'; +import 'package:built_value/serializer.dart'; +import 'package:built_value/standard_json_plugin.dart'; +import 'package:dynamite_runtime/built_value.dart'; +import 'package:dynamite_runtime/http_client.dart'; +import 'package:meta/meta.dart'; +import 'package:universal_io/io.dart'; + +part 'headers.openapi.g.dart'; + +class Client extends DynamiteClient { + Client( + super.baseURL, { + super.baseHeaders, + super.userAgent, + super.httpClient, + super.cookieJar, + }); + + Client.fromClient(final DynamiteClient client) + : super( + client.baseURL, + baseHeaders: client.baseHeaders, + httpClient: client.httpClient, + cookieJar: client.cookieJar, + authentications: client.authentications, + ); + + /// Returns a [Future] containing a [DynamiteResponse] with the status code, deserialized body and headers. + /// Throws a [DynamiteApiException] if the API call does not return an expected status code. + /// + /// Status codes: + /// * 200: Returns a header only + /// + /// See: + /// * [$getRaw] for an experimental operation that returns a [DynamiteRawResponse] that can be serialized. + Future> $get() async { + final rawResponse = $getRaw(); + + return rawResponse.future; + } + + /// This method and the response it returns is experimental. The API might change without a major version bump. + /// + /// Returns a [Future] containing a [DynamiteRawResponse] with the raw [HttpClientResponse] and serialization helpers. + /// Throws a [DynamiteApiException] if the API call does not return an expected status code. + /// + /// Status codes: + /// * 200: Returns a header only + /// + /// See: + /// * [$get] for an operation that returns a [DynamiteResponse] with a stable API. + @experimental + DynamiteRawResponse $getRaw() { + final queryParameters = {}; + final headers = {}; + Uint8List? body; + + const path = '/'; + final uri = Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null); + + return DynamiteRawResponse( + response: executeRequest( + 'get', + uri, + headers, + body, + const {200}, + ), + bodyType: null, + headersType: const FullType(GetHeaders), + serializers: _jsonSerializers, + ); + } + + /// Returns a [Future] containing a [DynamiteResponse] with the status code, deserialized body and headers. + /// Throws a [DynamiteApiException] if the API call does not return an expected status code. + /// + /// Status codes: + /// * 200: Returns a header only + /// + /// See: + /// * [withContentOperationIdRaw] for an experimental operation that returns a [DynamiteRawResponse] that can be serialized. + Future> withContentOperationId() async { + final rawResponse = withContentOperationIdRaw(); + + return rawResponse.future; + } + + /// This method and the response it returns is experimental. The API might change without a major version bump. + /// + /// Returns a [Future] containing a [DynamiteRawResponse] with the raw [HttpClientResponse] and serialization helpers. + /// Throws a [DynamiteApiException] if the API call does not return an expected status code. + /// + /// Status codes: + /// * 200: Returns a header only + /// + /// See: + /// * [withContentOperationId] for an operation that returns a [DynamiteResponse] with a stable API. + @experimental + DynamiteRawResponse withContentOperationIdRaw() { + final queryParameters = {}; + final headers = {}; + Uint8List? body; + + const path = '/with_content/operation_id'; + final uri = Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null); + + return DynamiteRawResponse( + response: executeRequest( + 'get', + uri, + headers, + body, + const {200}, + ), + bodyType: null, + headersType: const FullType(WithContentOperationIdHeaders), + serializers: _jsonSerializers, + ); + } + + /// Returns a [Future] containing a [DynamiteResponse] with the status code, deserialized body and headers. + /// Throws a [DynamiteApiException] if the API call does not return an expected status code. + /// + /// Status codes: + /// * 200: Returns both a header and a body. + /// + /// See: + /// * [getWithContentRaw] for an experimental operation that returns a [DynamiteRawResponse] that can be serialized. + Future> getWithContent() async { + final rawResponse = getWithContentRaw(); + + return rawResponse.future; + } + + /// This method and the response it returns is experimental. The API might change without a major version bump. + /// + /// Returns a [Future] containing a [DynamiteRawResponse] with the raw [HttpClientResponse] and serialization helpers. + /// Throws a [DynamiteApiException] if the API call does not return an expected status code. + /// + /// Status codes: + /// * 200: Returns both a header and a body. + /// + /// See: + /// * [getWithContent] for an operation that returns a [DynamiteResponse] with a stable API. + @experimental + DynamiteRawResponse getWithContentRaw() { + final queryParameters = {}; + final headers = { + 'Accept': 'application/octet-stream', + }; + Uint8List? body; + + const path = '/with_content'; + final uri = Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null); + + return DynamiteRawResponse( + response: executeRequest( + 'get', + uri, + headers, + body, + const {200}, + ), + bodyType: const FullType(Uint8List), + headersType: const FullType(GetWithContentHeaders), + serializers: _jsonSerializers, + ); + } +} + +@BuiltValue(instantiable: false) +abstract interface class GetHeadersInterface { + @BuiltValueField(wireName: 'my-header') + String? get myHeader; +} + +abstract class GetHeaders implements GetHeadersInterface, Built { + factory GetHeaders([final void Function(GetHeadersBuilder)? b]) = _$GetHeaders; + + // coverage:ignore-start + const GetHeaders._(); + // coverage:ignore-end + + // coverage:ignore-start + factory GetHeaders.fromJson(final Map json) => _jsonSerializers.deserializeWith(serializer, json)!; + // coverage:ignore-end + + // coverage:ignore-start + Map toJson() => _jsonSerializers.serializeWith(serializer, this)! as Map; + // coverage:ignore-end + + @BuiltValueSerializer(custom: true) + static Serializer get serializer => _$GetHeadersSerializer(); +} + +class _$GetHeadersSerializer implements StructuredSerializer { + @override + final Iterable types = const [GetHeaders, _$GetHeaders]; + + @override + final String wireName = 'GetHeaders'; + + @override + Iterable serialize( + final Serializers serializers, + final GetHeaders object, { + final FullType specifiedType = FullType.unspecified, + }) { + throw UnimplementedError(); + } + + @override + GetHeaders deserialize( + final Serializers serializers, + final Iterable serialized, { + final FullType specifiedType = FullType.unspecified, + }) { + final result = GetHeadersBuilder(); + + final iterator = serialized.iterator; + while (iterator.moveNext()) { + final key = iterator.current! as String; + iterator.moveNext(); + final value = iterator.current! as String; + switch (key) { + case 'my-header': + result.myHeader = value; + } + } + + return result.build(); + } +} + +@BuiltValue(instantiable: false) +abstract interface class WithContentOperationIdHeadersInterface { + @BuiltValueField(wireName: 'my-header') + String? get myHeader; +} + +abstract class WithContentOperationIdHeaders + implements + WithContentOperationIdHeadersInterface, + Built { + factory WithContentOperationIdHeaders([final void Function(WithContentOperationIdHeadersBuilder)? b]) = + _$WithContentOperationIdHeaders; + + // coverage:ignore-start + const WithContentOperationIdHeaders._(); + // coverage:ignore-end + + // coverage:ignore-start + factory WithContentOperationIdHeaders.fromJson(final Map json) => + _jsonSerializers.deserializeWith(serializer, json)!; + // coverage:ignore-end + + // coverage:ignore-start + Map toJson() => _jsonSerializers.serializeWith(serializer, this)! as Map; + // coverage:ignore-end + + @BuiltValueSerializer(custom: true) + static Serializer get serializer => _$WithContentOperationIdHeadersSerializer(); +} + +class _$WithContentOperationIdHeadersSerializer implements StructuredSerializer { + @override + final Iterable types = const [WithContentOperationIdHeaders, _$WithContentOperationIdHeaders]; + + @override + final String wireName = 'WithContentOperationIdHeaders'; + + @override + Iterable serialize( + final Serializers serializers, + final WithContentOperationIdHeaders object, { + final FullType specifiedType = FullType.unspecified, + }) { + throw UnimplementedError(); + } + + @override + WithContentOperationIdHeaders deserialize( + final Serializers serializers, + final Iterable serialized, { + final FullType specifiedType = FullType.unspecified, + }) { + final result = WithContentOperationIdHeadersBuilder(); + + final iterator = serialized.iterator; + while (iterator.moveNext()) { + final key = iterator.current! as String; + iterator.moveNext(); + final value = iterator.current! as String; + switch (key) { + case 'my-header': + result.myHeader = value; + } + } + + return result.build(); + } +} + +@BuiltValue(instantiable: false) +abstract interface class GetWithContentHeadersInterface { + @BuiltValueField(wireName: 'my-header') + String? get myHeader; +} + +abstract class GetWithContentHeaders + implements GetWithContentHeadersInterface, Built { + factory GetWithContentHeaders([final void Function(GetWithContentHeadersBuilder)? b]) = _$GetWithContentHeaders; + + // coverage:ignore-start + const GetWithContentHeaders._(); + // coverage:ignore-end + + // coverage:ignore-start + factory GetWithContentHeaders.fromJson(final Map json) => + _jsonSerializers.deserializeWith(serializer, json)!; + // coverage:ignore-end + + // coverage:ignore-start + Map toJson() => _jsonSerializers.serializeWith(serializer, this)! as Map; + // coverage:ignore-end + + @BuiltValueSerializer(custom: true) + static Serializer get serializer => _$GetWithContentHeadersSerializer(); +} + +class _$GetWithContentHeadersSerializer implements StructuredSerializer { + @override + final Iterable types = const [GetWithContentHeaders, _$GetWithContentHeaders]; + + @override + final String wireName = 'GetWithContentHeaders'; + + @override + Iterable serialize( + final Serializers serializers, + final GetWithContentHeaders object, { + final FullType specifiedType = FullType.unspecified, + }) { + throw UnimplementedError(); + } + + @override + GetWithContentHeaders deserialize( + final Serializers serializers, + final Iterable serialized, { + final FullType specifiedType = FullType.unspecified, + }) { + final result = GetWithContentHeadersBuilder(); + + final iterator = serialized.iterator; + while (iterator.moveNext()) { + final key = iterator.current! as String; + iterator.moveNext(); + final value = iterator.current! as String; + switch (key) { + case 'my-header': + result.myHeader = value; + } + } + + return result.build(); + } +} + +// coverage:ignore-start +final Serializers _serializers = (Serializers().toBuilder() + ..addBuilderFactory(const FullType(GetHeaders), GetHeaders.new) + ..add(GetHeaders.serializer) + ..addBuilderFactory(const FullType(WithContentOperationIdHeaders), WithContentOperationIdHeaders.new) + ..add(WithContentOperationIdHeaders.serializer) + ..addBuilderFactory(const FullType(GetWithContentHeaders), GetWithContentHeaders.new) + ..add(GetWithContentHeaders.serializer)) + .build(); + +final Serializers _jsonSerializers = (_serializers.toBuilder() + ..add(DynamiteDoubleSerializer()) + ..addPlugin(StandardJsonPlugin()) + ..addPlugin(const ContentStringPlugin())) + .build(); +// coverage:ignore-end diff --git a/packages/dynamite/dynamite_end_to_end_test/lib/headers.openapi.g.dart b/packages/dynamite/dynamite_end_to_end_test/lib/headers.openapi.g.dart new file mode 100644 index 00000000..0466b3cc --- /dev/null +++ b/packages/dynamite/dynamite_end_to_end_test/lib/headers.openapi.g.dart @@ -0,0 +1,257 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'headers.openapi.dart'; + +// ************************************************************************** +// BuiltValueGenerator +// ************************************************************************** + +abstract mixin class GetHeadersInterfaceBuilder { + void replace(GetHeadersInterface other); + void update(void Function(GetHeadersInterfaceBuilder) updates); + String? get myHeader; + set myHeader(String? myHeader); +} + +class _$GetHeaders extends GetHeaders { + @override + final String? myHeader; + + factory _$GetHeaders([void Function(GetHeadersBuilder)? updates]) => (GetHeadersBuilder()..update(updates))._build(); + + _$GetHeaders._({this.myHeader}) : super._(); + + @override + GetHeaders rebuild(void Function(GetHeadersBuilder) updates) => (toBuilder()..update(updates)).build(); + + @override + GetHeadersBuilder toBuilder() => GetHeadersBuilder()..replace(this); + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is GetHeaders && myHeader == other.myHeader; + } + + @override + int get hashCode { + var _$hash = 0; + _$hash = $jc(_$hash, myHeader.hashCode); + _$hash = $jf(_$hash); + return _$hash; + } + + @override + String toString() { + return (newBuiltValueToStringHelper(r'GetHeaders')..add('myHeader', myHeader)).toString(); + } +} + +class GetHeadersBuilder implements Builder, GetHeadersInterfaceBuilder { + _$GetHeaders? _$v; + + String? _myHeader; + String? get myHeader => _$this._myHeader; + set myHeader(covariant String? myHeader) => _$this._myHeader = myHeader; + + GetHeadersBuilder(); + + GetHeadersBuilder get _$this { + final $v = _$v; + if ($v != null) { + _myHeader = $v.myHeader; + _$v = null; + } + return this; + } + + @override + void replace(covariant GetHeaders other) { + ArgumentError.checkNotNull(other, 'other'); + _$v = other as _$GetHeaders; + } + + @override + void update(void Function(GetHeadersBuilder)? updates) { + if (updates != null) updates(this); + } + + @override + GetHeaders build() => _build(); + + _$GetHeaders _build() { + final _$result = _$v ?? _$GetHeaders._(myHeader: myHeader); + replace(_$result); + return _$result; + } +} + +abstract mixin class WithContentOperationIdHeadersInterfaceBuilder { + void replace(WithContentOperationIdHeadersInterface other); + void update(void Function(WithContentOperationIdHeadersInterfaceBuilder) updates); + String? get myHeader; + set myHeader(String? myHeader); +} + +class _$WithContentOperationIdHeaders extends WithContentOperationIdHeaders { + @override + final String? myHeader; + + factory _$WithContentOperationIdHeaders([void Function(WithContentOperationIdHeadersBuilder)? updates]) => + (WithContentOperationIdHeadersBuilder()..update(updates))._build(); + + _$WithContentOperationIdHeaders._({this.myHeader}) : super._(); + + @override + WithContentOperationIdHeaders rebuild(void Function(WithContentOperationIdHeadersBuilder) updates) => + (toBuilder()..update(updates)).build(); + + @override + WithContentOperationIdHeadersBuilder toBuilder() => WithContentOperationIdHeadersBuilder()..replace(this); + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is WithContentOperationIdHeaders && myHeader == other.myHeader; + } + + @override + int get hashCode { + var _$hash = 0; + _$hash = $jc(_$hash, myHeader.hashCode); + _$hash = $jf(_$hash); + return _$hash; + } + + @override + String toString() { + return (newBuiltValueToStringHelper(r'WithContentOperationIdHeaders')..add('myHeader', myHeader)).toString(); + } +} + +class WithContentOperationIdHeadersBuilder + implements + Builder, + WithContentOperationIdHeadersInterfaceBuilder { + _$WithContentOperationIdHeaders? _$v; + + String? _myHeader; + String? get myHeader => _$this._myHeader; + set myHeader(covariant String? myHeader) => _$this._myHeader = myHeader; + + WithContentOperationIdHeadersBuilder(); + + WithContentOperationIdHeadersBuilder get _$this { + final $v = _$v; + if ($v != null) { + _myHeader = $v.myHeader; + _$v = null; + } + return this; + } + + @override + void replace(covariant WithContentOperationIdHeaders other) { + ArgumentError.checkNotNull(other, 'other'); + _$v = other as _$WithContentOperationIdHeaders; + } + + @override + void update(void Function(WithContentOperationIdHeadersBuilder)? updates) { + if (updates != null) updates(this); + } + + @override + WithContentOperationIdHeaders build() => _build(); + + _$WithContentOperationIdHeaders _build() { + final _$result = _$v ?? _$WithContentOperationIdHeaders._(myHeader: myHeader); + replace(_$result); + return _$result; + } +} + +abstract mixin class GetWithContentHeadersInterfaceBuilder { + void replace(GetWithContentHeadersInterface other); + void update(void Function(GetWithContentHeadersInterfaceBuilder) updates); + String? get myHeader; + set myHeader(String? myHeader); +} + +class _$GetWithContentHeaders extends GetWithContentHeaders { + @override + final String? myHeader; + + factory _$GetWithContentHeaders([void Function(GetWithContentHeadersBuilder)? updates]) => + (GetWithContentHeadersBuilder()..update(updates))._build(); + + _$GetWithContentHeaders._({this.myHeader}) : super._(); + + @override + GetWithContentHeaders rebuild(void Function(GetWithContentHeadersBuilder) updates) => + (toBuilder()..update(updates)).build(); + + @override + GetWithContentHeadersBuilder toBuilder() => GetWithContentHeadersBuilder()..replace(this); + + @override + bool operator ==(Object other) { + if (identical(other, this)) return true; + return other is GetWithContentHeaders && myHeader == other.myHeader; + } + + @override + int get hashCode { + var _$hash = 0; + _$hash = $jc(_$hash, myHeader.hashCode); + _$hash = $jf(_$hash); + return _$hash; + } + + @override + String toString() { + return (newBuiltValueToStringHelper(r'GetWithContentHeaders')..add('myHeader', myHeader)).toString(); + } +} + +class GetWithContentHeadersBuilder + implements Builder, GetWithContentHeadersInterfaceBuilder { + _$GetWithContentHeaders? _$v; + + String? _myHeader; + String? get myHeader => _$this._myHeader; + set myHeader(covariant String? myHeader) => _$this._myHeader = myHeader; + + GetWithContentHeadersBuilder(); + + GetWithContentHeadersBuilder get _$this { + final $v = _$v; + if ($v != null) { + _myHeader = $v.myHeader; + _$v = null; + } + return this; + } + + @override + void replace(covariant GetWithContentHeaders other) { + ArgumentError.checkNotNull(other, 'other'); + _$v = other as _$GetWithContentHeaders; + } + + @override + void update(void Function(GetWithContentHeadersBuilder)? updates) { + if (updates != null) updates(this); + } + + @override + GetWithContentHeaders build() => _build(); + + _$GetWithContentHeaders _build() { + final _$result = _$v ?? _$GetWithContentHeaders._(myHeader: myHeader); + replace(_$result); + return _$result; + } +} + +// ignore_for_file: deprecated_member_use_from_same_package,type=lint diff --git a/packages/dynamite/dynamite_end_to_end_test/lib/headers.openapi.json b/packages/dynamite/dynamite_end_to_end_test/lib/headers.openapi.json new file mode 100644 index 00000000..5825ee00 --- /dev/null +++ b/packages/dynamite/dynamite_end_to_end_test/lib/headers.openapi.json @@ -0,0 +1,67 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "headers test", + "version": "0.0.1" + }, + "paths": { + "/": { + "get": { + "responses": { + "200": { + "description": "Returns a header only", + "headers": { + "My-Header": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/with_content/operation_id": { + "get": { + "operationId": "with_content-operation_id", + "responses": { + "200": { + "description": "Returns a header only", + "headers": { + "My-Header": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/with_content": { + "get": { + "responses": { + "200": { + "description": "Returns both a header and a body.", + "headers": { + "My-Header": { + "schema": { + "type": "string" + } + } + }, + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + } + } + } + } + }, + "tags": [] +} diff --git a/packages/dynamite/dynamite_end_to_end_test/lib/parameters.openapi.dart b/packages/dynamite/dynamite_end_to_end_test/lib/parameters.openapi.dart index 81b0baba..1998e0ba 100644 --- a/packages/dynamite/dynamite_end_to_end_test/lib/parameters.openapi.dart +++ b/packages/dynamite/dynamite_end_to_end_test/lib/parameters.openapi.dart @@ -116,7 +116,19 @@ class Client extends DynamiteClient { } // coverage:ignore-start -final Serializers _serializers = Serializers().toBuilder().build(); +final Serializers _serializers = (Serializers().toBuilder() + ..addBuilderFactory( + const FullType(BuiltMap, [FullType(String), FullType(JsonObject)]), + MapBuilder.new, + ) + ..addBuilderFactory( + const FullType(ContentString, [ + FullType(BuiltMap, [FullType(String), FullType(JsonObject)]), + ]), + ContentString>.new, + ) + ..add(ContentString.serializer)) + .build(); final Serializers _jsonSerializers = (_serializers.toBuilder() ..add(DynamiteDoubleSerializer()) diff --git a/packages/dynamite/dynamite_end_to_end_test/lib/parameters.openapi.json b/packages/dynamite/dynamite_end_to_end_test/lib/parameters.openapi.json index 5b51e1cb..5582a0fe 100644 --- a/packages/dynamite/dynamite_end_to_end_test/lib/parameters.openapi.json +++ b/packages/dynamite/dynamite_end_to_end_test/lib/parameters.openapi.json @@ -38,8 +38,7 @@ "description": "", "content": { "application/json": { - "schema": { - } + "schema": {} } } }