From 798c3e196095389221c1970896c6c29c5e6827bc Mon Sep 17 00:00:00 2001 From: jld3103 Date: Tue, 3 Oct 2023 20:24:22 +0200 Subject: [PATCH 1/2] feat(dynamite): Support default responses Signed-off-by: jld3103 --- .../dynamite/lib/src/builder/client.dart | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/dynamite/dynamite/lib/src/builder/client.dart b/packages/dynamite/dynamite/lib/src/builder/client.dart index 51e5bf5e..f7c6f962 100644 --- a/packages/dynamite/dynamite/lib/src/builder/client.dart +++ b/packages/dynamite/dynamite/lib/src/builder/client.dart @@ -190,14 +190,10 @@ Iterable buildTags( ]..sort(sortRequiredParameters); final name = toDartName(filterMethodName(operationName, tag ?? '')); - var responses = >{}; + 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 $operationName'); - continue; - } + final statusCode = responseEntry.key; final response = responseEntry.value; responses[response] ??= []; @@ -225,7 +221,6 @@ Iterable buildTags( '''); buildAuthCheck( - responses, pathEntry, operation, spec, @@ -357,8 +352,12 @@ final _uri = Uri(path: _path, queryParameters: _queryParameters.isNotEmpty ? _qu '''); if (responses.values.isNotEmpty) { - final codes = statusCodes.join(','); - code.writeln('const {$codes},'); + if (statusCodes.contains('default')) { + code.writeln('null,'); + } else { + final codes = statusCodes.join(','); + code.writeln('const {$codes},'); + } } code.writeln(''' @@ -478,7 +477,6 @@ Iterable buildPatternCheck( } Iterable buildAuthCheck( - final Map> responses, final MapEntry pathEntry, final openapi.Operation operation, final openapi.OpenAPI spec, From ef7ff107288ac70fbb08ca51f8dd9a0009fe7ce6 Mon Sep 17 00:00:00 2001 From: jld3103 Date: Sun, 29 Oct 2023 12:01:09 +0100 Subject: [PATCH 2/2] test(dynamite_end_to_end_test): Add test for responses Signed-off-by: jld3103 --- .../lib/responses.openapi.dart | 245 ++++++++++++++++++ .../lib/responses.openapi.json | 108 ++++++++ 2 files changed, 353 insertions(+) create mode 100644 packages/dynamite/dynamite_end_to_end_test/lib/responses.openapi.dart create mode 100644 packages/dynamite/dynamite_end_to_end_test/lib/responses.openapi.json diff --git a/packages/dynamite/dynamite_end_to_end_test/lib/responses.openapi.dart b/packages/dynamite/dynamite_end_to_end_test/lib/responses.openapi.dart new file mode 100644 index 00000000..6bb9e433 --- /dev/null +++ b/packages/dynamite/dynamite_end_to_end_test/lib/responses.openapi.dart @@ -0,0 +1,245 @@ +// 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/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'; + +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: + /// * default + /// + /// 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: + /// * default + /// + /// See: + /// * [$get] for an operation that returns a [DynamiteResponse] with a stable API. + @experimental + DynamiteRawResponse $getRaw() { + final queryParameters = {}; + final headers = { + 'Accept': 'application/json', + }; + Uint8List? body; + + const path = '/'; + final uri = Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null); + + return DynamiteRawResponse( + response: executeRequest( + 'get', + uri, + headers, + body, + null, + ), + bodyType: const FullType(String), + headersType: null, + 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 + /// * 201 + /// + /// See: + /// * [putRaw] for an experimental operation that returns a [DynamiteRawResponse] that can be serialized. + Future> put() async { + final rawResponse = putRaw(); + + 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 + /// * 201 + /// + /// See: + /// * [put] for an operation that returns a [DynamiteResponse] with a stable API. + @experimental + DynamiteRawResponse putRaw() { + final queryParameters = {}; + final headers = { + 'Accept': 'application/json', + }; + Uint8List? body; + + const path = '/'; + final uri = Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null); + + return DynamiteRawResponse( + response: executeRequest( + 'put', + uri, + headers, + body, + const {200}, + ), + bodyType: const FullType(String), + headersType: null, + 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: + /// * default + /// * 200 + /// * 201 + /// + /// See: + /// * [postRaw] for an experimental operation that returns a [DynamiteRawResponse] that can be serialized. + Future> post() async { + final rawResponse = postRaw(); + + 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: + /// * default + /// * 200 + /// * 201 + /// + /// See: + /// * [post] for an operation that returns a [DynamiteResponse] with a stable API. + @experimental + DynamiteRawResponse postRaw() { + final queryParameters = {}; + final headers = { + 'Accept': 'application/json', + }; + Uint8List? body; + + const path = '/'; + final uri = Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null); + + return DynamiteRawResponse( + response: executeRequest( + 'post', + uri, + headers, + body, + null, + ), + bodyType: const FullType(String), + headersType: null, + 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 + /// * 201 + /// + /// See: + /// * [patchRaw] for an experimental operation that returns a [DynamiteRawResponse] that can be serialized. + Future> patch() async { + final rawResponse = patchRaw(); + + 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 + /// * 201 + /// + /// See: + /// * [patch] for an operation that returns a [DynamiteResponse] with a stable API. + @experimental + DynamiteRawResponse patchRaw() { + final queryParameters = {}; + final headers = { + 'Accept': 'application/json', + }; + Uint8List? body; + + const path = '/'; + final uri = Uri(path: path, queryParameters: queryParameters.isNotEmpty ? queryParameters : null); + + return DynamiteRawResponse( + response: executeRequest( + 'patch', + uri, + headers, + body, + const {200, 201}, + ), + bodyType: const FullType(String), + headersType: null, + serializers: _jsonSerializers, + ); + } +} + +// coverage:ignore-start +final Serializers _serializers = Serializers().toBuilder().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/responses.openapi.json b/packages/dynamite/dynamite_end_to_end_test/lib/responses.openapi.json new file mode 100644 index 00000000..5907423d --- /dev/null +++ b/packages/dynamite/dynamite_end_to_end_test/lib/responses.openapi.json @@ -0,0 +1,108 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "responses test", + "version": "0.0.1" + }, + "paths": { + "/": { + "get": { + "responses": { + "default": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + } + }, + "post": { + "responses": { + "default": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "integer" + } + } + } + } + } + }, + "put": { + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "integer" + } + } + } + } + } + }, + "patch": { + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + }, + "201": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "tags": [] +}