diff --git a/CHANGELOG.md b/CHANGELOG.md index 9148198..fbab1ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - `DELETE /api/v1/domain_blocks` - Added response headers in `MastodonResponse`. ([#128](https://github.com/mastodon-dart/mastodon-api/issues/128)) - Added HTTP status in `MastodonResponse`. ([#126](https://github.com/mastodon-dart/mastodon-api/issues/126)) +- Added HTTP request in `MastodonResponse`. ([#127](https://github.com/mastodon-dart/mastodon-api/issues/127)) ## v0.4.0 diff --git a/lib/mastodon_api.dart b/lib/mastodon_api.dart index 1763aa6..1aed173 100644 --- a/lib/mastodon_api.dart +++ b/lib/mastodon_api.dart @@ -9,6 +9,7 @@ export 'package:mastodon_api/src/core/exception/data_not_found_exception.dart'; export 'package:mastodon_api/src/core/exception/mastodon_exception.dart'; export 'package:mastodon_api/src/core/exception/rate_limit_exceeded_exception.dart'; export 'package:mastodon_api/src/core/exception/unauthorized_exception.dart'; +export 'package:mastodon_api/src/core/http_method.dart'; export 'package:mastodon_api/src/core/http_status.dart'; export 'package:mastodon_api/src/core/language.dart'; export 'package:mastodon_api/src/core/locale.dart'; @@ -74,6 +75,7 @@ export 'package:mastodon_api/src/service/entities/trends_link.dart'; export 'package:mastodon_api/src/service/entities/usage_statistics.dart'; export 'package:mastodon_api/src/service/mastodon_v1_service.dart'; export 'package:mastodon_api/src/service/mastodon_v2_service.dart'; +export 'package:mastodon_api/src/service/response/mastodon_request.dart'; export 'package:mastodon_api/src/service/response/mastodon_response.dart'; export 'package:mastodon_api/src/service/v1/accounts/account_default_settings_param.dart'; export 'package:mastodon_api/src/service/v1/accounts/account_profile_meta_param.dart'; diff --git a/lib/src/core/http_method.dart b/lib/src/core/http_method.dart new file mode 100644 index 0000000..64dff9e --- /dev/null +++ b/lib/src/core/http_method.dart @@ -0,0 +1,36 @@ +// Copyright 2023 Kato Shinya. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided the conditions. + +enum HttpMethod { + /// `GET` + get('GET'), + + /// `POST` + post('POST'), + + /// `DELETE` + delete('DELETE'), + + /// `PUT` + put('PUT'), + + /// `PATCH` + patch('PATCH'); + + /// The value. + final String value; + + /// Returns the http method associated with [value]. + static HttpMethod valueOf(final String value) { + for (final method in values) { + if (method.value == value) { + return method; + } + } + + throw UnsupportedError('Unsupported value [$value].'); + } + + const HttpMethod(this.value); +} diff --git a/lib/src/service/base_service.dart b/lib/src/service/base_service.dart index 591d717..d636e83 100644 --- a/lib/src/service/base_service.dart +++ b/lib/src/service/base_service.dart @@ -17,11 +17,13 @@ import '../core/exception/data_not_found_exception.dart'; import '../core/exception/mastodon_exception.dart'; import '../core/exception/rate_limit_exceeded_exception.dart'; import '../core/exception/unauthorized_exception.dart'; +import '../core/http_method.dart'; import '../core/http_status.dart'; import '../core/service_helper.dart'; import '../core/util/json_utils.dart'; import 'entities/empty.dart'; import 'entities/rate_limit.dart'; +import 'response/mastodon_request.dart'; import 'response/mastodon_response.dart'; /// The callback function for building data object from response. @@ -213,6 +215,10 @@ abstract class BaseService implements _Service { MastodonResponse( headers: response.headers, status: HttpStatus.valueOf(response.statusCode), + request: MastodonRequest( + method: HttpMethod.valueOf(response.request!.method), + url: response.request!.url, + ), rateLimit: RateLimit.fromJson( rateLimitConverter.convert(response.headers), ), @@ -227,6 +233,10 @@ abstract class BaseService implements _Service { MastodonResponse( headers: response.headers, status: HttpStatus.valueOf(response.statusCode), + request: MastodonRequest( + method: HttpMethod.valueOf(response.request!.method), + url: response.request!.url, + ), rateLimit: RateLimit.fromJson( rateLimitConverter.convert(response.headers), ), @@ -245,6 +255,10 @@ abstract class BaseService implements _Service { return MastodonResponse( headers: response.headers, status: HttpStatus.valueOf(response.statusCode), + request: MastodonRequest( + method: HttpMethod.valueOf(response.request!.method), + url: response.request!.url, + ), rateLimit: RateLimit.fromJson( rateLimitConverter.convert(response.headers), ), @@ -263,6 +277,10 @@ abstract class BaseService implements _Service { return MastodonResponse( headers: response.headers, status: HttpStatus.valueOf(response.statusCode), + request: MastodonRequest( + method: HttpMethod.valueOf(response.request!.method), + url: response.request!.url, + ), rateLimit: RateLimit.fromJson( rateLimitConverter.convert(response.headers), ), diff --git a/lib/src/service/response/mastodon_request.dart b/lib/src/service/response/mastodon_request.dart new file mode 100644 index 0000000..f5435ea --- /dev/null +++ b/lib/src/service/response/mastodon_request.dart @@ -0,0 +1,20 @@ +// Copyright 2023 Kato Shinya. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided the conditions. + +// 🌎 Project imports: +import '../../core/http_method.dart'; + +class MastodonRequest { + /// Returns the new instance of [MastodonRequest]. + const MastodonRequest({ + required this.method, + required this.url, + }); + + /// The http method when request has sent. + final HttpMethod method; + + /// The request url. + final Uri url; +} diff --git a/lib/src/service/response/mastodon_response.dart b/lib/src/service/response/mastodon_response.dart index e0bf2c2..aeb44fb 100644 --- a/lib/src/service/response/mastodon_response.dart +++ b/lib/src/service/response/mastodon_response.dart @@ -6,6 +6,7 @@ import '../../core/http_status.dart'; import '../entities/empty.dart'; import '../entities/rate_limit.dart'; +import 'mastodon_request.dart'; /// The class represents the response from Mastodon API. class MastodonResponse { @@ -13,6 +14,7 @@ class MastodonResponse { const MastodonResponse({ required this.headers, required this.status, + required this.request, required this.rateLimit, required this.data, }); @@ -23,6 +25,9 @@ class MastodonResponse { /// The HTTP status from Mastodon API server. final HttpStatus status; + /// The request that generated this response. + final MastodonRequest request; + /// The rate limit final RateLimit rateLimit; diff --git a/test/mocks/client_context_stubs.dart b/test/mocks/client_context_stubs.dart index 5c9802a..51bcf56 100644 --- a/test/mocks/client_context_stubs.dart +++ b/test/mocks/client_context_stubs.dart @@ -33,6 +33,10 @@ MockClientContext buildGetStub( await File(resourcePath).readAsString(), statusCode, headers: {'content-type': 'application/json; charset=utf-8'}, + request: Request( + 'GET', + Uri(), + ), ), ); @@ -60,6 +64,10 @@ MockClientContext buildPostStub( headers: { 'content-type': 'application/json; charset=utf-8', }, + request: Request( + 'POST', + Uri(), + ), ), ); @@ -87,6 +95,10 @@ MockClientContext buildPostMultipartStub( headers: { 'content-type': 'application/json; charset=utf-8', }, + request: Request( + 'POST', + Uri(), + ), ), ); @@ -110,6 +122,10 @@ MockClientContext buildDeleteStub( await File(resourcePath).readAsString(), statusCode, headers: {'content-type': 'application/json; charset=utf-8'}, + request: Request( + 'DELETE', + Uri(), + ), ), ); @@ -134,6 +150,10 @@ MockClientContext buildPutStub( await File(resourcePath).readAsString(), statusCode, headers: {'content-type': 'application/json; charset=utf-8'}, + request: Request( + 'PUT', + Uri(), + ), ), ); @@ -159,6 +179,10 @@ MockClientContext buildPatchStub( await File(resourcePath).readAsString(), statusCode, headers: {'content-type': 'application/json; charset=utf-8'}, + request: Request( + 'PATCH', + Uri(), + ), ), ); @@ -183,6 +207,10 @@ MockClientContext buildPatchMultipartStub( await File(resourcePath).readAsString(), statusCode, headers: {'content-type': 'application/json; charset=utf-8'}, + request: Request( + 'PATCH', + Uri(), + ), ), ); @@ -216,6 +244,10 @@ MockClientContext buildSendStub( responseStream(), statusCode, headers: {'content-type': 'application/json; charset=utf-8'}, + request: Request( + 'GET', + Uri(), + ), ); }, ); diff --git a/test/src/core/http_method_test.dart b/test/src/core/http_method_test.dart new file mode 100644 index 0000000..f06298a --- /dev/null +++ b/test/src/core/http_method_test.dart @@ -0,0 +1,36 @@ +// Copyright 2023 Kato Shinya. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided the conditions. + +// 📦 Package imports: +import 'package:mastodon_api/src/core/http_method.dart'; +import 'package:test/test.dart'; + +void main() { + test('.name', () { + expect(HttpMethod.get.name, 'get'); + expect(HttpMethod.post.name, 'post'); + expect(HttpMethod.delete.name, 'delete'); + expect(HttpMethod.put.name, 'put'); + expect(HttpMethod.patch.name, 'patch'); + }); + + test('.value', () { + expect(HttpMethod.get.value, 'GET'); + expect(HttpMethod.post.value, 'POST'); + expect(HttpMethod.delete.value, 'DELETE'); + expect(HttpMethod.put.value, 'PUT'); + expect(HttpMethod.patch.value, 'PATCH'); + }); + + group('.valueOf', () { + test('when value is supported', () { + expect(HttpMethod.valueOf('POST'), HttpMethod.post); + }); + + test('when value is not supported', () { + expect( + () => HttpMethod.valueOf('TEST'), throwsA(isA())); + }); + }); +}