docs(toh-6/dart): getHero makes HTTP get-by-id (#2936)
Dart follow-up to #2906
This commit is contained in:
parent
bc416b8e0f
commit
499d4b3c88
|
@ -15,7 +15,7 @@ class HeroService {
|
|||
static final _headers = {'Content-Type': 'application/json'};
|
||||
// #enddocregion update
|
||||
// #docregion getHeroes
|
||||
static const _heroesUrl = 'app/heroes'; // URL to web API
|
||||
static const _heroesUrl = 'api/heroes'; // URL to web API
|
||||
|
||||
final Client _http;
|
||||
|
||||
|
@ -46,8 +46,16 @@ class HeroService {
|
|||
}
|
||||
// #enddocregion handleError, getHeroes
|
||||
|
||||
Future<Hero> getHero(int id) async =>
|
||||
(await getHeroes()).firstWhere((hero) => hero.id == id);
|
||||
// #docregion getHero
|
||||
Future<Hero> getHero(int id) async {
|
||||
try {
|
||||
final response = await _http.get('$_heroesUrl/$id');
|
||||
return new Hero.fromJson(_extractData(response));
|
||||
} catch (e) {
|
||||
throw _handleError(e);
|
||||
}
|
||||
}
|
||||
// #enddocregion getHero
|
||||
|
||||
// #docregion create
|
||||
Future<Hero> create(String name) async {
|
||||
|
@ -64,7 +72,7 @@ class HeroService {
|
|||
|
||||
Future<Hero> update(Hero hero) async {
|
||||
try {
|
||||
var url = '$_heroesUrl/${hero.id}';
|
||||
final url = '$_heroesUrl/${hero.id}';
|
||||
final response =
|
||||
await _http.put(url, headers: _headers, body: JSON.encode(hero));
|
||||
return new Hero.fromJson(_extractData(response));
|
||||
|
@ -77,7 +85,7 @@ class HeroService {
|
|||
// #docregion delete
|
||||
Future<Null> delete(int id) async {
|
||||
try {
|
||||
var url = '$_heroesUrl/$id';
|
||||
final url = '$_heroesUrl/$id';
|
||||
await _http.delete(url, headers: _headers);
|
||||
} catch (e) {
|
||||
throw _handleError(e);
|
||||
|
|
|
@ -31,9 +31,14 @@ class InMemoryDataService extends MockClient {
|
|||
var data;
|
||||
switch (request.method) {
|
||||
case 'GET':
|
||||
String prefix = request.url.queryParameters['name'] ?? '';
|
||||
final regExp = new RegExp(prefix, caseSensitive: false);
|
||||
data = _heroesDb.where((hero) => hero.name.contains(regExp)).toList();
|
||||
final id = int.parse(request.url.pathSegments.last, onError: (_) => null);
|
||||
if (id != null) {
|
||||
data = _heroesDb.firstWhere((hero) => hero.id == id); // throws if no match
|
||||
} else {
|
||||
String prefix = request.url.queryParameters['name'] ?? '';
|
||||
final regExp = new RegExp(prefix, caseSensitive: false);
|
||||
data = _heroesDb.where((hero) => hero.name.contains(regExp)).toList();
|
||||
}
|
||||
break;
|
||||
// #enddocregion init-disabled
|
||||
case 'POST':
|
||||
|
|
|
@ -212,12 +212,32 @@ block get-heroes-details
|
|||
We've also decided to return a user friendly form of the error to
|
||||
the caller in a !{rejected_promise} so that the caller can display a proper error message to the user.
|
||||
|
||||
### Unchanged `getHeroes` API
|
||||
### Get hero by id
|
||||
The `HeroDetailComponent` asks the `HeroService` to fetch a single hero to edit.
|
||||
|
||||
Although we made significant *internal* changes to `getHeroes()`, the public signature did not change.
|
||||
We still return a !{_Promise}. We won't have to update any of the components that call `getHeroes()`.
|
||||
The `HeroService` currently fetches all heroes and then finds the desired hero
|
||||
by filtering for the one with the matching `id`.
|
||||
That's fine in a simulation. It's wasteful to ask a real server for _all_ heroes when we only want one.
|
||||
Most web APIs support a _get-by-id_ request in the form `api/hero/:id` (e.g., `api/hero/11`).
|
||||
|
||||
Our stakeholders are thrilled with the added flexibility from the API integration.
|
||||
Update the `HeroService.getHero` method to make a _get-by-id_ request,
|
||||
applying what we just learned to write `getHeroes`:
|
||||
+makeExcerpt('app/hero.service.ts', 'getHero', '')
|
||||
:marked
|
||||
It's almost the same as `getHeroes`.
|
||||
The URL identifies _which_ hero the server should update by encoding the hero id into the URL
|
||||
to match the `api/hero/:id` pattern.
|
||||
|
||||
We also adjust to the fact that the `data` in the response is a single hero object rather than !{_an} !{_array}.
|
||||
|
||||
### Unchanged _getHeroes_ API
|
||||
|
||||
Although we made significant *internal* changes to `getHeroes()` and `getHero()`,
|
||||
the public signatures did not change.
|
||||
We still return a !{_Promise} from both methods.
|
||||
We won't have to update any of the components that call them.
|
||||
|
||||
Our stakeholders are thrilled with the web API integration so far.
|
||||
Now they want the ability to create and delete heroes.
|
||||
|
||||
Let's see first what happens when we try to update a hero's details.
|
||||
|
@ -230,15 +250,12 @@ block get-heroes-details
|
|||
it. As we type, the hero name is updated in the view heading.
|
||||
But when we hit the `Back` button, the changes are lost!
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
Updates weren't lost before, what's happening?
|
||||
When the app used a list of mock heroes, changes were made directly to the
|
||||
hero objects in the single, app-wide shared list. Now that we are fetching data
|
||||
from a server, if we want changes to persist, we'll need to write them back to
|
||||
the server.
|
||||
Updates weren't lost before. What changed?
|
||||
When the app used a list of mock heroes, updates were applied directly to the
|
||||
hero objects within the single, app-wide, shared list. Now that we are fetching data
|
||||
from a server, if we want changes to persist, we'll need to write them back to
|
||||
the server.
|
||||
|
||||
:marked
|
||||
### Save hero details
|
||||
|
||||
Let's ensure that edits to a hero's name aren't lost. Start by adding,
|
||||
|
|
|
@ -228,7 +228,7 @@ block get-heroes-details
|
|||
The URL identifies _which_ hero the server should update by encoding the hero id into the URL
|
||||
to match the `api/hero/:id` pattern.
|
||||
|
||||
We also adjust to the fact that the `data` in the response is a single hero object rather than array.
|
||||
We also adjust to the fact that the `data` in the response is a single hero object rather than !{_an} !{_array}.
|
||||
|
||||
### Unchanged _getHeroes_ API
|
||||
|
||||
|
|
Loading…
Reference in New Issue