Now, after we have developed both forms – for importing existing and adding new developers, it is time to implement the logic behind them in the controller of the component.
For this purpose, we will need to communicate with the GitHub API. Although we can do this directly from the component's controller, by approaching the problem this way, we would couple the component with the RESTful API of GitHub. In order to enforce better separation of concerns, we can extract the logic for communication with GitHub into a separate service called GitHubGateway
. Open the file called github_gateway.ts
, and enter the following content:
import {Injectable} from '@angular/core'; import {Http} from '@angular/http'; @Injectable() export class GitHubGateway { constructor(private http: Http) {} getUser(username: string) { return this.http .get(`https://api.github.com/users/${username}`); } }
Initially, we import the Http
class from the @angular/http
module. All the HTTP-related functionalities are externalized and are outside the Angular's core. Since GitHubGateway
accepts a dependency, which needs to be injected through the DI mechanism of the framework, we will decorate it with the @Injectable
decorator.
The only functionality from the GitHub's API we use is the one for fetching users, so we define a single method called getUser
. As an argument, it accepts the GitHub handle of the developer.
Note that, if you make more than 60 requests per day to the GitHub's API, you might get the error GitHub API Rate limit exceeded. This is due to the rate limits for requests without a GitHub API token. For further information, visit https://github.com/blog/1509-personal-api-tokens .
Inside the getUser
method, we use the instance of the Http
service that we received in the constructor
. The Http
service's API stays as close to the HTML5 fetch API as possible. However, there are a couple of differences. The most significant one of them is that, at the moment of writing this content, all the methods of the Http
instances return Observables
instead of Promises
.
The Http
service instances have the following API:
request(url: string | Request, options: RequestOptionsArgs)
: This makes a request to the specified URL. The request can be configured using RequestOptionsArgs
, as follows:http.request('http://example.com/', { method: 'get', search: 'foo=bar', headers: new Headers({ 'X-Custom-Header': 'Hello' }) });
get(url: string, options?: RequestOptionsArgs)
: This makes a get request to the specified URL. The request headers and other options can be configured using the second argument.post(url: string, options?: RequestOptionsArgs)
: This makes a post request to the specified URL. The request body, headers, and other options can be configured using the second argument.put(url: string, options?: RequestOptionsArgs)
: This makes a put request to the specified URL. The request headers and other options can be configured using the second argument.patch(url: string, options?: RequestOptionsArgs)
: This makes a patch request to the specified URL. The request headers and other options can be configured using the second argument.delete(url: string, options?: RequestOptionsArgs)
: This makes a delete request to the specified URL. The request headers and other options can be configured using the second argument.head(url: string, options?: RequestOptionsArgs)
: This makes a head request to the specified URL. The request headers and other options can be configured using the second argument.Now, let's implement the logic for importing the existing developers from GitHub. First, we will need to import the HttpModule
in our AppModule
:
import {HttpModule} from '@angular/http'; ... @NgModule({ imports: [..., HttpModule], declarations: [...], providers: [...], bootstrap: [...] }) class AppModule {} ...
After that, open the ch6/ts/step-2/add_developer.ts
file and enter the following imports:
import {Response} from '@angular/http'; import {GitHubGateway} from './github_gateway';
Add GitHubGateway
to the list of providers of the AddDeveloper
component:
@Component({ ... providers: [GitHubGateway] }) class AddDeveloper {...}
As the next step, we have to include the following parameters in the constructor of the class:
constructor(private githubAPI: GitHubGateway, private developers: DeveloperCollection, fb: FormBuilder) { //... }
This way, the AddDeveloper
class' instances will have a private property called githubAPI
.
The only thing left is to implement the addDeveloper
method and allow the user to import the existing developers using the GitHubGateway
instance.
Once the user presses the Add button, we will need to check whether we need to import an existing GitHub user or add a new developer. For this purpose, we can use the value of the fetchFromGitHub
control:
if (this.importDevForm.controls['fetchFromGitHub'].value) { // Import developer } else { // Add new developer }
If it has a truthy value, then we can invoke the getUser
method of the githubAPI
property and pass the value of the githubHandle
control as an argument:
this.githubAPI.getUser(model.githubHandle)
In the getUser
method of the GitHubGateway
instance, we delegate the call to the Http
service's get
method, which returns an observable. In order to get the result that the observable will push, we will need to pass a callback to its subscribe
method:
this.githubAPI.getUser(model.githubHandle) .map((r: Response) => r.json()) .subscribe((res: any) => { // "res" contains the response of the GitHub's API });
In the preceding snippet, we first establish the HTTP get
request. After this, we get the corresponding observable that, in general cases, will emit a series of values (in this case, only a single one-the response of the request) and map them to their JSON representations. If the request fails, or the response's body is not a valid JSON string, then we will get an error.
Note that, in order to reduce the bundle size of Angular, the team at Google has included only the core of RxJS in the framework. In order to use the map
and catch
methods, you will need to add the following imports at add_developer.ts
:
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
Now, let's implement the body of the callback we pass to subscribe
:
let dev = new Developer(); dev.githubHandle = res.login; dev.email = res.email; dev.popular = res.followers >= 1000; dev.realName = res.name; dev.id = res.id; dev.avatarUrl = res.avatar_url; this.developers.addDeveloper(dev); this.successMessage = `Developer ${dev.githubHandle} successfully imported from GitHub`;
In the preceding example, we set the properties of a new Developer
instance. Here, we establish the mapping between the object returned from GitHub's API and the developer's representation in our application. We consider a developer as popular if they have more than 1,000 followers.
The entire implementation of the addDeveloper
method can be found at ch7/ts/multi-page-model-driven/add_developer.ts
.