Tableless

Busca Menu

Trabalhando com serviços no Javascript

Seja o primeiro a comentar por

JavaScript é uma linguagem multiparadigma. Pode-se “emular” várias técnicas de programação com ele, e isso é incrível pois podemos decidir qual o melhor paradigma para a resolução dos problemas dos nossos projetos. Porém se por um lado isso pode parecer poderoso para a linguagem, também pode deixar os iniciantes bem confusos, é muito comum escolher a abordagem errada para o problema. Por esse motivo que o JavaScript em sido polêmico nos últimos anos.

Pensando nisso muitos desenvolvedores criam suas próprias soluções, uns pensando em ajudar e outros em forçar padrões.
Eu prefiro ensinar a pescar, pois JavaScript não tem que ser complexo. A versão 6 do JavaScript (ES6/ES2015) tornou a linguagem muito mais expressiva, facilitando muito o entendimento.

Encapsulando lógicas

Tudo em JavaScript são objetos (exceto undefined), então serviços também são objetos, dominando como criamos e trabalhamos com objetos todas as coisas ficam bem mais tranquilas.

O Jean Carlo Emer fez um artigo muito, mas muito bom sobre Modularização no JavaScript. Sugiro que você leia, mas vou explicar um pouco sobre o assunto logo abaixo.

i know JavaScript basics

Scope e Closures

JavaScript possui escopo léxico. Entre outras coisas isso permite que você crie closures.
De maneira resumida você cria um “ambiente controlado” onde há funções/variáveis que só podem ser acessadas naquele escopo, criando um enclausuramento (closure).

const initPage = (root) => {
  const $root = $(root);
  const $menu = $root.find('.menu');
  const $profile = $menu.find('.profile');

  const initProfile = () => {
    $.get('/me')
      .then(response => $profile.text(response.username));
    // ...
  };

  const showProfileModal = e => {
   // ...
  };

  $profile.on('click', e => showProfileModal(e));

  initProfile();
};

initPage('body');

Este é um exemplo bem bobo, mas que ilustra bem como criamos closures.
As variáveis declaradas dentro de initPage só existem naquele escopo.
No mesmo exemplo podemos refatorar esse código em uma IIFE (Immediately-Invoked Function Expression)

((root) => {
  const $root = $(root);
  const $menu = $root.find('.menu');
  const $profile = $menu.find('.profile');

  const initProfile = () => {
    $.get('/me')
     .then(response => $profile.text(response.username));
    //  ...
  };

  const showProfileModal = e => {
    // ...
  };

  $profile.on('click', e => showProfileModal(e));

  initProfile();
})('body');

Nesse código declaramos uma função e a executamos imediatamente, passando um argumento. Isso é extremamente útil quando queremos fazer um processamento de uma informação que vai servir apenas para criar uma variável.

const timezones = (() => {
  const zones = [];
  const min = -12;
  const max = 13;
  let simbol;

  for (let i = min; i <= max; i++) {
    simbol = (i < 0) ? '' : '+';
    zones.push(`GMT${simbol}${i}`);
  }

  return zones;
})();

Como você já pode perceber, é possível expor dados de uma closure como no exemplo anterior. A variável zones é retornada, assim a variável timezones agora possui como valor o resultado da closure.
Nesse exemplo a closure não usa dados externos a ela (parent scope/escopo pai) porém dada a natureza do JavaScript isso é perfeitamente possível.

Isso é útil para não poluir o escopo principal com informações irrelevantes.

const makeCounter = (start = 0) => {
  let current = start;

  const add = (value = 1) => current += value;
  const remove = (value = 1) => add(value * -1);
  const get = () => current;

  return { add, remove, get };
};

const counter = makeCounter(10);

counter.add() // 11
counter.add() // 12
counter.add(8) // 20
counter.remove(10) // 10

Este é um exemplo bem interessante. Estamos combinando closures com factory.

Com isso podemos criar vários contadores, e trabalhar como melhor convir com estes contadores.

Só isso! Simples, né?

Só isso! Simples, né?

Se você entendeu como o exemplo do contador funciona, parabéns você já sabe criar serviços com javascript.

Isso mesmo, este contator é um serviço. Na verdade ele é um factory, mas com pequenos ajustes ele vira um serviço de fácil reuso.

// makeCounter.js -> factory
const makeCounter = (start = 0) => {
  let current = start;

  const add = (value = 1) => current += value;
  const remove = (value = 1) => add(value * -1);
  const get = () => current;

  return { add, remove, get };
};

export default makeCounter
// counter.js -> service
import makeCounter from './makeCounter.js';

export default makeCounter(0);

Agora temos dois arquivos, um contendo o factory do contador, e outro contendo o serviço de contagem.

Módulos JavaScript

module

Como visto anteriormente, é bem simples criar serviços com JavaScript, basta antes entender alguns conceitos.

Porém isso não é tudo, se você esta criando um serviço é porque tem a intenção de reusar esta lógica em mais de um local da aplicação. Isto não é uma regra, talvez você queira apenas centralizar a lógica da operação.

Não importa o objetivo inicial, você vai acabar criando um módulo JavaScript para aquela sua operação/serviço. No exemplo do contador foram criados dois arquivos, o contador e o factory do contador. Nesse momento você precisa entender minimamente o que são módulos JavaScript.

Em resumo: um arquivo JavaScript é um módulo e um módulo JavaScript é um arquivo.

Você pode criar um módulo a partir de outros módulos, como é o exemplo do contador, ele é composto a partir do módulo makeCouter.

Em geral a lógica dos módulo é encapsulada em closures e o retorno delas é cacheado, sendo assim, uma vez que você importa um módulo, ele será o mesmo sempre, compartilhando seu estado. Saiba mais aqui.

Usando serviços

Agora que você possui essas informações acredito que criar seus próprios serviços não será nenhum bicho de sete cabeças.

Vale a pena dizer que tudo pode ser considerado um serviço, inclusive factories.

Para reforçar vou deixar mais um exemplo de uso de serviços.

import Http from './http.js';
import UsersService from './modules/users/service.js';

Http.setToken('XPTO'); // Define o token de autentificação

// Cattega a primeira página de usuários
// Exibe um alerta com o nome do primeiro usuário retornado pelo serviço

UsersService
  .getAll({ page: 1 })
  .then(result => result.data)
  .then(data => data[0])
  .then(first => {
    alert(first.name);
  });

Para efeito de aprendizado uma sintaxe alternativa, com import binding.

import { setToken } from './http.js';
import { getAll as getAllUsers } from './modules/users/service.js';

setToken('XPTO'); // Define o token de autentificação

// Carrega a primeira página de usuários
// Exibe um alerta com o nome do primeiro usuário retornado pelo serviço

getAllUsers({ page: 1 })
  .then(result => result.data)
  .then(data => data[0])
  .then(first => {
    alert(first.name);
  });

Este pode não parecer para alguns mas é um exemplo bem prático do uso de serviços.
O serviço de Http também é usado pelo serviço de usuários, por isso é possível definir o token de autentificação antes de efetivamente usar os serviços, pois eles vão compartilhar o mesmo estado/serviço.

Outra característica interessante é que esses serviços não estão ligados diretamente a nenhum contexto. Isso significa que não importa que ambiente você esteja ou que framework você esta usando, os serviços são agnósticos. Eles podem ser usados no NodeJS, VueJS, ReactJS, etc.
Este é um dos princípios do polimorfismos do JavaScript porém este é outro assunto.

 

Se quiser saber mais sobre meu trabalho visite meu blog https://medium.com/@luizvinicius73


Este artigo foi originalmente postado no meu blog no medium em 31 de Julho de 2016

Publicado no dia