diff --git a/lib/src/client/response/collection_fetched.dart b/lib/src/client/response/collection_fetched.dart index d643258..f77b709 100644 --- a/lib/src/client/response/collection_fetched.dart +++ b/lib/src/client/response/collection_fetched.dart @@ -1,16 +1,25 @@ -import 'package:http_interop/http_interop.dart'; +import 'package:http_interop/http_interop.dart' as i; import 'package:json_api/document.dart'; +import 'package:json_api/src/client/response.dart'; class CollectionFetched { - CollectionFetched(this.httpResponse, Map json) { - final document = InboundDocument(json); + CollectionFetched(this.rawResponse) { + final document = InboundDocument(rawResponse.document ?? + (throw FormatException('The document must not be empty'))); collection.addAll(document.dataAsCollection()); included.addAll(document.included()); meta.addAll(document.meta()); links.addAll(document.links()); } - final Response httpResponse; + // coverage:ignore-start + /// The raw HTTP response + @Deprecated('Use rawResponse.httpResponse instead') + i.Response get httpResponse => rawResponse.httpResponse; + // coverage:ignore-end + + /// The raw JSON:API response + final Response rawResponse; /// The resource collection fetched from the server final collection = []; diff --git a/lib/src/client/response/related_resource_fetched.dart b/lib/src/client/response/related_resource_fetched.dart index 39a71a7..ab3cd60 100644 --- a/lib/src/client/response/related_resource_fetched.dart +++ b/lib/src/client/response/related_resource_fetched.dart @@ -1,22 +1,31 @@ -import 'package:http_interop/http_interop.dart'; +import 'package:http_interop/http_interop.dart' as i; import 'package:json_api/document.dart'; +import 'package:json_api/src/client/response.dart'; /// A related resource response. /// /// https://jsonapi.org/format/#fetching-resources-responses class RelatedResourceFetched { - RelatedResourceFetched(this.httpResponse, Map json) - : resource = InboundDocument(json).dataAsResourceOrNull() { - final document = InboundDocument(json); + RelatedResourceFetched(this.rawResponse) { + final document = InboundDocument(rawResponse.document ?? + (throw FormatException('The document must not be empty'))); + resource = document.dataAsResourceOrNull(); included.addAll(document.included()); meta.addAll(document.meta()); links.addAll(document.links()); } - final Response httpResponse; + // coverage:ignore-start + /// The raw HTTP response + @Deprecated('Use rawResponse.httpResponse instead') + i.Response get httpResponse => rawResponse.httpResponse; + // coverage:ignore-end + + /// The raw JSON:API response + final Response rawResponse; /// Related resource. May be null - final Resource? resource; + late final Resource? resource; /// Included resources final included = []; diff --git a/lib/src/client/response/relationship_fetched.dart b/lib/src/client/response/relationship_fetched.dart index a99c78e..889070f 100644 --- a/lib/src/client/response/relationship_fetched.dart +++ b/lib/src/client/response/relationship_fetched.dart @@ -1,19 +1,34 @@ -import 'package:http_interop/http_interop.dart'; +import 'package:http_interop/http_interop.dart' as i; import 'package:json_api/document.dart'; +import 'package:json_api/src/client/response.dart'; /// A response to a relationship fetch request. class RelationshipFetched { - RelationshipFetched(this.httpResponse, this.relationship); + RelationshipFetched(this.rawResponse, this.relationship); - static RelationshipFetched many(Response httpResponse, Map json) => - RelationshipFetched(httpResponse, InboundDocument(json).asToMany()) - ..included.addAll(InboundDocument(json).included()); + static RelationshipFetched many(Response response) { + final document = InboundDocument(response.document ?? + (throw FormatException('The document must not be empty'))); + return RelationshipFetched(response, document.asToMany()) + ..included.addAll(document.included()); + } - static RelationshipFetched one(Response httpResponse, Map json) => - RelationshipFetched(httpResponse, InboundDocument(json).asToOne()) - ..included.addAll(InboundDocument(json).included()); + static RelationshipFetched one(Response response) { + final document = InboundDocument(response.document ?? + (throw FormatException('The document must not be empty'))); + return RelationshipFetched(response, document.asToOne()) + ..included.addAll(document.included()); + } + + // coverage:ignore-start + /// The raw HTTP response + @Deprecated('Use rawResponse.httpResponse instead') + i.Response get httpResponse => rawResponse.httpResponse; + // coverage:ignore-end + + /// The raw JSON:API response + final Response rawResponse; - final Response httpResponse; final R relationship; final included = []; } diff --git a/lib/src/client/response/relationship_updated.dart b/lib/src/client/response/relationship_updated.dart index 2adb742..9a885d8 100644 --- a/lib/src/client/response/relationship_updated.dart +++ b/lib/src/client/response/relationship_updated.dart @@ -1,19 +1,31 @@ -import 'package:http_interop/http_interop.dart'; +import 'package:http_interop/http_interop.dart' as i; import 'package:json_api/document.dart'; +import 'package:json_api/src/client/response.dart'; /// A response to a relationship request. class RelationshipUpdated { - RelationshipUpdated(this.httpResponse, this.relationship); + RelationshipUpdated(this.rawResponse, this.relationship); - static RelationshipUpdated many(Response httpResponse, Map? json) => - RelationshipUpdated( - httpResponse, json == null ? null : InboundDocument(json).asToMany()); + static RelationshipUpdated many(Response response) { + final json = response.document; + return RelationshipUpdated( + response, json == null ? null : InboundDocument(json).asToMany()); + } - static RelationshipUpdated one(Response httpResponse, Map? json) => - RelationshipUpdated( - httpResponse, json == null ? null : InboundDocument(json).asToOne()); + static RelationshipUpdated one(Response response) { + final json = response.document; + return RelationshipUpdated( + response, json == null ? null : InboundDocument(json).asToOne()); + } - final Response httpResponse; + // coverage:ignore-start + /// The raw HTTP response + @Deprecated('Use rawResponse.httpResponse instead') + i.Response get httpResponse => rawResponse.httpResponse; + // coverage:ignore-end + + /// The raw JSON:API response + final Response rawResponse; /// Updated relationship. Null if "204 No Content" is returned. final R? relationship; diff --git a/lib/src/client/response/request_failure.dart b/lib/src/client/response/request_failure.dart index 096a84c..1f69695 100644 --- a/lib/src/client/response/request_failure.dart +++ b/lib/src/client/response/request_failure.dart @@ -1,16 +1,25 @@ -import 'package:http_interop/http_interop.dart'; +import 'package:http_interop/http_interop.dart' as i; import 'package:json_api/document.dart'; +import 'package:json_api/src/client/response.dart'; /// Thrown when the server returns a non-successful response. class RequestFailure implements Exception { - RequestFailure(this.httpResponse, Map? document) { - if (document != null) { - errors.addAll(InboundDocument(document).errors()); - meta.addAll(InboundDocument(document).meta()); - } + RequestFailure(this.rawResponse) { + final json = rawResponse.document; + if (json == null) return; + final document = InboundDocument(json); + errors.addAll(document.errors()); + meta.addAll(document.meta()); } - final Response httpResponse; + // coverage:ignore-start + /// The raw HTTP response + @Deprecated('Use rawResponse.httpResponse instead') + i.Response get httpResponse => rawResponse.httpResponse; + // coverage:ignore-end + + /// The raw JSON:API response + final Response rawResponse; /// Error objects returned by the server final errors = []; @@ -20,5 +29,5 @@ class RequestFailure implements Exception { @override String toString() => - 'JSON:API request failed with HTTP status ${httpResponse.statusCode}.'; + 'JSON:API request failed with HTTP status ${rawResponse.httpResponse.statusCode}.'; } diff --git a/lib/src/client/response/resource_created.dart b/lib/src/client/response/resource_created.dart index 3b15781..d67a8ec 100644 --- a/lib/src/client/response/resource_created.dart +++ b/lib/src/client/response/resource_created.dart @@ -1,22 +1,32 @@ -import 'package:http_interop/http_interop.dart'; +import 'package:http_interop/http_interop.dart' as i; import 'package:json_api/document.dart'; +import 'package:json_api/src/client/response.dart'; /// A response to a new resource creation request. /// This is always a "201 Created" response. /// /// https://jsonapi.org/format/#crud-creating-responses-201 class ResourceCreated { - ResourceCreated(this.httpResponse, Map json) - : resource = InboundDocument(json).dataAsResource() { - meta.addAll(InboundDocument(json).meta()); - links.addAll(InboundDocument(json).links()); - included.addAll(InboundDocument(json).included()); + ResourceCreated(this.rawResponse) { + final document = InboundDocument(rawResponse.document ?? + (throw FormatException('The document must not be empty'))); + resource = document.dataAsResource(); + included.addAll(document.included()); + meta.addAll(document.meta()); + links.addAll(document.links()); } - final Response httpResponse; + // coverage:ignore-start + /// The raw HTTP response + @Deprecated('Use rawResponse.httpResponse instead') + i.Response get httpResponse => rawResponse.httpResponse; + // coverage:ignore-end + + /// The raw JSON:API response + final Response rawResponse; /// Created resource. - final Resource resource; + late final Resource resource; /// Top-level meta data final meta = {}; diff --git a/lib/src/client/response/resource_fetched.dart b/lib/src/client/response/resource_fetched.dart index 3e62829..2b69446 100644 --- a/lib/src/client/response/resource_fetched.dart +++ b/lib/src/client/response/resource_fetched.dart @@ -1,17 +1,28 @@ -import 'package:http_interop/http_interop.dart'; +import 'package:http_interop/http_interop.dart' as i; import 'package:json_api/document.dart'; +import 'package:json_api/src/client/response.dart'; /// A response to fetch a primary resource request class ResourceFetched { - ResourceFetched(this.httpResponse, Map json) - : resource = InboundDocument(json).dataAsResource() { - included.addAll(InboundDocument(json).included()); - meta.addAll(InboundDocument(json).meta()); - links.addAll(InboundDocument(json).links()); + ResourceFetched(this.rawResponse) { + final document = InboundDocument(rawResponse.document ?? + (throw FormatException('The document must not be empty'))); + resource = document.dataAsResource(); + included.addAll(document.included()); + meta.addAll(document.meta()); + links.addAll(document.links()); } - final Response httpResponse; - final Resource resource; + // coverage:ignore-start + /// The raw HTTP response + @Deprecated('Use rawResponse.httpResponse instead') + i.Response get httpResponse => rawResponse.httpResponse; + // coverage:ignore-end + + /// The raw JSON:API response + final Response rawResponse; + + late final Resource resource; /// Top-level meta data final meta = {}; diff --git a/lib/src/client/response/resource_updated.dart b/lib/src/client/response/resource_updated.dart index ca9b919..381ebe9 100644 --- a/lib/src/client/response/resource_updated.dart +++ b/lib/src/client/response/resource_updated.dart @@ -1,26 +1,34 @@ -import 'package:http_interop/http_interop.dart'; +import 'package:http_interop/http_interop.dart' as i; import 'package:json_api/document.dart'; +import 'package:json_api/src/client/response.dart'; class ResourceUpdated { - ResourceUpdated(this.httpResponse, Map? json) : resource = _resource(json) { - if (json != null) { - included.addAll(InboundDocument(json).included()); - meta.addAll(InboundDocument(json).meta()); - links.addAll(InboundDocument(json).links()); + ResourceUpdated(this.rawResponse) + : resource = _resource(rawResponse.document) { + final document = rawResponse.document; + if (document != null) { + included.addAll(InboundDocument(document).included()); + meta.addAll(InboundDocument(document).meta()); + links.addAll(InboundDocument(document).links()); } } static Resource? _resource(Map? json) { if (json != null) { final doc = InboundDocument(json); - if (doc.hasData) { - return doc.dataAsResource(); - } + if (doc.hasData) return doc.dataAsResource(); } return null; } - final Response httpResponse; + // coverage:ignore-start + /// The raw HTTP response + @Deprecated('Use rawResponse.httpResponse instead') + i.Response get httpResponse => rawResponse.httpResponse; + // coverage:ignore-end + + /// The raw JSON:API response + final Response rawResponse; /// The created resource. Null for "204 No Content" responses. late final Resource? resource; diff --git a/lib/src/client/routing_client.dart b/lib/src/client/routing_client.dart index 9a250d0..7a11e24 100644 --- a/lib/src/client/routing_client.dart +++ b/lib/src/client/routing_client.dart @@ -32,14 +32,12 @@ class RoutingClient { List identifiers, { Map meta = const {}, Map> headers = const {}, - }) async { - final response = await send( - _baseUri.relationship(type, id, relationship), - Request.post( - OutboundDataDocument.many(ToMany(identifiers)..meta.addAll(meta))) - ..headers.addAll(headers)); - return RelationshipUpdated.many(response.httpResponse, response.document); - } + }) async => + RelationshipUpdated.many(await send( + _baseUri.relationship(type, id, relationship), + Request.post( + OutboundDataDocument.many(ToMany(identifiers)..meta.addAll(meta))) + ..headers.addAll(headers))); /// Creates a new resource with the given [type] and [id] on the server. /// @@ -61,21 +59,19 @@ class RoutingClient { Map documentMeta = const {}, Map> headers = const {}, Iterable query = const [], - }) async { - final response = await send( - _baseUri.collection(type), - Request.post(OutboundDataDocument.resource(Resource(type, id) - ..attributes.addAll(attributes) - ..relationships.addAll({ - ...one.map((key, value) => MapEntry(key, ToOne(value))), - ...many.map((key, value) => MapEntry(key, ToMany(value))), - }) - ..meta.addAll(meta)) - ..meta.addAll(documentMeta)) - ..headers.addAll(headers) - ..query.mergeAll(query)); - return ResourceUpdated(response.httpResponse, response.document); - } + }) async => + ResourceUpdated(await send( + _baseUri.collection(type), + Request.post(OutboundDataDocument.resource(Resource(type, id) + ..attributes.addAll(attributes) + ..relationships.addAll({ + ...one.map((key, value) => MapEntry(key, ToOne(value))), + ...many.map((key, value) => MapEntry(key, ToMany(value))), + }) + ..meta.addAll(meta)) + ..meta.addAll(documentMeta)) + ..headers.addAll(headers) + ..query.mergeAll(query))); /// Creates a new resource in the collection of type [type]. /// The server is responsible for assigning the resource id. @@ -99,24 +95,20 @@ class RoutingClient { Map documentMeta = const {}, Map> headers = const {}, Iterable query = const [], - }) async { - final response = await send( - _baseUri.collection(type), - Request.post( - OutboundDataDocument.newResource(NewResource(type, lid: lid) - ..attributes.addAll(attributes) - ..relationships.addAll({ - ...one.map((key, value) => MapEntry(key, NewToOne(value))), - ...many.map((key, value) => MapEntry(key, NewToMany(value))), - }) - ..meta.addAll(meta)) - ..meta.addAll(documentMeta)) - ..headers.addAll(headers) - ..query.mergeAll(query)); - - return ResourceCreated( - response.httpResponse, response.document ?? (throw FormatException())); - } + }) async => + ResourceCreated(await send( + _baseUri.collection(type), + Request.post( + OutboundDataDocument.newResource(NewResource(type, lid: lid) + ..attributes.addAll(attributes) + ..relationships.addAll({ + ...one.map((key, value) => MapEntry(key, NewToOne(value))), + ...many.map((key, value) => MapEntry(key, NewToMany(value))), + }) + ..meta.addAll(meta)) + ..meta.addAll(documentMeta)) + ..headers.addAll(headers) + ..query.mergeAll(query))); /// Deletes the [identifiers] from the to-many relationship /// identified by [type], [id], [relationship]. @@ -131,15 +123,12 @@ class RoutingClient { List identifiers, { Map meta = const {}, Map> headers = const {}, - }) async { - final response = await send( - _baseUri.relationship(type, id, relationship), - Request.delete( - OutboundDataDocument.many(ToMany(identifiers)..meta.addAll(meta))) - ..headers.addAll(headers)); - - return RelationshipUpdated.many(response.httpResponse, response.document); - } + }) async => + RelationshipUpdated.many(await send( + _baseUri.relationship(type, id, relationship), + Request.delete( + OutboundDataDocument.many(ToMany(identifiers)..meta.addAll(meta))) + ..headers.addAll(headers))); /// Fetches the primary collection of type [type]. /// @@ -150,15 +139,12 @@ class RoutingClient { String type, { Map> headers = const {}, Iterable query = const [], - }) async { - final response = await send( - _baseUri.collection(type), - Request.get() - ..headers.addAll(headers) - ..query.mergeAll(query)); - return CollectionFetched( - response.httpResponse, response.document ?? (throw FormatException())); - } + }) async => + CollectionFetched(await send( + _baseUri.collection(type), + Request.get() + ..headers.addAll(headers) + ..query.mergeAll(query))); /// Fetches the related resource collection /// identified by [type], [id], [relationship]. @@ -172,15 +158,12 @@ class RoutingClient { String relationship, { Map> headers = const {}, Iterable query = const [], - }) async { - final response = await send( - _baseUri.related(type, id, relationship), - Request.get() - ..headers.addAll(headers) - ..query.mergeAll(query)); - return CollectionFetched( - response.httpResponse, response.document ?? (throw FormatException())); - } + }) async => + CollectionFetched(await send( + _baseUri.related(type, id, relationship), + Request.get() + ..headers.addAll(headers) + ..query.mergeAll(query))); /// Fetches the to-one relationship /// identified by [type], [id], [relationship]. @@ -194,15 +177,12 @@ class RoutingClient { String relationship, { Map> headers = const {}, Iterable query = const [], - }) async { - final response = await send( - _baseUri.relationship(type, id, relationship), - Request.get() - ..headers.addAll(headers) - ..query.mergeAll(query)); - return RelationshipFetched.one( - response.httpResponse, response.document ?? (throw FormatException())); - } + }) async => + RelationshipFetched.one(await send( + _baseUri.relationship(type, id, relationship), + Request.get() + ..headers.addAll(headers) + ..query.mergeAll(query))); /// Fetches the to-many relationship /// identified by [type], [id], [relationship]. @@ -216,15 +196,12 @@ class RoutingClient { String relationship, { Map> headers = const {}, Iterable query = const [], - }) async { - final response = await send( - _baseUri.relationship(type, id, relationship), - Request.get() - ..headers.addAll(headers) - ..query.mergeAll(query)); - return RelationshipFetched.many( - response.httpResponse, response.document ?? (throw FormatException())); - } + }) async => + RelationshipFetched.many(await send( + _baseUri.relationship(type, id, relationship), + Request.get() + ..headers.addAll(headers) + ..query.mergeAll(query))); /// Fetches the related resource /// identified by [type], [id], [relationship]. @@ -238,15 +215,12 @@ class RoutingClient { String relationship, { Map> headers = const {}, Iterable query = const [], - }) async { - final response = await send( - _baseUri.related(type, id, relationship), - Request.get() - ..headers.addAll(headers) - ..query.mergeAll(query)); - return RelatedResourceFetched( - response.httpResponse, response.document ?? (throw FormatException())); - } + }) async => + RelatedResourceFetched(await send( + _baseUri.related(type, id, relationship), + Request.get() + ..headers.addAll(headers) + ..query.mergeAll(query))); /// Fetches the resource identified by [type] and [id]. /// @@ -258,16 +232,12 @@ class RoutingClient { String id, { Map> headers = const {}, Iterable query = const [], - }) async { - final response = await send( - _baseUri.resource(type, id), - Request.get() - ..headers.addAll(headers) - ..query.mergeAll(query)); - - return ResourceFetched( - response.httpResponse, response.document ?? (throw FormatException())); - } + }) async => + ResourceFetched(await send( + _baseUri.resource(type, id), + Request.get() + ..headers.addAll(headers) + ..query.mergeAll(query))); /// Updates the resource identified by [type] and [id]. /// @@ -289,21 +259,19 @@ class RoutingClient { Map documentMeta = const {}, Map> headers = const {}, Iterable query = const [], - }) async { - final response = await send( - _baseUri.resource(type, id), - Request.patch(OutboundDataDocument.resource(Resource(type, id) - ..attributes.addAll(attributes) - ..relationships.addAll({ - ...one.map((key, value) => MapEntry(key, ToOne(value))), - ...many.map((key, value) => MapEntry(key, ToMany(value))), - }) - ..meta.addAll(meta)) - ..meta.addAll(documentMeta)) - ..headers.addAll(headers) - ..query.mergeAll(query)); - return ResourceUpdated(response.httpResponse, response.document); - } + }) async => + ResourceUpdated(await send( + _baseUri.resource(type, id), + Request.patch(OutboundDataDocument.resource(Resource(type, id) + ..attributes.addAll(attributes) + ..relationships.addAll({ + ...one.map((key, value) => MapEntry(key, ToOne(value))), + ...many.map((key, value) => MapEntry(key, ToMany(value))), + }) + ..meta.addAll(meta)) + ..meta.addAll(documentMeta)) + ..headers.addAll(headers) + ..query.mergeAll(query))); /// Replaces the to-one relationship /// identified by [type], [id], and [relationship] by setting @@ -321,15 +289,13 @@ class RoutingClient { Map meta = const {}, Map> headers = const {}, Iterable query = const [], - }) async { - final response = await send( - _baseUri.relationship(type, id, relationship), - Request.patch( - OutboundDataDocument.one(ToOne(identifier)..meta.addAll(meta))) - ..headers.addAll(headers) - ..query.mergeAll(query)); - return RelationshipUpdated.one(response.httpResponse, response.document); - } + }) async => + RelationshipUpdated.one(await send( + _baseUri.relationship(type, id, relationship), + Request.patch( + OutboundDataDocument.one(ToOne(identifier)..meta.addAll(meta))) + ..headers.addAll(headers) + ..query.mergeAll(query))); /// Replaces the to-many relationship /// identified by [type], [id], and [relationship] by setting @@ -347,15 +313,13 @@ class RoutingClient { Map meta = const {}, Map> headers = const {}, Iterable query = const [], - }) async { - final response = await send( - _baseUri.relationship(type, id, relationship), - Request.patch( - OutboundDataDocument.many(ToMany(identifiers)..meta.addAll(meta))) - ..headers.addAll(headers) - ..query.mergeAll(query)); - return RelationshipUpdated.many(response.httpResponse, response.document); - } + }) async => + RelationshipUpdated.many(await send( + _baseUri.relationship(type, id, relationship), + Request.patch( + OutboundDataDocument.many(ToMany(identifiers)..meta.addAll(meta))) + ..headers.addAll(headers) + ..query.mergeAll(query))); /// Removes the to-one relationship /// identified by [type], [id], and [relationship].. @@ -369,14 +333,12 @@ class RoutingClient { String relationship, { Map> headers = const {}, Iterable query = const [], - }) async { - final response = await send( - _baseUri.relationship(type, id, relationship), - Request.patch(OutboundDataDocument.one(ToOne.empty())) - ..headers.addAll(headers) - ..query.mergeAll(query)); - return RelationshipUpdated.one(response.httpResponse, response.document); - } + }) async => + RelationshipUpdated.one(await send( + _baseUri.relationship(type, id, relationship), + Request.patch(OutboundDataDocument.one(ToOne.empty())) + ..headers.addAll(headers) + ..query.mergeAll(query))); /// Deletes the resource identified by [type] and [id]. /// @@ -399,9 +361,7 @@ class RoutingClient { /// This method can be used to send any non-standard requests. Future send(Uri uri, Request request) async { final response = await _client.send(uri, request); - if (response.isFailed) { - throw RequestFailure(response.httpResponse, response.document); - } + if (response.isFailed) throw RequestFailure(response); return response; } } diff --git a/test/contract/crud_test.dart b/test/contract/crud_test.dart index 41520f5..e2af254 100644 --- a/test/contract/crud_test.dart +++ b/test/contract/crud_test.dart @@ -47,7 +47,7 @@ void main() { Include(['author', 'comments', 'comments.author']) ]); - expect(response.httpResponse.statusCode, 200); + expect(response.rawResponse.httpResponse.statusCode, 200); expect(response.collection.length, 1); expect(response.included.length, 3); @@ -175,7 +175,7 @@ void main() { await action(); fail('Exception expected'); } on RequestFailure catch (e) { - expect(e.httpResponse.statusCode, 404); + expect(e.rawResponse.httpResponse.statusCode, 404); } } }); diff --git a/test/contract/resource_creation_test.dart b/test/contract/resource_creation_test.dart index 06b215b..c29991a 100644 --- a/test/contract/resource_creation_test.dart +++ b/test/contract/resource_creation_test.dart @@ -16,8 +16,9 @@ void main() { test('Resource id assigned on the server', () async { await client .createNew('posts', attributes: {'title': 'Hello world'}).then((r) { - expect(r.httpResponse.statusCode, 201); - expect(r.httpResponse.headers['location'], ['/posts/${r.resource.id}']); + expect(r.rawResponse.httpResponse.statusCode, 201); + expect(r.rawResponse.httpResponse.headers['location'], + ['/posts/${r.resource.id}']); expect(r.links['self'].toString(), '/posts/${r.resource.id}'); expect(r.resource.type, 'posts'); expect(r.resource.attributes['title'], 'Hello world'); @@ -30,8 +31,9 @@ void main() { lid: 'lid', attributes: {'title': 'Hello world'}, one: {'self': LocalIdentifier('posts', 'lid')}).then((r) { - expect(r.httpResponse.statusCode, 201); - expect(r.httpResponse.headers['location'], ['/posts/${r.resource.id}']); + expect(r.rawResponse.httpResponse.statusCode, 201); + expect(r.rawResponse.httpResponse.headers['location'], + ['/posts/${r.resource.id}']); expect(r.links['self'].toString(), '/posts/${r.resource.id}'); expect(r.resource.type, 'posts'); expect(r.resource.attributes['title'], 'Hello world'); @@ -42,9 +44,9 @@ void main() { test('Resource id assigned on the client', () async { await client.create('posts', '12345', attributes: {'title': 'Hello world'}).then((r) { - expect(r.httpResponse.statusCode, 204); + expect(r.rawResponse.httpResponse.statusCode, 204); expect(r.resource, isNull); - expect(r.httpResponse.headers['location'], isNull); + expect(r.rawResponse.httpResponse.headers['location'], isNull); }); }); }); diff --git a/test/e2e/e2e_test_set.dart b/test/e2e/e2e_test_set.dart index 4d7a3fd..6dc67ec 100644 --- a/test/e2e/e2e_test_set.dart +++ b/test/e2e/e2e_test_set.dart @@ -30,7 +30,7 @@ void testLocationIsSet(RoutingClient Function() client) { test('Location is set', () async { final r = await client() .createNew('posts', attributes: {'title': 'Location test'}); - expect(r.httpResponse.headers['Location'], isNotEmpty); + expect(r.rawResponse.httpResponse.headers['Location'], isNotEmpty); await client().deleteResource('posts', r.resource.id); }); } diff --git a/test/unit/client/client_test.dart b/test/unit/client/client_test.dart index eaf38e0..1ce542a 100644 --- a/test/unit/client/client_test.dart +++ b/test/unit/client/client_test.dart @@ -22,7 +22,7 @@ void main() { await client.fetchCollection('articles'); fail('Exception expected'); } on RequestFailure catch (e) { - expect(e.httpResponse.statusCode, 422); + expect(e.rawResponse.httpResponse.statusCode, 422); expect(e.errors.first.status, '422'); expect(e.errors.first.title, 'Invalid Attribute'); } @@ -33,7 +33,7 @@ void main() { await client.fetchCollection('articles'); fail('Exception expected'); } on RequestFailure catch (e) { - expect(e.httpResponse.statusCode, 500); + expect(e.rawResponse.httpResponse.statusCode, 500); } }); }); @@ -558,7 +558,7 @@ void main() { 'articles', '1', 'author', Identifier('people', '42')); fail('Exception expected'); } on RequestFailure catch (e) { - expect(e.httpResponse.statusCode, 422); + expect(e.rawResponse.httpResponse.statusCode, 422); expect(e.errors.first.status, '422'); } }); @@ -615,7 +615,7 @@ void main() { await client.deleteToOne('articles', '1', 'author'); fail('Exception expected'); } on RequestFailure catch (e) { - expect(e.httpResponse.statusCode, 422); + expect(e.rawResponse.httpResponse.statusCode, 422); expect(e.errors.first.status, '422'); } }); @@ -680,7 +680,7 @@ void main() { .deleteFromMany('articles', '1', 'tags', [Identifier('tags', '1')]); fail('Exception expected'); } on RequestFailure catch (e) { - expect(e.httpResponse.statusCode, 422); + expect(e.rawResponse.httpResponse.statusCode, 422); expect(e.errors.first.status, '422'); } }); @@ -747,7 +747,7 @@ void main() { .replaceToMany('articles', '1', 'tags', [Identifier('tags', '1')]); fail('Exception expected'); } on RequestFailure catch (e) { - expect(e.httpResponse.statusCode, 422); + expect(e.rawResponse.httpResponse.statusCode, 422); expect(e.errors.first.status, '422'); } }); @@ -814,7 +814,7 @@ void main() { .addMany('articles', '1', 'tags', [Identifier('tags', '1')]); fail('Exception expected'); } on RequestFailure catch (e) { - expect(e.httpResponse.statusCode, 422); + expect(e.rawResponse.httpResponse.statusCode, 422); expect(e.errors.first.status, '422'); expect(e.toString(), contains('422')); } diff --git a/test/unit/client/typed_responses_test.dart b/test/unit/client/typed_responses_test.dart new file mode 100644 index 0000000..85525cd --- /dev/null +++ b/test/unit/client/typed_responses_test.dart @@ -0,0 +1,45 @@ +import 'package:http_interop/http_interop.dart' as i; +import 'package:json_api/client.dart'; +import 'package:json_api/src/client/response.dart'; +import 'package:test/expect.dart'; +import 'package:test/scaffolding.dart'; + +void main() { + final emptyResponse = Response(i.Response(200, i.Body(), i.Headers()), null); + group('CollectionFetched', () { + test('throws on empty body', () { + expect(() => CollectionFetched(emptyResponse), throwsFormatException); + }); + }); + + group('RelatedResourceFetched', () { + test('throws on empty body', () { + expect( + () => RelatedResourceFetched(emptyResponse), throwsFormatException); + }); + }); + + group('RelationshipFetched', () { + test('.many() throws on empty body', () { + expect( + () => RelationshipFetched.many(emptyResponse), throwsFormatException); + }); + + test('.one() throws on empty body', () { + expect( + () => RelationshipFetched.one(emptyResponse), throwsFormatException); + }); + }); + + group('ResourceCreated', () { + test('throws on empty body', () { + expect(() => ResourceCreated(emptyResponse), throwsFormatException); + }); + }); + + group('ResourceFetched', () { + test('throws on empty body', () { + expect(() => ResourceFetched(emptyResponse), throwsFormatException); + }); + }); +}