Solucionado (ver solução)
Solucionado
(ver solução)
8
respostas

Retorno API Rest

Olá pessoall,

Confesso que pulei algumas fases e não tive tempo de pegar uma base forte em ES6 com calma, tive que sair fazendo um projeto e ir acertando ele "on the fly"... preciso entender o seguinte:

Eu aprendi desta forma (meu provider):

  getGroups(): Promise<Group[]> {
    return this.http.get(this.api)
      .toPromise()
      .then(response => response.json() as Group[])
      .catch(this.handleError);
  }
`

No .ts da tela eu faço isso:

this._groupService.getGroups().then(groups => this.groups = groups);

Tenho um model para cada entidade, inicialmente até me agradava esta abordagem, mas olhando o exemplo super do Ionic vi que eles trabalham desta forma:

Tenho uma API genérica que faz a chamada desta forma:

return this.http.get(this.url + '/' + endpoint, reqOpts);

Esta API é chamada por um provider que tem este código:

let seq = this.api.get('group').share();

No .ts da tela eu gostaria de fazer isso aqui:

this.groups = this._groupProvider.getGroups();

Gostaria de dois tipos de ajuda:

1) Solução para fazer rodar msm...

2) Entender melhor a diferença das duas abordagens, sinto que necessito entender de verdade o que é uma promisse e um observable, etc... Agora sim que ja tenho o APP rodando quero começar a mergulhar nos detalhes e entender a necessidade de saber estes itens, se eu ficasse dando cabeçada no ES6 eu tenderia a desanimar... No resto eu me sinto tranquilo conforme vou olhando códigos por ai e tentando aprender boas práticas com o código alheio...

Desde já obrigado!

8 respostas

Fiz um teste e desta forma funciona, mas estou achando um lixo este código:

    this._groupProvider.getGroups().subscribe(
      res => {
        res.forEach(group => {
          let g = new Group();
          g.description = group.description;
          g.id = group.id;

          console.log(this.groups.push(g));
        });
      })
`

Não entendo também, porque ao iniciar o ionic (ionic serve --lab) ele da erro na linha do forEach, ai eu dou um salvar no arquivo e roda normal...

Agora estou começando a entender que o ideal é esquecer as promisses e usar Observable (não sei se entendi direito) que tem algumas vantagens em relação a promisses e vejo que no curso utilizamos Http, ja a sugestão do Ionic seria HttpCliente que tem alguns upgrades em relação a Http, preciso de ajuda meu... na boa, foquei meio confuso agora...

Agora estou mais confuso ainda...

    this._groupProvider.getGroups().subscribe(
      res => {
        //this.groups = res
        console.log(typeof res);
        var a = JSON.stringify(res);
        var b = JSON.parse(a);
        console.log(b[0].id);

        this.groups = b;
        //console.log(res);
      }
    )

Não entendo pq não posso fazer this.groups = res

É muito informação, estou confuso igual a você. Mas em suma, se você fez

getGroups(): Promise<Group[]> {
    return this.http.get(this.api)
      .toPromise()
      .then(response => response.json() as Group[])
      .catch(this.handleError);
  }

Isso já deve ser suficiente para que você receba a lista de grupos.

Foi você que criou as API's e os providers da sua App? Se sim, tem que dá uma passada nelas, não tem outro jeito.

Sobre o ES6, como Angular usa TypeScript e TypeScript é um subset do ES6, você terá bastante dificuldade em pegar outros conceitos do Ionic que dependem desse pré-requisito. Lhe faltará até mesmo os termos mais concretos para exemplificar seu problema.

Então, se eu fizer isso eu tenho que usar o Http antigo, gostaria de usar o HttpCliente que é mais novo, ele não tem este .json por exemplo... ele ja faz direto... Já tento explicar melhor aqui...

Temporariamente estou fazendo isso com o retorno: this.groups = JSON.parse(JSON.stringify(res))

O HttpClient já faz o res.json() por debaixo dos panos, mas como isso esta isolado em uma camada de serviço, usar HttpClient só por causa disso não é grande vantagem.

O HttpClient suporta:

  • Typed, synchronous response body access, including support for JSON body types

  • JSON is an assumed default and no longer needs to be explicitly parsed

  • Interceptors allow middleware logic to be inserted into the pipeline

  • Immutable request/response objects

  • Progress events for both request upload and response download

  • Post-request verification & flush based testing framework

A ideia é que em um futuro distante o HttpClient substituia o Http. Se os demais recursos você não vai utilizar, vá de Http enquanto ganha expertise no HttpClient.

Eu uso Http porque a maioria das minhas aplicações são pré-angular 4.

Faz sentido, mas agora ja foi, ja refatorei tudo, antes eu tinha uma classe para fazer as chamadas de cada entidade, exemplo:

import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';
import 'rxjs/add/operator/toPromise';

import { Child } from '../model/child'

@Injectable()

export class ChildService {
  constructor(private http: Http) {}

  private headers = new Headers({ 'Content-Type': 'application/json' });
  private api = 'http://192.168.15.231:3000/child';

  getChilds(): Promise<Child[]> {
    return this.http.get(this.api)
      .toPromise()
      .then(response => response.json() as Child[])
      .catch(this.handleError);
  }

  getChild(id: number): Promise<Child> {
    const url = `${this.api}/${id}`;
    return this.http.get(url)
      .toPromise()
      .then(response => response.json() as Child)
      .catch(this.handleError);
  }

  createChild(child: Child): Promise<Child> {
    return this.http
      .post(this.api, JSON.stringify(child), { headers: this.headers })
      .toPromise()
      .then()
      //.then(res => res.json() as Child)
      .catch(this.handleError);
  }

  updateChild(child: Child): Promise<Child> {
    const url = `${this.api}/${child.id}`;
    return this.http
      .put(url, JSON.stringify(child), { headers: this.headers })
      .toPromise()
      .then(() => child)
      .catch(this.handleError);
  }

  deleteChild(child: Child): Promise<void> {
    const url = `${this.api}/${child.id}`;
    return this.http.delete(url, { headers: this.headers })
      .toPromise()
      .then(() => null)
      .catch(this.handleError);
  }

  private handleError(error: any): Promise<any> {
    console.error('An error occurred', error);
    return Promise.reject(error.message || error);
  }  
}

Agora só tenho uma para tudo...

import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Group } from '../../models/group';

@Injectable()
export class Api {
  //url: string = 'http://192.168.15.231:3000';
  url: string = 'http://localhost:3000';

  constructor(public http: HttpClient) {
  }

  get(endpoint: string, params?: any, reqOpts?: any) {
    if (!reqOpts) {
      reqOpts = {
        params: new HttpParams()
      };
    }

    // Support easy query params for GET requests
    if (params) {
      reqOpts.params = new HttpParams();
      for (let k in params) {
        reqOpts.params.set(k, params[k]);
      }
    }

    return this.http.get(this.url + '/' + endpoint, reqOpts);
  }

  post(endpoint: string, body: any, reqOpts?: any) {
    return this.http.post(this.url + '/' + endpoint, body, reqOpts);
  }

  put(endpoint: string, body: any, reqOpts?: any) {
    return this.http.put(this.url + '/' + endpoint, body, reqOpts);
  }

  delete(endpoint: string, reqOpts?: any) {
    return this.http.delete(this.url + '/' + endpoint, reqOpts);
  }

  patch(endpoint: string, body: any, reqOpts?: any) {
    return this.http.put(this.url + '/' + endpoint, body, reqOpts);
  }
}

Esta segunda abordagem me agrada bastante, o lance que estava pegando era apenas o retorno mesmo, ainda não entendi pq a necessidade de um stringify e depois um parse, sendo que eu também tinha entendido que ela ja fez um .json por debaixo dos panos, isso me rendeu boas horas de "aprendizado" (cabeçadas e se sentindo um retardado)... Só não consegui tipar dinamicamente como fazemos em Java, no seu exemplo o tipo é estático, por isso eu acabava criando um deste primeiro arquivo para cada entidade, eu idealizo apenas esta API para cuidar de tudo que eu precisar no sistema e o JSON do modelo "sincroniza os dados que vem do DB"

Estou apanhando com o "toast" agora... :-(

Agora sim... esta quase amador, melhorou bastante....


    this._groupProvider.getGroups().subscribe((res) => { 
      this.groups = JSON.parse(JSON.stringify(res))
    }, (err) => {
      let toast = this.toastCtrl.create({
        message: this.translateService.instant('CHILD_GROUP_ERROR'),
        duration: 3000,
        position: 'top'
      });
      toast.present();
    });

Se possível só me ajuda com esta parte aqui:

this.groups = JSON.parse(JSON.stringify(res))

Revisando o ciclo completo:

Isso aqui: this.groups = JSON.parse(JSON.stringify(res))

chama isso:

  getGroups() {
    let seq = this.api.get('group').share();
    seq.subscribe((res: any) => {
      console.log('Consulta OK');
    }, err => {
      console.error('ERROR', err);
    });
    return seq;
  }

Que chama isso:

  get(endpoint: string, params?: any, reqOpts?: any) {
    if (!reqOpts) {
      reqOpts = {
        params: new HttpParams()
      };
    }

    // Support easy query params for GET requests
    if (params) {
      reqOpts.params = new HttpParams();
      for (let k in params) {
        reqOpts.params.set(k, params[k]);
      }
    }

    return this.http.get(this.url + '/' + endpoint, reqOpts);
  }

Eu realmente não entendi pq estes JSON na primeira chamada...

export class Group { id: number; description: string; period: string; }

Cara! Desde já obrigado e espero lhe conhecer pessoalmente, vc esta me tirando do amadorismo! vlw

solução!

Acabou ficando assim a linha:

      this.groups = <any> res;
`

ao invés de:

     this.groups = JSON.parse(JSON.stringify(res))