Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3aeecb6

Browse files
authoredAug 30, 2024··
Add rawResponse (#144)
1 parent a1b2f09 commit 3aeecb6

14 files changed

+317
-227
lines changed
 

‎lib/src/client/response/collection_fetched.dart

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
1-
import 'package:http_interop/http_interop.dart';
1+
import 'package:http_interop/http_interop.dart' as i;
22
import 'package:json_api/document.dart';
3+
import 'package:json_api/src/client/response.dart';
34

45
class CollectionFetched {
5-
CollectionFetched(this.httpResponse, Map json) {
6-
final document = InboundDocument(json);
6+
CollectionFetched(this.rawResponse) {
7+
final document = InboundDocument(rawResponse.document ??
8+
(throw FormatException('The document must not be empty')));
79
collection.addAll(document.dataAsCollection());
810
included.addAll(document.included());
911
meta.addAll(document.meta());
1012
links.addAll(document.links());
1113
}
1214

13-
final Response httpResponse;
15+
// coverage:ignore-start
16+
/// The raw HTTP response
17+
@Deprecated('Use rawResponse.httpResponse instead')
18+
i.Response get httpResponse => rawResponse.httpResponse;
19+
// coverage:ignore-end
20+
21+
/// The raw JSON:API response
22+
final Response rawResponse;
1423

1524
/// The resource collection fetched from the server
1625
final collection = <Resource>[];

‎lib/src/client/response/related_resource_fetched.dart

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,31 @@
1-
import 'package:http_interop/http_interop.dart';
1+
import 'package:http_interop/http_interop.dart' as i;
22
import 'package:json_api/document.dart';
3+
import 'package:json_api/src/client/response.dart';
34

45
/// A related resource response.
56
///
67
/// https://jsonapi.org/format/#fetching-resources-responses
78
class RelatedResourceFetched {
8-
RelatedResourceFetched(this.httpResponse, Map json)
9-
: resource = InboundDocument(json).dataAsResourceOrNull() {
10-
final document = InboundDocument(json);
9+
RelatedResourceFetched(this.rawResponse) {
10+
final document = InboundDocument(rawResponse.document ??
11+
(throw FormatException('The document must not be empty')));
12+
resource = document.dataAsResourceOrNull();
1113
included.addAll(document.included());
1214
meta.addAll(document.meta());
1315
links.addAll(document.links());
1416
}
1517

16-
final Response httpResponse;
18+
// coverage:ignore-start
19+
/// The raw HTTP response
20+
@Deprecated('Use rawResponse.httpResponse instead')
21+
i.Response get httpResponse => rawResponse.httpResponse;
22+
// coverage:ignore-end
23+
24+
/// The raw JSON:API response
25+
final Response rawResponse;
1726

1827
/// Related resource. May be null
19-
final Resource? resource;
28+
late final Resource? resource;
2029

2130
/// Included resources
2231
final included = <Resource>[];
Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,34 @@
1-
import 'package:http_interop/http_interop.dart';
1+
import 'package:http_interop/http_interop.dart' as i;
22
import 'package:json_api/document.dart';
3+
import 'package:json_api/src/client/response.dart';
34

45
/// A response to a relationship fetch request.
56
class RelationshipFetched<R extends Relationship> {
6-
RelationshipFetched(this.httpResponse, this.relationship);
7+
RelationshipFetched(this.rawResponse, this.relationship);
78

8-
static RelationshipFetched<ToMany> many(Response httpResponse, Map json) =>
9-
RelationshipFetched(httpResponse, InboundDocument(json).asToMany())
10-
..included.addAll(InboundDocument(json).included());
9+
static RelationshipFetched<ToMany> many(Response response) {
10+
final document = InboundDocument(response.document ??
11+
(throw FormatException('The document must not be empty')));
12+
return RelationshipFetched(response, document.asToMany())
13+
..included.addAll(document.included());
14+
}
1115

12-
static RelationshipFetched<ToOne> one(Response httpResponse, Map json) =>
13-
RelationshipFetched(httpResponse, InboundDocument(json).asToOne())
14-
..included.addAll(InboundDocument(json).included());
16+
static RelationshipFetched<ToOne> one(Response response) {
17+
final document = InboundDocument(response.document ??
18+
(throw FormatException('The document must not be empty')));
19+
return RelationshipFetched(response, document.asToOne())
20+
..included.addAll(document.included());
21+
}
22+
23+
// coverage:ignore-start
24+
/// The raw HTTP response
25+
@Deprecated('Use rawResponse.httpResponse instead')
26+
i.Response get httpResponse => rawResponse.httpResponse;
27+
// coverage:ignore-end
28+
29+
/// The raw JSON:API response
30+
final Response rawResponse;
1531

16-
final Response httpResponse;
1732
final R relationship;
1833
final included = <Resource>[];
1934
}

‎lib/src/client/response/relationship_updated.dart

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,31 @@
1-
import 'package:http_interop/http_interop.dart';
1+
import 'package:http_interop/http_interop.dart' as i;
22
import 'package:json_api/document.dart';
3+
import 'package:json_api/src/client/response.dart';
34

45
/// A response to a relationship request.
56
class RelationshipUpdated<R extends Relationship> {
6-
RelationshipUpdated(this.httpResponse, this.relationship);
7+
RelationshipUpdated(this.rawResponse, this.relationship);
78

8-
static RelationshipUpdated<ToMany> many(Response httpResponse, Map? json) =>
9-
RelationshipUpdated(
10-
httpResponse, json == null ? null : InboundDocument(json).asToMany());
9+
static RelationshipUpdated<ToMany> many(Response response) {
10+
final json = response.document;
11+
return RelationshipUpdated(
12+
response, json == null ? null : InboundDocument(json).asToMany());
13+
}
1114

12-
static RelationshipUpdated<ToOne> one(Response httpResponse, Map? json) =>
13-
RelationshipUpdated(
14-
httpResponse, json == null ? null : InboundDocument(json).asToOne());
15+
static RelationshipUpdated<ToOne> one(Response response) {
16+
final json = response.document;
17+
return RelationshipUpdated(
18+
response, json == null ? null : InboundDocument(json).asToOne());
19+
}
1520

16-
final Response httpResponse;
21+
// coverage:ignore-start
22+
/// The raw HTTP response
23+
@Deprecated('Use rawResponse.httpResponse instead')
24+
i.Response get httpResponse => rawResponse.httpResponse;
25+
// coverage:ignore-end
26+
27+
/// The raw JSON:API response
28+
final Response rawResponse;
1729

1830
/// Updated relationship. Null if "204 No Content" is returned.
1931
final R? relationship;
Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
1-
import 'package:http_interop/http_interop.dart';
1+
import 'package:http_interop/http_interop.dart' as i;
22
import 'package:json_api/document.dart';
3+
import 'package:json_api/src/client/response.dart';
34

45
/// Thrown when the server returns a non-successful response.
56
class RequestFailure implements Exception {
6-
RequestFailure(this.httpResponse, Map? document) {
7-
if (document != null) {
8-
errors.addAll(InboundDocument(document).errors());
9-
meta.addAll(InboundDocument(document).meta());
10-
}
7+
RequestFailure(this.rawResponse) {
8+
final json = rawResponse.document;
9+
if (json == null) return;
10+
final document = InboundDocument(json);
11+
errors.addAll(document.errors());
12+
meta.addAll(document.meta());
1113
}
1214

13-
final Response httpResponse;
15+
// coverage:ignore-start
16+
/// The raw HTTP response
17+
@Deprecated('Use rawResponse.httpResponse instead')
18+
i.Response get httpResponse => rawResponse.httpResponse;
19+
// coverage:ignore-end
20+
21+
/// The raw JSON:API response
22+
final Response rawResponse;
1423

1524
/// Error objects returned by the server
1625
final errors = <ErrorObject>[];
@@ -20,5 +29,5 @@ class RequestFailure implements Exception {
2029

2130
@override
2231
String toString() =>
23-
'JSON:API request failed with HTTP status ${httpResponse.statusCode}.';
32+
'JSON:API request failed with HTTP status ${rawResponse.httpResponse.statusCode}.';
2433
}

‎lib/src/client/response/resource_created.dart

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,32 @@
1-
import 'package:http_interop/http_interop.dart';
1+
import 'package:http_interop/http_interop.dart' as i;
22
import 'package:json_api/document.dart';
3+
import 'package:json_api/src/client/response.dart';
34

45
/// A response to a new resource creation request.
56
/// This is always a "201 Created" response.
67
///
78
/// https://jsonapi.org/format/#crud-creating-responses-201
89
class ResourceCreated {
9-
ResourceCreated(this.httpResponse, Map json)
10-
: resource = InboundDocument(json).dataAsResource() {
11-
meta.addAll(InboundDocument(json).meta());
12-
links.addAll(InboundDocument(json).links());
13-
included.addAll(InboundDocument(json).included());
10+
ResourceCreated(this.rawResponse) {
11+
final document = InboundDocument(rawResponse.document ??
12+
(throw FormatException('The document must not be empty')));
13+
resource = document.dataAsResource();
14+
included.addAll(document.included());
15+
meta.addAll(document.meta());
16+
links.addAll(document.links());
1417
}
1518

16-
final Response httpResponse;
19+
// coverage:ignore-start
20+
/// The raw HTTP response
21+
@Deprecated('Use rawResponse.httpResponse instead')
22+
i.Response get httpResponse => rawResponse.httpResponse;
23+
// coverage:ignore-end
24+
25+
/// The raw JSON:API response
26+
final Response rawResponse;
1727

1828
/// Created resource.
19-
final Resource resource;
29+
late final Resource resource;
2030

2131
/// Top-level meta data
2232
final meta = <String, Object?>{};

‎lib/src/client/response/resource_fetched.dart

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
1-
import 'package:http_interop/http_interop.dart';
1+
import 'package:http_interop/http_interop.dart' as i;
22
import 'package:json_api/document.dart';
3+
import 'package:json_api/src/client/response.dart';
34

45
/// A response to fetch a primary resource request
56
class ResourceFetched {
6-
ResourceFetched(this.httpResponse, Map json)
7-
: resource = InboundDocument(json).dataAsResource() {
8-
included.addAll(InboundDocument(json).included());
9-
meta.addAll(InboundDocument(json).meta());
10-
links.addAll(InboundDocument(json).links());
7+
ResourceFetched(this.rawResponse) {
8+
final document = InboundDocument(rawResponse.document ??
9+
(throw FormatException('The document must not be empty')));
10+
resource = document.dataAsResource();
11+
included.addAll(document.included());
12+
meta.addAll(document.meta());
13+
links.addAll(document.links());
1114
}
1215

13-
final Response httpResponse;
14-
final Resource resource;
16+
// coverage:ignore-start
17+
/// The raw HTTP response
18+
@Deprecated('Use rawResponse.httpResponse instead')
19+
i.Response get httpResponse => rawResponse.httpResponse;
20+
// coverage:ignore-end
21+
22+
/// The raw JSON:API response
23+
final Response rawResponse;
24+
25+
late final Resource resource;
1526

1627
/// Top-level meta data
1728
final meta = <String, Object?>{};

‎lib/src/client/response/resource_updated.dart

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
1-
import 'package:http_interop/http_interop.dart';
1+
import 'package:http_interop/http_interop.dart' as i;
22
import 'package:json_api/document.dart';
3+
import 'package:json_api/src/client/response.dart';
34

45
class ResourceUpdated {
5-
ResourceUpdated(this.httpResponse, Map? json) : resource = _resource(json) {
6-
if (json != null) {
7-
included.addAll(InboundDocument(json).included());
8-
meta.addAll(InboundDocument(json).meta());
9-
links.addAll(InboundDocument(json).links());
6+
ResourceUpdated(this.rawResponse)
7+
: resource = _resource(rawResponse.document) {
8+
final document = rawResponse.document;
9+
if (document != null) {
10+
included.addAll(InboundDocument(document).included());
11+
meta.addAll(InboundDocument(document).meta());
12+
links.addAll(InboundDocument(document).links());
1013
}
1114
}
1215

1316
static Resource? _resource(Map? json) {
1417
if (json != null) {
1518
final doc = InboundDocument(json);
16-
if (doc.hasData) {
17-
return doc.dataAsResource();
18-
}
19+
if (doc.hasData) return doc.dataAsResource();
1920
}
2021
return null;
2122
}
2223

23-
final Response httpResponse;
24+
// coverage:ignore-start
25+
/// The raw HTTP response
26+
@Deprecated('Use rawResponse.httpResponse instead')
27+
i.Response get httpResponse => rawResponse.httpResponse;
28+
// coverage:ignore-end
29+
30+
/// The raw JSON:API response
31+
final Response rawResponse;
2432

2533
/// The created resource. Null for "204 No Content" responses.
2634
late final Resource? resource;

‎lib/src/client/routing_client.dart

Lines changed: 109 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,12 @@ class RoutingClient {
3232
List<Identifier> identifiers, {
3333
Map<String, Object?> meta = const {},
3434
Map<String, List<String>> headers = const {},
35-
}) async {
36-
final response = await send(
37-
_baseUri.relationship(type, id, relationship),
38-
Request.post(
39-
OutboundDataDocument.many(ToMany(identifiers)..meta.addAll(meta)))
40-
..headers.addAll(headers));
41-
return RelationshipUpdated.many(response.httpResponse, response.document);
42-
}
35+
}) async =>
36+
RelationshipUpdated.many(await send(
37+
_baseUri.relationship(type, id, relationship),
38+
Request.post(
39+
OutboundDataDocument.many(ToMany(identifiers)..meta.addAll(meta)))
40+
..headers.addAll(headers)));
4341

4442
/// Creates a new resource with the given [type] and [id] on the server.
4543
///
@@ -61,21 +59,19 @@ class RoutingClient {
6159
Map<String, Object?> documentMeta = const {},
6260
Map<String, List<String>> headers = const {},
6361
Iterable<QueryEncodable> query = const [],
64-
}) async {
65-
final response = await send(
66-
_baseUri.collection(type),
67-
Request.post(OutboundDataDocument.resource(Resource(type, id)
68-
..attributes.addAll(attributes)
69-
..relationships.addAll({
70-
...one.map((key, value) => MapEntry(key, ToOne(value))),
71-
...many.map((key, value) => MapEntry(key, ToMany(value))),
72-
})
73-
..meta.addAll(meta))
74-
..meta.addAll(documentMeta))
75-
..headers.addAll(headers)
76-
..query.mergeAll(query));
77-
return ResourceUpdated(response.httpResponse, response.document);
78-
}
62+
}) async =>
63+
ResourceUpdated(await send(
64+
_baseUri.collection(type),
65+
Request.post(OutboundDataDocument.resource(Resource(type, id)
66+
..attributes.addAll(attributes)
67+
..relationships.addAll({
68+
...one.map((key, value) => MapEntry(key, ToOne(value))),
69+
...many.map((key, value) => MapEntry(key, ToMany(value))),
70+
})
71+
..meta.addAll(meta))
72+
..meta.addAll(documentMeta))
73+
..headers.addAll(headers)
74+
..query.mergeAll(query)));
7975

8076
/// Creates a new resource in the collection of type [type].
8177
/// The server is responsible for assigning the resource id.
@@ -99,24 +95,20 @@ class RoutingClient {
9995
Map<String, Object?> documentMeta = const {},
10096
Map<String, List<String>> headers = const {},
10197
Iterable<QueryEncodable> query = const [],
102-
}) async {
103-
final response = await send(
104-
_baseUri.collection(type),
105-
Request.post(
106-
OutboundDataDocument.newResource(NewResource(type, lid: lid)
107-
..attributes.addAll(attributes)
108-
..relationships.addAll({
109-
...one.map((key, value) => MapEntry(key, NewToOne(value))),
110-
...many.map((key, value) => MapEntry(key, NewToMany(value))),
111-
})
112-
..meta.addAll(meta))
113-
..meta.addAll(documentMeta))
114-
..headers.addAll(headers)
115-
..query.mergeAll(query));
116-
117-
return ResourceCreated(
118-
response.httpResponse, response.document ?? (throw FormatException()));
119-
}
98+
}) async =>
99+
ResourceCreated(await send(
100+
_baseUri.collection(type),
101+
Request.post(
102+
OutboundDataDocument.newResource(NewResource(type, lid: lid)
103+
..attributes.addAll(attributes)
104+
..relationships.addAll({
105+
...one.map((key, value) => MapEntry(key, NewToOne(value))),
106+
...many.map((key, value) => MapEntry(key, NewToMany(value))),
107+
})
108+
..meta.addAll(meta))
109+
..meta.addAll(documentMeta))
110+
..headers.addAll(headers)
111+
..query.mergeAll(query)));
120112

121113
/// Deletes the [identifiers] from the to-many relationship
122114
/// identified by [type], [id], [relationship].
@@ -131,15 +123,12 @@ class RoutingClient {
131123
List<Identifier> identifiers, {
132124
Map<String, Object?> meta = const {},
133125
Map<String, List<String>> headers = const {},
134-
}) async {
135-
final response = await send(
136-
_baseUri.relationship(type, id, relationship),
137-
Request.delete(
138-
OutboundDataDocument.many(ToMany(identifiers)..meta.addAll(meta)))
139-
..headers.addAll(headers));
140-
141-
return RelationshipUpdated.many(response.httpResponse, response.document);
142-
}
126+
}) async =>
127+
RelationshipUpdated.many(await send(
128+
_baseUri.relationship(type, id, relationship),
129+
Request.delete(
130+
OutboundDataDocument.many(ToMany(identifiers)..meta.addAll(meta)))
131+
..headers.addAll(headers)));
143132

144133
/// Fetches the primary collection of type [type].
145134
///
@@ -150,15 +139,12 @@ class RoutingClient {
150139
String type, {
151140
Map<String, List<String>> headers = const {},
152141
Iterable<QueryEncodable> query = const [],
153-
}) async {
154-
final response = await send(
155-
_baseUri.collection(type),
156-
Request.get()
157-
..headers.addAll(headers)
158-
..query.mergeAll(query));
159-
return CollectionFetched(
160-
response.httpResponse, response.document ?? (throw FormatException()));
161-
}
142+
}) async =>
143+
CollectionFetched(await send(
144+
_baseUri.collection(type),
145+
Request.get()
146+
..headers.addAll(headers)
147+
..query.mergeAll(query)));
162148

163149
/// Fetches the related resource collection
164150
/// identified by [type], [id], [relationship].
@@ -172,15 +158,12 @@ class RoutingClient {
172158
String relationship, {
173159
Map<String, List<String>> headers = const {},
174160
Iterable<QueryEncodable> query = const [],
175-
}) async {
176-
final response = await send(
177-
_baseUri.related(type, id, relationship),
178-
Request.get()
179-
..headers.addAll(headers)
180-
..query.mergeAll(query));
181-
return CollectionFetched(
182-
response.httpResponse, response.document ?? (throw FormatException()));
183-
}
161+
}) async =>
162+
CollectionFetched(await send(
163+
_baseUri.related(type, id, relationship),
164+
Request.get()
165+
..headers.addAll(headers)
166+
..query.mergeAll(query)));
184167

185168
/// Fetches the to-one relationship
186169
/// identified by [type], [id], [relationship].
@@ -194,15 +177,12 @@ class RoutingClient {
194177
String relationship, {
195178
Map<String, List<String>> headers = const {},
196179
Iterable<QueryEncodable> query = const [],
197-
}) async {
198-
final response = await send(
199-
_baseUri.relationship(type, id, relationship),
200-
Request.get()
201-
..headers.addAll(headers)
202-
..query.mergeAll(query));
203-
return RelationshipFetched.one(
204-
response.httpResponse, response.document ?? (throw FormatException()));
205-
}
180+
}) async =>
181+
RelationshipFetched.one(await send(
182+
_baseUri.relationship(type, id, relationship),
183+
Request.get()
184+
..headers.addAll(headers)
185+
..query.mergeAll(query)));
206186

207187
/// Fetches the to-many relationship
208188
/// identified by [type], [id], [relationship].
@@ -216,15 +196,12 @@ class RoutingClient {
216196
String relationship, {
217197
Map<String, List<String>> headers = const {},
218198
Iterable<QueryEncodable> query = const [],
219-
}) async {
220-
final response = await send(
221-
_baseUri.relationship(type, id, relationship),
222-
Request.get()
223-
..headers.addAll(headers)
224-
..query.mergeAll(query));
225-
return RelationshipFetched.many(
226-
response.httpResponse, response.document ?? (throw FormatException()));
227-
}
199+
}) async =>
200+
RelationshipFetched.many(await send(
201+
_baseUri.relationship(type, id, relationship),
202+
Request.get()
203+
..headers.addAll(headers)
204+
..query.mergeAll(query)));
228205

229206
/// Fetches the related resource
230207
/// identified by [type], [id], [relationship].
@@ -238,15 +215,12 @@ class RoutingClient {
238215
String relationship, {
239216
Map<String, List<String>> headers = const {},
240217
Iterable<QueryEncodable> query = const [],
241-
}) async {
242-
final response = await send(
243-
_baseUri.related(type, id, relationship),
244-
Request.get()
245-
..headers.addAll(headers)
246-
..query.mergeAll(query));
247-
return RelatedResourceFetched(
248-
response.httpResponse, response.document ?? (throw FormatException()));
249-
}
218+
}) async =>
219+
RelatedResourceFetched(await send(
220+
_baseUri.related(type, id, relationship),
221+
Request.get()
222+
..headers.addAll(headers)
223+
..query.mergeAll(query)));
250224

251225
/// Fetches the resource identified by [type] and [id].
252226
///
@@ -258,16 +232,12 @@ class RoutingClient {
258232
String id, {
259233
Map<String, List<String>> headers = const {},
260234
Iterable<QueryEncodable> query = const [],
261-
}) async {
262-
final response = await send(
263-
_baseUri.resource(type, id),
264-
Request.get()
265-
..headers.addAll(headers)
266-
..query.mergeAll(query));
267-
268-
return ResourceFetched(
269-
response.httpResponse, response.document ?? (throw FormatException()));
270-
}
235+
}) async =>
236+
ResourceFetched(await send(
237+
_baseUri.resource(type, id),
238+
Request.get()
239+
..headers.addAll(headers)
240+
..query.mergeAll(query)));
271241

272242
/// Updates the resource identified by [type] and [id].
273243
///
@@ -289,21 +259,19 @@ class RoutingClient {
289259
Map<String, Object?> documentMeta = const {},
290260
Map<String, List<String>> headers = const {},
291261
Iterable<QueryEncodable> query = const [],
292-
}) async {
293-
final response = await send(
294-
_baseUri.resource(type, id),
295-
Request.patch(OutboundDataDocument.resource(Resource(type, id)
296-
..attributes.addAll(attributes)
297-
..relationships.addAll({
298-
...one.map((key, value) => MapEntry(key, ToOne(value))),
299-
...many.map((key, value) => MapEntry(key, ToMany(value))),
300-
})
301-
..meta.addAll(meta))
302-
..meta.addAll(documentMeta))
303-
..headers.addAll(headers)
304-
..query.mergeAll(query));
305-
return ResourceUpdated(response.httpResponse, response.document);
306-
}
262+
}) async =>
263+
ResourceUpdated(await send(
264+
_baseUri.resource(type, id),
265+
Request.patch(OutboundDataDocument.resource(Resource(type, id)
266+
..attributes.addAll(attributes)
267+
..relationships.addAll({
268+
...one.map((key, value) => MapEntry(key, ToOne(value))),
269+
...many.map((key, value) => MapEntry(key, ToMany(value))),
270+
})
271+
..meta.addAll(meta))
272+
..meta.addAll(documentMeta))
273+
..headers.addAll(headers)
274+
..query.mergeAll(query)));
307275

308276
/// Replaces the to-one relationship
309277
/// identified by [type], [id], and [relationship] by setting
@@ -321,15 +289,13 @@ class RoutingClient {
321289
Map<String, Object?> meta = const {},
322290
Map<String, List<String>> headers = const {},
323291
Iterable<QueryEncodable> query = const [],
324-
}) async {
325-
final response = await send(
326-
_baseUri.relationship(type, id, relationship),
327-
Request.patch(
328-
OutboundDataDocument.one(ToOne(identifier)..meta.addAll(meta)))
329-
..headers.addAll(headers)
330-
..query.mergeAll(query));
331-
return RelationshipUpdated.one(response.httpResponse, response.document);
332-
}
292+
}) async =>
293+
RelationshipUpdated.one(await send(
294+
_baseUri.relationship(type, id, relationship),
295+
Request.patch(
296+
OutboundDataDocument.one(ToOne(identifier)..meta.addAll(meta)))
297+
..headers.addAll(headers)
298+
..query.mergeAll(query)));
333299

334300
/// Replaces the to-many relationship
335301
/// identified by [type], [id], and [relationship] by setting
@@ -347,15 +313,13 @@ class RoutingClient {
347313
Map<String, Object?> meta = const {},
348314
Map<String, List<String>> headers = const {},
349315
Iterable<QueryEncodable> query = const [],
350-
}) async {
351-
final response = await send(
352-
_baseUri.relationship(type, id, relationship),
353-
Request.patch(
354-
OutboundDataDocument.many(ToMany(identifiers)..meta.addAll(meta)))
355-
..headers.addAll(headers)
356-
..query.mergeAll(query));
357-
return RelationshipUpdated.many(response.httpResponse, response.document);
358-
}
316+
}) async =>
317+
RelationshipUpdated.many(await send(
318+
_baseUri.relationship(type, id, relationship),
319+
Request.patch(
320+
OutboundDataDocument.many(ToMany(identifiers)..meta.addAll(meta)))
321+
..headers.addAll(headers)
322+
..query.mergeAll(query)));
359323

360324
/// Removes the to-one relationship
361325
/// identified by [type], [id], and [relationship]..
@@ -369,14 +333,12 @@ class RoutingClient {
369333
String relationship, {
370334
Map<String, List<String>> headers = const {},
371335
Iterable<QueryEncodable> query = const [],
372-
}) async {
373-
final response = await send(
374-
_baseUri.relationship(type, id, relationship),
375-
Request.patch(OutboundDataDocument.one(ToOne.empty()))
376-
..headers.addAll(headers)
377-
..query.mergeAll(query));
378-
return RelationshipUpdated.one(response.httpResponse, response.document);
379-
}
336+
}) async =>
337+
RelationshipUpdated.one(await send(
338+
_baseUri.relationship(type, id, relationship),
339+
Request.patch(OutboundDataDocument.one(ToOne.empty()))
340+
..headers.addAll(headers)
341+
..query.mergeAll(query)));
380342

381343
/// Deletes the resource identified by [type] and [id].
382344
///
@@ -399,9 +361,7 @@ class RoutingClient {
399361
/// This method can be used to send any non-standard requests.
400362
Future<Response> send(Uri uri, Request request) async {
401363
final response = await _client.send(uri, request);
402-
if (response.isFailed) {
403-
throw RequestFailure(response.httpResponse, response.document);
404-
}
364+
if (response.isFailed) throw RequestFailure(response);
405365
return response;
406366
}
407367
}

‎test/contract/crud_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ void main() {
4747
Include(['author', 'comments', 'comments.author'])
4848
]);
4949

50-
expect(response.httpResponse.statusCode, 200);
50+
expect(response.rawResponse.httpResponse.statusCode, 200);
5151
expect(response.collection.length, 1);
5252
expect(response.included.length, 3);
5353

@@ -175,7 +175,7 @@ void main() {
175175
await action();
176176
fail('Exception expected');
177177
} on RequestFailure catch (e) {
178-
expect(e.httpResponse.statusCode, 404);
178+
expect(e.rawResponse.httpResponse.statusCode, 404);
179179
}
180180
}
181181
});

‎test/contract/resource_creation_test.dart

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ void main() {
1616
test('Resource id assigned on the server', () async {
1717
await client
1818
.createNew('posts', attributes: {'title': 'Hello world'}).then((r) {
19-
expect(r.httpResponse.statusCode, 201);
20-
expect(r.httpResponse.headers['location'], ['/posts/${r.resource.id}']);
19+
expect(r.rawResponse.httpResponse.statusCode, 201);
20+
expect(r.rawResponse.httpResponse.headers['location'],
21+
['/posts/${r.resource.id}']);
2122
expect(r.links['self'].toString(), '/posts/${r.resource.id}');
2223
expect(r.resource.type, 'posts');
2324
expect(r.resource.attributes['title'], 'Hello world');
@@ -30,8 +31,9 @@ void main() {
3031
lid: 'lid',
3132
attributes: {'title': 'Hello world'},
3233
one: {'self': LocalIdentifier('posts', 'lid')}).then((r) {
33-
expect(r.httpResponse.statusCode, 201);
34-
expect(r.httpResponse.headers['location'], ['/posts/${r.resource.id}']);
34+
expect(r.rawResponse.httpResponse.statusCode, 201);
35+
expect(r.rawResponse.httpResponse.headers['location'],
36+
['/posts/${r.resource.id}']);
3537
expect(r.links['self'].toString(), '/posts/${r.resource.id}');
3638
expect(r.resource.type, 'posts');
3739
expect(r.resource.attributes['title'], 'Hello world');
@@ -42,9 +44,9 @@ void main() {
4244
test('Resource id assigned on the client', () async {
4345
await client.create('posts', '12345',
4446
attributes: {'title': 'Hello world'}).then((r) {
45-
expect(r.httpResponse.statusCode, 204);
47+
expect(r.rawResponse.httpResponse.statusCode, 204);
4648
expect(r.resource, isNull);
47-
expect(r.httpResponse.headers['location'], isNull);
49+
expect(r.rawResponse.httpResponse.headers['location'], isNull);
4850
});
4951
});
5052
});

‎test/e2e/e2e_test_set.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ void testLocationIsSet(RoutingClient Function() client) {
3030
test('Location is set', () async {
3131
final r = await client()
3232
.createNew('posts', attributes: {'title': 'Location test'});
33-
expect(r.httpResponse.headers['Location'], isNotEmpty);
33+
expect(r.rawResponse.httpResponse.headers['Location'], isNotEmpty);
3434
await client().deleteResource('posts', r.resource.id);
3535
});
3636
}

‎test/unit/client/client_test.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ void main() {
2222
await client.fetchCollection('articles');
2323
fail('Exception expected');
2424
} on RequestFailure catch (e) {
25-
expect(e.httpResponse.statusCode, 422);
25+
expect(e.rawResponse.httpResponse.statusCode, 422);
2626
expect(e.errors.first.status, '422');
2727
expect(e.errors.first.title, 'Invalid Attribute');
2828
}
@@ -33,7 +33,7 @@ void main() {
3333
await client.fetchCollection('articles');
3434
fail('Exception expected');
3535
} on RequestFailure catch (e) {
36-
expect(e.httpResponse.statusCode, 500);
36+
expect(e.rawResponse.httpResponse.statusCode, 500);
3737
}
3838
});
3939
});
@@ -558,7 +558,7 @@ void main() {
558558
'articles', '1', 'author', Identifier('people', '42'));
559559
fail('Exception expected');
560560
} on RequestFailure catch (e) {
561-
expect(e.httpResponse.statusCode, 422);
561+
expect(e.rawResponse.httpResponse.statusCode, 422);
562562
expect(e.errors.first.status, '422');
563563
}
564564
});
@@ -615,7 +615,7 @@ void main() {
615615
await client.deleteToOne('articles', '1', 'author');
616616
fail('Exception expected');
617617
} on RequestFailure catch (e) {
618-
expect(e.httpResponse.statusCode, 422);
618+
expect(e.rawResponse.httpResponse.statusCode, 422);
619619
expect(e.errors.first.status, '422');
620620
}
621621
});
@@ -680,7 +680,7 @@ void main() {
680680
.deleteFromMany('articles', '1', 'tags', [Identifier('tags', '1')]);
681681
fail('Exception expected');
682682
} on RequestFailure catch (e) {
683-
expect(e.httpResponse.statusCode, 422);
683+
expect(e.rawResponse.httpResponse.statusCode, 422);
684684
expect(e.errors.first.status, '422');
685685
}
686686
});
@@ -747,7 +747,7 @@ void main() {
747747
.replaceToMany('articles', '1', 'tags', [Identifier('tags', '1')]);
748748
fail('Exception expected');
749749
} on RequestFailure catch (e) {
750-
expect(e.httpResponse.statusCode, 422);
750+
expect(e.rawResponse.httpResponse.statusCode, 422);
751751
expect(e.errors.first.status, '422');
752752
}
753753
});
@@ -814,7 +814,7 @@ void main() {
814814
.addMany('articles', '1', 'tags', [Identifier('tags', '1')]);
815815
fail('Exception expected');
816816
} on RequestFailure catch (e) {
817-
expect(e.httpResponse.statusCode, 422);
817+
expect(e.rawResponse.httpResponse.statusCode, 422);
818818
expect(e.errors.first.status, '422');
819819
expect(e.toString(), contains('422'));
820820
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import 'package:http_interop/http_interop.dart' as i;
2+
import 'package:json_api/client.dart';
3+
import 'package:json_api/src/client/response.dart';
4+
import 'package:test/expect.dart';
5+
import 'package:test/scaffolding.dart';
6+
7+
void main() {
8+
final emptyResponse = Response(i.Response(200, i.Body(), i.Headers()), null);
9+
group('CollectionFetched', () {
10+
test('throws on empty body', () {
11+
expect(() => CollectionFetched(emptyResponse), throwsFormatException);
12+
});
13+
});
14+
15+
group('RelatedResourceFetched', () {
16+
test('throws on empty body', () {
17+
expect(
18+
() => RelatedResourceFetched(emptyResponse), throwsFormatException);
19+
});
20+
});
21+
22+
group('RelationshipFetched', () {
23+
test('.many() throws on empty body', () {
24+
expect(
25+
() => RelationshipFetched.many(emptyResponse), throwsFormatException);
26+
});
27+
28+
test('.one() throws on empty body', () {
29+
expect(
30+
() => RelationshipFetched.one(emptyResponse), throwsFormatException);
31+
});
32+
});
33+
34+
group('ResourceCreated', () {
35+
test('throws on empty body', () {
36+
expect(() => ResourceCreated(emptyResponse), throwsFormatException);
37+
});
38+
});
39+
40+
group('ResourceFetched', () {
41+
test('throws on empty body', () {
42+
expect(() => ResourceFetched(emptyResponse), throwsFormatException);
43+
});
44+
});
45+
}

0 commit comments

Comments
 (0)
Please sign in to comment.