Nodejs - usar api ou modelo

tuniq

What is folding?
Boas,

Estou a desenvolver uma webapp em Nodejs com Express e tou aqui com uma duvida sobre qual é a melhor prática a usar. A app consiste numa API e em 2 páginas web. A estrutura da app que tou a usar é:
- Modelos (onde defino funções/constantes para diversos componentes; ie: weather)
- Routes (onde defino as rotas, = modelos + index)

Alguns dos modelos fazem pedidos a API's externas. Isto significa que, quando faço um pedido à minha API (ie: GET /api/weather/forecast), no lado do servidor é feito um pedido a uma API externa (neste caso, de meteorologia).

Deixo aqui o código deste exemplo:
- No modelo weather (Weather.getForecast(lat,lng))
Código:
getForecast(lat, lng) {
    const options = {
      uri: `http://api.wunderground.com/api/${this.apiKey}/forecast/q/${lat},${lng}.json`,
      json: true,
    };
    return new Promise((resolve, reject) => {
      *****(options)
        .then(res => resolve(res.forecast.simpleforecast))
        .catch(err => reject(err));
    });
  }

- Na route weather (/api/weather/forecast)
Código:
router.get('/forecast', (req, res) => {

    // parte do código removida

    Weather.getForecast(location.lat, location.lng)
      .then(forecast => res.status(200).send(forecast))
      .catch(err => res.status(500).json({ status: err });
});

Das 2 páginas web da app, uma é de login, a outra é o conteúdo em si. Podemos considerar que é basicamente só uma página. Quando essa página é apresentada pela primeira vez, é necessário fazer uma certa quantidade de pedidos (neste momento são 4, mas podem vir a ser muitos mais). As possíveis soluções que descobri foram:
1. Fazer esses pedidos no lado do cliente (ajax)
2. Fazer esses pedidos no lado do servidor (request/fetch)
3. Utilizar directamente as funções dos modelos e não fazer qualquer pedido

Neste momento, estou a usar a opção 3. A minha duvida é: Qual é a melhor pratica num caso destes ? Devo usar sempre a API ou posso usar directamente os modelos como estou a fazer ?

Ja agora, deixo um bocado do código da rota index que mostra como vou buscar os dados aos modelos.

Código:
router.get('/dashboard', (req, res) => {

  const promises = [
    TvShows.getTvShows(userSettings.tvshows.shows),
    Movies.getMovies(),
    Weather.getConditions(userSettings.weather.location.lat, userSettings.weather.location.lng),
    Weather.getForecast(userSettings.weather.location.lat, userSettings.weather.location.lng),
  ];

  return Promise.all(promises.map(promise => promise.reflect()))
    .then(([tvList, moviesList, weatherConditions, weatherForecast]) => {
      const errors = {};
      (!tvList.isFulfilled()) ? errors.tvList = true : tvList = tvList.value();
      (!moviesList.isFulfilled()) ? errors.moviesList = true : moviesList = moviesList.value();
      (!weatherConditions.isFulfilled()) ? errors.weatherConditions = true : weatherConditions = weatherConditions.value();
      (!weatherForecast.isFulfilled()) ? errors.weatherForecast = true : weatherForecast = weatherForecast.value();
      res.render('dashboard', {
        title: 'Dashboard - Main',
        user: {
          username: userSettings.username,
        },
        tv: {
          days: Utils.getListOfFiveDays(5, -2, 'D MMM'),
          list: tvList,
          settings: userSettings.tvshows.shows,
        },
        weather: {
          days: Utils.getListOfFiveDays(4, 0, 'ddd, D MMM'),
          conditions: weatherConditions,
          forecast: weatherForecast,
        },
        movies: {
          list: moviesList,
        },
        errors,
      });
    })
    .catch((err) => {
      console.log(err);
    });
});
 
Boas,
Antes de mais algumas melhorias ao teu código:

Código:
getForecast(lat, lng) {
    const options = {
      uri: `http://api.wunderground.com/api/${this.apiKey}/forecast/q/${lat},${lng}.json`,
      json: true,
    };
    return *****(options)
                 .then(res => res.forecast.simpleforecast);
    });
  }

É um erro comum quando se começa a usar promises embrulhar uma promise noutra, mas neste caso o request-promise já te devolve uma promise.

Código:
router.get('/forecast', (req, res) => {

    // parte do código removida

    Weather.getForecast(location.lat, location.lng)
      .then(forecast => res.status(200).send(forecast))
      .catch(err => next(err);
});

//error middleware
app.use((err, req, res, next) => {
    res.status(err.statusCode || 500).json({ err });
});

Vê mais sobre middlewares de erro aqui: https://expressjs.com/en/guide/error-handling.html

1. Fazer esses pedidos no lado do cliente (ajax)
2. Fazer esses pedidos no lado do servidor (request/fetch)
3. Utilizar directamente as funções dos modelos e não fazer qualquer pedido

Quanto à tua pergunta:
1. A API externa pode não te deixar fazer o pedido através do browser por causa do CORS, a menos que essa API envie o response header Access-Control-Allow-Origin: '*' que permite a qualquer origin que não o próprio faça o pedido
2/3. Não percebi, tu estás a fazer pedidos do lado do servidor, estás é a resolver o pedido dentro do modelo em vez de noutra função qq, o que à partida não tem qualquer problema, é uma decisão arquitetural...
 
Uma dica já que estás a começar em Express, vê a framework KrakenJS, basicamente é uma convenção por cima de Express que usa as melhores práticas, é bom para aprenderes!
 
já agora...
podem dizer qual a lib ou fw que tem um orm semelhante ao hibernate e suporta migrations... mas em que não temos que escrever migrations à mão... algo do genero http://www.liquibase.org/
à uns tempos atrás desisti de fazer um protejo grande em nodejs por não haver algo para migrações de jeito... ou então não encontrei... na altura, tentei sailsjs e outros...
ter que andar a criar campos à mão e mais as migrations dá muito trab e é seca :P

não sei como está agora o noduas js, mas só não usei por achar que certas coisas não estão maduras como o rails ou django...
 
Boas,
Antes de mais algumas melhorias ao teu código:

É um erro comum quando se começa a usar promises embrulhar uma promise noutra, mas neste caso o request-promise já te devolve uma promise.

Obrigado pela dica. Faz sentido ! Tenho de ir ver o resto dos ficheiros que acho que ando a fazer isso em todo o lado.



Eu ja uso middleware de erro na aplicação. O que estás a sugerir é usar middleware em certas rotas em especifico ?

Quanto à tua pergunta:
1. A API externa pode não te deixar fazer o pedido através do browser por causa do CORS, a menos que essa API envie o response header Access-Control-Allow-Origin: '*' que permite a qualquer origin que não o próprio faça o pedido
2/3. Não percebi, tu estás a fazer pedidos do lado do servidor, estás é a resolver o pedido dentro do modelo em vez de noutra função qq, o que à partida não tem qualquer problema, é uma decisão arquitetural...

1. Os pedidos que faço ás api's externas funcionam no browser, apesar de eu não fazer isso neste momento. (E não o faço porque algumas têm limites de pedidos e api keys portanto é feito no lado no servidor para poder limitar os pedidos e ao mesmo tempo esconder a api key).

2/3 Acho que percebeste a duvida e acabaste por responder "é uma decisão arquitetural". A minha questão era saber se há "boas práticas" neste caso que descrevo. Posso tentar explicar melhor: Como "tive" de fazer uma API, devo fazer os pedidos por lá, mesmo dentro da aplicação no lado do servidor ? Ou seja, no lado do servidor tenho 2 hipoteses para aceder aos dados: 1. fazer pedido à minha api (com o request, por exemplo). 2. Usar directamente as funcoes dos modelos.

Uma dica já que estás a começar em Express, vê a framework KrakenJS, basicamente é uma convenção por cima de Express que usa as melhores práticas, é bom para aprenderes!

Vou dar uma vista de olhos.
 
Última edição:
já agora...
podem dizer qual a lib ou fw que tem um orm semelhante ao hibernate e suporta migrations... mas em que não temos que escrever migrations à mão... algo do genero http://www.liquibase.org/
à uns tempos atrás desisti de fazer um protejo grande em nodejs por não haver algo para migrações de jeito... ou então não encontrei... na altura, tentei sailsjs e outros...
ter que andar a criar campos à mão e mais as migrations dá muito trab e é seca :P

não sei como está agora o noduas js, mas só não usei por achar que certas coisas não estão maduras como o rails ou django...

Eu uso o Knex com db Postgres. Tem sistema de migrações, tanto do esquema da db como dados.

Edit: Saltei a parte do "escrever à mão". Não sei como funciona a parte de automatização das migrações. Eu tenho esquemas da db/tabelas definidos e só preciso de executar o ficheiro na máquina onde está o servidor da db. Em relação aos dados, só tenho um ficheiro com alguns dados para testes porque o resto exporto do postgres e importo onde for preciso.

Por exemplo, a tabela users:

Código:
exports.up = (knex, Promise) => knex.schema.createTableIfNotExists('users', (table) => {
  table.increments();
  table.string('email').unique().notNullable();
  table.string('password').notNullable();
  table.boolean('admin').notNullable().defaultTo(false);
  table.timestamp('created_at').notNullable().defaultTo(knex.raw('now()'));
});

exports.down = (knex, Promise) => knex.schema.dropTable('users');
 
Última edição:
Eu uso o Knex com db Postgres. Tem sistema de migrações, tanto do esquema da db como dados.
node js faz lembrar o php, é muita fw para fazer o mesmo, e depois é tudo muito espalhado... mas não quer dizer que tenha boas fw :P
assim as big corporates não pegam :P existe alguma empresa grande a fazer uma fw para backend node js? como por exemplo a google com o angular js...
no ruby tem o rails, no python o django, no node js tem muita coisa mas não sei se são assim tão maduras... os devs ficam todos espalhados :(
estou errado?
 
node j
s faz lembrar o php, é muita fw para fazer o mesmo, e depois é tudo muito espalhado... mas não quer dizer que tenha boas fw :P
assim as big corporates não pegam :P existe alguma empresa grande a fazer uma fw para backend node js? como por exemplo a google com o angular js...
no ruby tem o rails, no python o django, no node js tem muita coisa mas não sei se são assim tão maduras... os devs ficam todos espalhados :(
estou errado?

Pois, isso é um grande problema do Node. Há demasiados "módulos" e 70% não interessam a ninguem nem fazem nada de jeito. Mas mesmo assim, acho que os principais (mais uteis) vão sendo reconhecidos. Eu cada vez que vou ao Reddit descubro que há 20 coisas novas.

Não percebi mt bem a questão. Frameworks de quê ? Back-end api's tens Express (ibm) e Hapi. Front-end tens Angular (google), React (facebook) e Vue.

Em termos de ORMs só usei Knex e Sequelize
 
Eu ja uso middleware de erro na aplicação. O que estás a sugerir é usar middleware em certas rotas em especifico ?

Se tens middleware de erro, no exemplo que deste não estás a usá-lo, e deves usá-lo sempre.
Ou seja, estou a dizer usares o middleware de erro para todos os erros, sempre que tiveres uma rota que responde com um erro chamas next(err) e em vez de fazer respond de erro diretamente na rota.

2/3 Acho que percebeste a duvida e acabaste por responder "é uma decisão arquitetural". A minha questão era saber se há "boas práticas" neste caso que descrevo. Posso tentar explicar melhor: Como "tive" de fazer uma API, devo fazer os pedidos por lá, mesmo dentro da aplicação no lado do servidor ? Ou seja, no lado do servidor tenho 2 hipoteses para aceder aos dados: 1. fazer pedido à minha api (com o request, por exemplo). 2. Usar directamente as funcoes dos modelos.

Não compliques, estás a fazer bem, estás a fazer o resolve do modelo nele próprio, tudo certo na minha opinião :)
 
Sim, tens razão. Eu é que ainda não cheguei a essa parte, apesar de já ter definido 2 middlewares para 404 e 500. Tou a ver se acabo as funcionalidades principais da app e depois trato disso. (até porque a lista de Todo's tem umas 200 linhas)

Maioria destas duvidas de "melhores praticas" vou procurando na net, sobretudo patterns de código e design de api's. Mas há algumas coisas que não consigo encontrar e depois fico a pensar se o que tou a fazer é a forma correcta ou não.

Já agora, um aparte.. usas Typescript ? Sempre que vejo discussão sobre isso, maioria das pessoas que aprendeu Typescript diz que não quer outra coisa. Dizem que facilita bastante o debugging (porque dá erros bem especificos/detalhados na compilação) e a organização do código em si. Mas eu como vou vendo coisas novas todos os dias, tarda nada demoro 5 anos a fazer uma app com Node e React.

Obrigado pela ajuda :)
 
JavaScript não é compilado, esses erros que o TypeScript dá são da análise estática de código.
Para efeitos de sintaxe (é +- disso que estás a falar) tanto profissionalmente como em projetos pessoais uso ESLint, que também faz análise estática, é muito completo.

Quando andei a brincar com Angular 2 usei TS, achei piada à parte dos decorators, que acho que tb vai ser uma feature do ES7.
Quanto aos types em si, é naquela... gosto de JS que parece JS e não C#/Java/outra linguagem OOP, até pq ultimamente tenho procurado explorar mais a composição de objetos em vez de prototypal inheritance, e o TypeScript é bastante "clássico" nesse aspecto.
 
JavaScript não é compilado, esses erros que o TypeScript dá são da análise estática de código.
Para efeitos de sintaxe (é +- disso que estás a falar) tanto profissionalmente como em projetos pessoais uso ESLint, que também faz análise estática, é muito completo.

Quando andei a brincar com Angular 2 usei TS, achei piada à parte dos decorators, que acho que tb vai ser uma feature do ES7.
Quanto aos types em si, é naquela... gosto de JS que parece JS e não C#/Java/outra linguagem OOP, até pq ultimamente tenho procurado explorar mais a composição de objetos em vez de prototypal inheritance, e o TypeScript é bastante "clássico" nesse aspecto.

Eu sei que Javascript não é compilado, mas TS deu-me a entender que é. Na página deles diz "TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.".

Eu tbm uso ESLint (neste momento, no VS Code) e não tenho esses erros tão detalhados como já vi a acontecer com TS. Aliás, aquilo praticamente só me dá erros de "estilo" tipo trailing spaces, espaço entre args, etc. Quer dizer, como é que é possível o ESLint fazer a mesma análise, se não se usa tipos em JS 'vanilla' ? Por exemplo, uma vantagem que vejo com TS, é que posso dizer qual o tipo dos argumentos de uma função e quando tento executa-la noutro sitio qq, ele diz-me que devia estar a usar uma 'string' em vez de um 'objecto ' (exemplo). Tem certos pormenores que" somados" acho que acabam por melhorar a produtividade. A minha duvida é se isto é algo que realmente me vale a pena "perder" tempo. Será que é algo muito especifico em termos profissionais ? (aka pouco usado em projectos)

Quando dizes "explorar mais a composição de objetos em vez de prototypal inheritance", o que significa isto ?

Já agora, visto que tens alguma experiência em JS (e alguns que vêm parar a este tópico tbm devem ter):
- Tou um bocado indeciso no que devo fazer a seguir. Além do óbvio, melhorar os conhecimentos em JS (e Node), tou dividido entre dedicar-me só a back-end (servidores web, segurança, redes, ...) ou ir para uma framework tipo React e ser full-stack dev.
A minha visão neste momento (não conheço o mercado de trabalho e tenho conhecimentos algo limitados no que falei anteriormente) é que back-end acaba por ser mais difícil/demorado/complexo de aprender (sobretudo para alguem que não está em Eng Informática e é auto-didata) mas depois é mais valorizado profissionalmente (ie: progressão maior com o tempo, que acaba por ser +€). E depois há a questão do dedico-me ao back-end até que ponto ? E em que ponto posso-me candidatar a posições de back-end ? Conhecimentos em Nodejs chegam para começar em algum sitio ? Ou vão sempre pedir conhecimentos em servidores web, db's, no mínimo ?
Por outro lado, frameworks tipo React "começam" a ser usadas mais a sério (por acaso não sei como anda isto em Portugal, já vi empresas que usam Angular, mas React ainda não). Além disso, ser full-stack tem a vantagem de ter conhecimentos mais abrangentes e puder ir ajustando conforme as necessidades. Vai dando trabalho, mas as bases já estão lá.
- O mercado dá muita importância à parte da criatividade/design quando procura pessoas para posições relacionadas com frameworks front-end tipo React ? Isto é, verifica-se uma separação entre front-end dev e webdesigner ? Ou só nas grandes empresas ? Ou nem isso ?
Eu pergunto isto porque acho que consigo aprender bem React, mas em termos de design esquece. Uso bootstrap para tudo e mais alguma coisa. E nem é o facto do css ser fácil ou difícil, é mesmo não ter visão para fazer uma UI ou um simples website.
- Em que ponto devo fazer um portefólio ? Vejo exemplos de pessoas que fazem webapps tipo gestor de todo's (api com 3/4 endpoints, autenticação, jwt e pouco mais) ou uma webapp que acede a uma api externa para ir buscar certos dados (tipo google maps api e ir buscar restaurantes abertos a 500m). Não sei se sou eu que tenho uma ideia errada e acho que preciso de ter mais conhecimentos do que na realidade preciso, ou se essas pessoas têm sorte. Porque se for assim, mais vale criar 20 webapps desse género do que uma que é útil para mim mas que demora bem mais tempo a fazer.

Gostava de ter várias respostas a estas perguntas, mas não sei se aqui é o sitio mais indicado...

Edit: Não falo de HTML/CSS na parte do front-end/full-stack porque são aqueles "conhecimentos obrigatórios".
 
Back
Topo