blank

Como usar API REST com HttpClient no Angular 8?

Como usar API REST com HttpClient no Angular 8?

22 de janeiro de 2020 1 Por Ramos de Souza Janones
Powered by Rock Convert

Neste tutorial passo a passo vamos aprender a consumir API REST no Angular 8 usando o serviço HttpClient com um exemplo prático.

Requisitos
Para exemplificar o uso do HttpClient vamos criar um projeto angular, o projeto será um CRUD para nos ajudar de forma simples e básica a manipular carros, também criaremos uma API REST fake, essa api fake vai simular nosso back-end, assim focaremos no uso do HttpClient, então para isso vamos precisar de algumas tecnologias

Angular 8 HttpClient

HttpClient é usado para fazer a comunicação entre cliente e servidor usando o protocolo HTTP. Ou seja, se você está querendo consumir dados de uma API externa o HttpClient facilitará essa comunicação, através de muitos métodos disponíveis:
post()
get()
put()
delete()
patch()
request()
head()

jsonp()
options()

Beneficios do HttpClient

HttpClient usa a interface XMLHttpRequest que também suporta a navegadores antigos, além de fácil de usar disponibiliza benefícios, como:
Solicitações de request e response interceptadas
Manipulação de erros simplificada
Suporte a api Observable
APIs e tratamentos de erros

Instalando o Angula CLI

O projeto será criado usado o angular CLI, então para seguimos com o tutorial, temos que tê-lo instalado em nossa maquina. Levando em consideração que temos o Node.js instalado, basta executar o seguinte comando:

sudo npm install -g @angular/cli

Criando projeto angular 8

Com o angular CLI e o Node.js instalado, vamos criar o nosso projeto angular usando o CLI, para isso execute o comando abaixo no seu terminal:

ng new angular-http

Após executar o comando acima, o angular CLI fará algumas perguntas, na primeira digite “y” para criar o projeto com rota, em seguida escolha a opção CSS como formato de folha de estilo, isso criará o nosso projeto com os módulos NPM necessários.

Leia também:  

Rodando o projeto angular 8

Após criar o projeto, precisamos rodar e verificar se tudo foi criado corretamente, então entre na pasta do projeto e digite:

ng serve --open

O comando acima rodará o nosso projeto, e o parâmetro --open abrirá automaticamente o browser com o nosso projeto angular 8 em execução, como na imagem abaixo.

Tela do angular 8 em execução

Consumindo rest api com Angular 8

Criando uma API REST fake

Para simular o uso do HttpClient, precisamos de uma API REST, como o foco é o HttpClient não vamos nos preocupar em criar uma API REST, para isso podemos usar o json-server, que faz uma API REST fake, assim focaremos no HttpClient.
Para mais detalhes sobre o json-server, podemos consultar seu github.

Para instalar o json-server, bastar executar o seguinte comando:

sudo npm install -g json-server

Dento do nosso projeto, vamos criar uma pasta chamada “data” dentro de “assets”

/src/assets/data

Agora crie um arquivo chamado db.json e jogue dentro da pasta “data” que acabamos de criar:

/src/assets/data/db.json

Vamos abrir o arquivo db.json e incluir o seguinte json:

{
  "cars": [
    {
      "id": 1,
      "model": "BMW X7",
      "color": "Preto",
      "price": 455.95
    },
    {
      "id": 2,
      "model": "Mercedes benz c180",
      "color": "Azul",
      "price": 194.9
    },
    {
      "id": 3,
      "model": "Land Rover Range Rover Velar",
      "color": "Branco",
      "price": 377.38
    }
  ]
}

Arquivo db.json para o json-server

Nossa estrutura de pastas e o arquivo db.json ficará assim:

Estrutura de pastas com o arquivo db.json

Vamos rodar o json-server para simular nossa API REST, abra um novo terminal e na raiz do projeto execute o seguinte comando:

json-server --watch src/assets/data/db.json
json-server em execução

json-server em execução

Tudo funcionará como na imagem acima, observe que nossa API REST fake está exposta no endereço: http://localhost:3000

Configurando o HttpClient

Para usar o HttpClient, precisamos adicionar o modulo HttpClientModule no arquivo app.module.ts.
Para fazer isso, vamos abrir o arquivo app.module.ts

src/app/app.module.ts

Dentro de imports do decorator @NgModule, adicione o modulo HttpClientModule

Vamos nos atentar para não usar o pacote @angular/http, esse pacote estava depreciado desde a versão 5 do angular, no angular 8 ele foi removido, o pacote que utilizaremos é @angular/common/http.

Vamos aproveitar e adicionar o modulo FormsMoule, esse modulo nos ajudará em nosso formulário para nossa tela de exemplo, porém não é necessário para o uso do HttpClient. O resultado do arquivo app.module.ts será:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

 

Criando o model

export interface Car {
    id: number;
    model: string;
    color: string;
    price: number;
}

 

Como vender Software - Seja desktop, web ou MobilePowered by Rock Convert

Vamos criar uma interface de modelo para os dados dos carros. Na raiz do projeto vamos executando o seguinte comando:

ng g interface models/car

O parâmetro g é uma abreviação de generate.
Será criado 2 arquivos dentro de uma pasta com o nome models, o arquivo car.spec.ts é um arquivo de teste, o segundo é o car.tso model que representará nosso carro.
Para não criar o arquivo de teste, é só usar o parâmetro --skipTests=true
Agora vamos adicionar o seguinte conteúdo dentro de nosso model car.ts

export interface Car {
    id: number;
    model: string;
    color: string;
    price: number;
}

Criando o serviço responsável pelas requisições http

Vamos criar os métodos responsáveis pelas requisições http que faremos no json-server usando o HttpClient, mas antes devemos criar um arquivo service, no angular é recomendado criar services para os métodos que faz chamadas http.
Para criar o serviço, digite o seguinte comando:

ng g service services/car

O comando acima, criará um arquivo com o nome car.services.ts dentro da pasta services. Após criar nosso service, já podemos começar a utilizar o HttpClient

Usando o HttpClient

Dentro do nosso service car.services.ts, vamos criar alguns métodos http utilizando o HttpClient.
Abra o arquivo car.services.ts dentro da pasta services e inclua o seguinte código:

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { retry, catchError } from 'rxjs/operators';
import { Car } from '../models/car';

@Injectable({
  providedIn: 'root'
})
export class CarService {

  url = 'http://localhost:3000/cars'; // api rest fake

  // injetando o HttpClient
  constructor(private httpClient: HttpClient) { }

  // Headers
  httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/json' })
  }

  // Obtem todos os carros
  getCars(): Observable<Car[]> {
    return this.httpClient.get<Car[]>(this.url)
      .pipe(
        retry(2),
        catchError(this.handleError))
  }

  // Obtem um carro pelo id
  getCarById(id: number): Observable<Car> {
    return this.httpClient.get<Car>(this.url + '/' + id)
      .pipe(
        retry(2),
        catchError(this.handleError)
      )
  }

  // salva um carro
  saveCar(car: Car): Observable<Car> {
    return this.httpClient.post<Car>(this.url, JSON.stringify(car), this.httpOptions)
      .pipe(
        retry(2),
        catchError(this.handleError)
      )
  }

  // utualiza um carro
  updateCar(car: Car): Observable<Car> {
    return this.httpClient.put<Car>(this.url + '/' + car.id, JSON.stringify(car), this.httpOptions)
      .pipe(
        retry(1),
        catchError(this.handleError)
      )
  }

  // deleta um carro
  deleteCar(car: Car) {
    return this.httpClient.delete<Car>(this.url + '/' + car.id, this.httpOptions)
      .pipe(
        retry(1),
        catchError(this.handleError)
      )
  }

  // Manipulação de erros
  handleError(error: HttpErrorResponse) {
    let errorMessage = '';
    if (error.error instanceof ErrorEvent) {
      // Erro ocorreu no lado do client
      errorMessage = error.error.message;
    } else {
      // Erro ocorreu no lado do servidor
      errorMessage = `Código do erro: ${error.status}, ` + `menssagem: ${error.message}`;
    }
    console.log(errorMessage);
    return throwError(errorMessage);
  };

}

Entendendo nosso serviço

Injetamos o HttpClient e atribuímos a uma variável chamada httpClient, observe como é simples usar os métodos get, post, put e delete do nosso httpClient:

this.httpClient.get<Car[]>(this.url)
this.httpClient.post<Car>(this.url, JSON.stringify(car), this.httpOptions)
this.httpClient.put<Car>(this.url + '/' + car.id, JSON.stringify(car), this.httpOptions)
this.httpClient.delete<Car>(this.url + '/' + car.id, this.httpOptions)

Note que passamos uma variável chamada “url” essa conterá o endereço http://localhost:3000/cars disponibilizada pela API REST fake do json-server.
Adicionamos em nosso HttpClient um objeto do tipo HttpOptions, contendo nosso header através da classe HttpHeaders.

Alguns servidores podem exigir cabeçalhos para algumas operações como, post, put e delete, por exemplo um back-end onde as requisições dependem de um token de autorização.

Erros podem acontecer, por exemplo, um servidor back-end pode rejeitar nossa solicitação, ou um erro de rede no lado do cliente, esses erros produzem um objeto javaScript do tipo ErrorEvent. Para manipularmos esses erros, criamos um método dentro do nosso serviço chamado handleError, esse método produzirá um RxJS ErrorObservable, caso nossas requisições contenha um erro, redirecionaremos para nossos serviços com uma mensagem mais amigável.

O angular recomenda que métodos de manipulação de erros deve ser nos services e não nos componentes.

Antes de chamar o método handleError, observe que adicionamos um operador chamado retry, esse é o mais simples da biblioteca RxJS, ele reexecutará a chamada em um numero específico de vezes caso aconteça um erro.

Após entendemos o uso do httpClient, concluímos que nosso serviço é responsável pelas seguintes ações:

  • getCars(): recupera todos os carros.
  • getCarById(): recupera um carro especifico pelo id.
  • saveCar(): salva um carro.
  • updateCar(): atualiza um carro.
  • deleteCar(): exclui um carro especifico pelo id.

Usando nosso serviço

Agora vamos chamar nosso serviço através do component app.component.ts. Para isso vamos editar o component app.component.ts e adicionar o seguinte conteúdo:

import { Component, OnInit } from '@angular/core';
import { CarService } from './services/car.service';
import { Car } from './models/car';
import { NgForm } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  car = {} as Car;
  cars: Car[];

  constructor(private carService: CarService) {}
  
  ngOnInit() {
    this.getCars();
  }

  // defini se um carro será criado ou atualizado
  saveCar(form: NgForm) {
    if (this.car.id !== undefined) {
      this.carService.updateCar(this.car).subscribe(() => {
        this.cleanForm(form);
      });
    } else {
      this.carService.saveCar(this.car).subscribe(() => {
        this.cleanForm(form);
      });
    }
  }

  // Chama o serviço para obtém todos os carros
  getCars() {
    this.carService.getCars().subscribe((cars: Car[]) => {
      this.cars = cars;
    });
  }

  // deleta um carro
  deleteCar(car: Car) {
    this.carService.deleteCar(car).subscribe(() => {
      this.getCars();
    });
  }

  // copia o carro para ser editado.
  editCar(car: Car) {
    this.car = { ...car };
  }

  // limpa o formulario
  cleanForm(form: NgForm) {
    this.getCars();
    form.resetForm();
    car = {} as Car;
  }

}

Na linha 16 injetamos via construtor nosso serviço CarService e atribuímos a uma variável chamada carService
Criamos um método getCars(), esse será responsável por chamar a listagem de carros disponíveis através do nosso serviço CarService, incluímos no onOnit() para quando acessarmos app.component.ts ele nos trazer todos os carros, observe que logo após o método getCars() do carService, usamos o subscribe

getCars() {
 this.carService.getCars().subscribe((cars: Car[]) => {
   this.cars = cars;
 });
}

subscribe é um dos operadores mais importantes do Observable da biblioteca RxJS, ele notificará assim que a resposta vier e for transformada em Json, nos retornando um array de Carros.

No nosso exemplo, não esperamos retorno nas chamadas aos método saveCar()updateCar() e deleteCar(), sendo assim, quando entrar no subscribe estamos limpando nosso formulário e consultando novamente o método getCars para listar todos os carros.

Testando a aplicação

Modifiquei o HTML e CSS para ficar parecido com um projeto real, apenas para mostrar o uso do HttpClient em ação de forma simples e visual através de interações de tela.
Para isso, vamos incluir alguns trechos de código em nossa aplicação, primeiro vamos abrir o arquivo index.html e adicionamos o link CSS externo do bootstrap:

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">

O código ficará:

<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>AngularHttp</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>

<body>
  <app-root></app-root>
</body>

</html>

Agora vamos apagar todo o conteúdo do arquivo app.component.html e inserir o seguinte código:

<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item active" aria-current="page">Gerenciamento de carros</li>
</ol>
</nav>
<div class="container">
<div class="card list-car">
<h5 class="card-header">Lista de carros</h5>
<div class="card-body">
<table class="table">
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">Modelo</th>
<th scope="col">Cor</th>
<th scope="col">Preço</th>
<th scope="col">Ações</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let car of cars">
<td>{{car.id}}</td>
<td>{{car.model}}</td>
<td>{{car.color}}</td>
<td>{{car.price | currency}}</td>
<td>
<button type="button" class="btn btn-warning btn-sm" (click)="editCar(car)">Editar</button>
<button type="button" class="btn btn-danger btn-sm ml-1" (click)="deleteCar(car)">Deletar</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="card add-car">
<h5 class="card-header">Adicionar/Atualizar carro</h5>
<div class="card-body">
<form id="add-form" (ngSubmit)="f.form.valid && saveCar(f)" #f="ngForm" novalidate>
<div class="form-group">
<label for="model">Modelo</label>
<input type="text" [(ngModel)]="car.model" id="model" name="model" #model="ngModel" required class="form-control" [ngClass]="{ 'is-invalid': f.submitted && model.invalid }" placeholder="Digite o modelo">
<div *ngIf="f.submitted && model.invalid" class="invalid-feedback">
<div *ngIf="model.errors.required">Modelo é obrigatório</div>
</div>
</div>
<div class="form-group">
<label for="color">Cor</label>
<input type="text" [(ngModel)]="car.color" id="color" name="color" #color="ngModel" required class="form-control" [ngClass]="{ 'is-invalid': f.submitted && color.invalid }" placeholder="Digite a cor">
<div *ngIf="f.submitted && color.invalid" class="invalid-feedback">
<div *ngIf="color.errors.required">Cor é obrigatória</div>
</div>
</div>
<div class="form-group">
<label for="price">Preço</label>
<input type="number" [(ngModel)]="car.price" id="price" name="price" #price="ngModel" required class="form-control" [ngClass]="{ 'is-invalid': f.submitted && price.invalid }" placeholder="Digite o preço">
<div *ngIf="f.submitted && price.invalid" class="invalid-feedback">
<div *ngIf="price.errors.required">Preço é obrigatório</div>
</div>
</div>
<button type="submit" class="btn btn-primary btn-add-car">Salvar</button>
<button type="reset" class="btn btn-secondary btn-add-car" (click)="cleanForm(f)">Cancelar</button>
</form>
</div>
</div>
</div>

No arquivo app.component.css vamos adicionar o seguinte CSS:

.container { margin-top: 30px; } .add-car { margin-bottom: 30px; } .list-car { margin-bottom: 50px; } .btn-add-car { margin-right: 10px; }

Tela da aplicação

Já podemos notar o funcionamento do HttpClient através da listagem de carros que está no arquivo db.json. Assim que acessamos a tela da aplicação o método onOnit()foi disparado chamado o método getCars()que chama a listagem de carros do nosso serviço CarService.

Vamos adicionar um novo carro, uma Lamborghini Aventador:

Se abrir o terminal do json-server podemos verificar que requisições do tipo GET e POST foram realizadas:

POST /cars 201 45.079 ms — 97 GET /cars 200 4.980 ms - 407

A primeira foi uma requisição do tipo GET que nos retornou uma listagem contendo os carros, essa foi executada assim que acessamos a tela, ela foi chamada através do método getCars(), dentro do onOnit(), a segunda requisição foi do tipo POST, realizada através do método saveCars(), invocada após clicar no botão “Salvar”.

Se editarmos o modelo do carro para Lamborghini Huracan e sua cor para azul, podemos notar a requisição do tipo PUT e logo em seguida outra do tipo GET que é a listagem dos carros

PUT /cars/4 200 5.340 ms — 99 GET /cars 200 3.185 ms — 409

E se excluirmos nossa Lamborghini Huracan, notamos outras requisições do tipo DELETE e outra do tipo GET .

DELETE /cars/4 200 5.155 ms - 2 GET /cars 200 5.871 ms - 296

Conclusão

Através de uma aplicação modelo mostramos como consumir uma API REST usando o HttpClient , além de aprendemos como fazer requisições HTTP com os métodos GET, POST, PUT E DELTE, também aprendemos de forma básica como manipular erros e usar uma API REST fake com o json-server.

VOCÊ ESTÁ NAS SEÇÕES: » Programação » Framework Angular
Powered by Rock Convert
Powered by Rock Convert
Siga os bons!
Últimos posts por Ramos de Souza Janones (exibir todos)
vote
Article Rating

LEIA TAMBÉM:  UX: Tela com muitas informações ou distribuídas em várias telas?