Provavelmente este não é o primeiro post sobre “como começar uma aplicação em Node.JS” que você lê. Existem muitos e, provavelmente, neles você viu exemplos que utilizam frameworks como o express.js, por exemplo. Nesse eu vou tentar mostrar o que é possível fazer somente com as bibliotecas nativas do Node.JS.

Caso ainda não tenha instalado o Node.js, clique aqui.

Vou assumir que você já conheça um pouco de Javascript e entende como funciona callbacks. Caso não faça ideia do que seja callbacks, sugiro que leia este post.

Este post não é adequado para quem está começando a programar. Para quem está começando, tem esse post aqui

Também indico que você acompanhe este post tentando criar a aplicação de exemplo. Se possível, leia o conteúdo dos links que coloquei ao longo do post.

Por onde começar?

$ npm init

Esse comando será o primeiro que você vai executar ao começar uma aplicação em branco.

Respondendo as perguntas que ele faz, você terá um arquivo chamado package.json.

No nosso exemplo, vamos nomear a aplicação de fakemytemplate, versão 1.0.0, sem descrição. No resto você pode ir teclando Enter.

O package.json, provavelmente, é o arquivo mais importante de uma aplicação em Node.JS. Nele especificamos o nome, a versão, os autores e, não menos importante, as dependências.

É muito comum uma aplicação em Node.JS tenha muitas dependências. Existe uma grande facilidade em reutilizar código open-source que a comunidade cria e publica no github e no npm. Isso faz com que o Node.JS seja um ambiente extremamente rápido para desenvolver (existem MUITAS libs).

É importante ter em mente que ao escolher uma lib, você está fazendo seu código dependente dela. Por mais que você tenha camadas de abstração, no fim das contas você ainda estará utilizando essa lib. Tenha cuidado ao escolher.

Uma recomendação rápida é procurar por libs que sejam conhecidas pela comunidade. As que são constantemente atualizadas (nada de libs que não tenham sido alteradas nenhuma vez durante anos) e com uma boa documentação.

Nesse tutorial, só vamos utilizar a lib: Faker.js. Uma lib para gerar dados falsos. Recomendo que você dê uma olhada na documentação, só para entender o que ele faz.

Instalando uma dependência

$ npm install --save faker.js

Toda dependência instalada vêm de um site chamado npm (Node Package Manager). Ele já vem junto com a instalação do Node JS.

Quando rodamos o comando o npm irá buscar a lib em seu registro (neste no caso, faker.js).

Uma dica é rodar o comando com a opção –save. Irá incluir automaticamente a dependência no seu package.json.

Notamos que apareceu uma pasta nova no nosso projeto, node_modules. É nele que as dependências do seu projeto são instaladas.

Package.json

Como eu disse antes, é o arquivo mais importante da nossa aplicação. Vamos dar uma olhada nele.

{
  "name": "fakemytemplate",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "faker": "^3.1.0"
  }
}

Observamos que ele incluiu o faker como dependência na sua versão mais recente no npm. Para ver como funciona o versionamento dentro do npm, recomendo que você dê uma olhada na documentação.

Com as dependências listadas corretamente no package.json, ao rodar novamente o comando npm install, o npm irá reconstruir a pasta node_modules e instalar as dependências novamente. Por isso, devemos manter o package.json atualizado. Facilitando a vida das outras pessoas que possam mexer no projeto. Tudo o que vão precisar fazer é executar o npm install.

Caso você esteja trabalhando com git ou com alguma outra ferramenta de versionamento, você pode ignorar toda a pasta node_modules.

Já que falamos para o package.json que o nosso arquivo principal é o index.js, vamos criar um:

const faker = require('faker');

const randomName = faker.name.findName();
console.log(randomName);

E rodar isso:

$ node index.js

Magnolia Glover

Tudo o que fizemos foi importar a lib faker utilizando a instrução require(‘faker’), chamar o método faker.name.findName() para ele gerar um nome randomicamente e mostrar no console.log o nome gerado.

Para quem ainda não está acostumado com ES6 (versão mais nova do Javascript), o const é parecido com o var. Só que ao definir uma variável utilizando o const, ela não pode mais ser modificada.

Por exemplo:

const faker = require('faker');

const randomName = faker.name.findName();
randomName = faker.name.lastName();

console.log(randomName);

Este código irá resultar em um erro, já que não podemos redefinir o conteúdo da variável randomName.

Vamos modificar um pouco o package.json e incluir um script chamado start.

{
  "name": "fakemytemplate",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo "Error: no test specified" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "faker": "^3.1.0"
  }
}

Agora, ao executar um npm start, o comando node index.js será executado:

npm start

> fakemytemplate@1.0.0 start /home/ubuntu/fakemytemplate
> node index.js

Jamar Klein

Vamos dar mais um passo e criar um server que, ao receber uma request, irá enviar um nome randômico.

Para isso vamos utilizar a biblioteca http, nativo no NodeJS.

const faker = require('faker');
const http = require('http');

const server = http.createServer();

server.on('request', function (request, response) {
  const randomName = faker.name.findName();

  response.write('Your random name: ' + randomName);
  response.end();
});

server.listen(3000);
console.log('Server is running.');

Beleza! Já consigo imaginar você olhando esse código e sua cabeça dando um nó.

Calma!

> const http = require('http');

Da mesma maneira que fizemos com o faker, estamos importando o módulo http do Node.

> const server = http.createServer();

Chamamos o método http.createServer do módulo http. Ele irá retornar uma nova instância da classe http.Server.

Mais a fundo, a classe http.Server herda de um EventEmitter, que, podemos dizer, é o core do Node, mas falar sobre ele tornaria este “Como começar” muito mais complexo. Então, por enquanto, vamos pular esta parte. Caso esteja interessado, temos outro post falando sobre o EventEmitter.

Quem já mexeu com Javascript nos web browsers vai se lembrar dos eventos do DOM (onclick, onload, etc.).

server.on('request', function (request, response) {
  const randomName = faker.name.findName();

  response.write('Your random name: ' + randomName);
  response.end();
});

O método .on() existe em toda classe que herda do EventEmitter:

O nosso objeto server, ao receber uma request, emitirá um evento chamado request. Assim, utilizamos o .on() para colocar um listener para evento, passando uma função de callback.

Se você ainda não sabe o que é callback, recomendo que pesquise um pouco antes de continuar nesse post.

A função de callback receberá dois argumentos do evento request. O primeiro é um objeto com as informações da requisição do client e o segundo é um objeto utilizado para responder ao client.

Então, o nosso callback para o evento request vai criar um nome randômico.

> const randomName = faker.name.findName();

Escrever no corpo da resposta o nome gerado.

>  response.write(randomName);

E terminar a resposta.

>  response.end();

O próximo passo é fazer o nosso servidor escutar em uma porta. No caso, a porta 3000.

server.listen(3000);
console.log('Server is running.');

E vamos executar o nosso index.js.

$ npm start

> fakemytemplate@1.0.0 start /home/ubuntu/fakemytemplate
> node index.js

Server is running.

É bom ter atenção que o código que o Node.JS está executando não é “atualizado automaticamente”. Temos que reiniciar a aplicação sempre que alterar o código. Diferentemente de outros runtimes, o Node.JS não abre uma thread ou processo para cada request. As aplicações em Node.JS são single threads, seu código permanece estático e as requisições são tratadas assincronamente. Ou seja, em paralelo. Mas ainda sim, sendo single thread não terá dois blocos de códigos sendo executados simultaneamente. Podemos dizer que Node.JS não é recomendado para executar um código que utiliza muito recurso do processador (CPU bind), mas ele é ótimo para código com muita operação de entrada / saída (I/O bind).

Você deve ter percebido que o processo não foi encerrado. Sim, nosso servidor está rodando.

Vamos testar tentando fazer uma requisição para o localhost:3000.

Você pode abrir no próprio browser, mas vamos utilizar o curl.

$ curl localhost:3000

Your random name: Ernesto Brakus

Hora de colocar mais coisas na nossa aplicação.

Vamos utilizar do poderoso método faker.fake que recebe um template e retorna um texto de acordo com o template que foi passado.

faker.fake("{{name.lastName}}, {{name.firstName}} {{name.suffix}}");

// outputs: "Marks, Dean Sr."

Utilizaremos o método faker.fake para quando o nosso servidor receber uma request ele seja via parâmetro do template e envie para o client o resultado.

Mais ou menos assim:

$ curl -G "localhost:3000" --data-urlencode "template=Hello {{name.firstName}}"

Hello Shanelle

Vamos dar uma olhada como recebemos o parâmetro template. Para isso, vamos inspecionar o parâmetro request.url.

const faker = require('faker');
const http = require('http');

const server = http.createServer();

server.on('request', function (request, response) {
 console.log('request.url:', request.url);
 const randomName = faker.name.findName();

 response.write('Your random name: ' + randomName);
 response.end();
});

server.listen(3000);
console.log('Server is running.');

Aquele console.log(‘request.url:’, request.url) irá mostrar algo assim:

request.url: /?template=Hello%20%7B%7Bname.firstName%7D%7D

Está meio confuso, certo? Vamos “parsear” a url utilizando o módulo url, também nativo do Node.JS.

const faker = require('faker');
const http = require('http');
const url = require('url');

const server = http.createServer();

server.on('request', function (request, response) {
  const parsedUrl = url.parse(request.url);
  console.log('parsedUrl:', parsedUrl);

  const randomName = faker.name.findName();

  response.write('Your random name: ' + randomName);
  response.end();
});

server.listen(3000);
console.log(‘Server is running.’);

Aquele console.log(‘parsedUrl:’, parsedUrl) irá mostrar parecido com isso:

parsedUrl: Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: '?template=Hello%20%7B%7Bname.firstName%7D%7D',
  query: 'template=Hello%20%7B%7Bname.firstName%7D%7D',
  pathname: '/',
  path: '/?template=Hello%20%7B%7Bname.firstName%7D%7D',
  href: '/?template=Hello%20%7B%7Bname.firstName%7D%7D'
}

Basicamente, a responsabilidade do módulo url é tratar urls.

Vamos utilizar o parâmetro query, que contém a parte da querystring da nossa url que foi “parseada”.

Utilizamos o módulo querystring para parsear a nossa query string e retirar parâmetros que desejamos.

const faker = require('faker');
const http = require('http');
const url = require('url');
const querystring = require('querystring');

const server = http.createServer();

server.on('request', function (request, response) {
  const parsedUrl = url.parse(request.url);
  const parameters = querystring.parse(parsedUrl.query);

  console.log('parameters:', parameters);

  const randomName = faker.name.findName();

  response.write('Your random name: ' + randomName);
  response.end();
});

server.listen(3000);
console.log('Server is running.');

console.log(‘parameters:’, parameters) irá mostrar algo assim:

parameters: { template: 'Hello {{name.firstName}}' }

Agora que temos os parâmetros que desejamos, vamos passar esse parâmetro para o faker.fake() e enviar o resultado de voltar para o client.

const faker = require('faker');
const http = require('http');
const url = require('url');
const querystring = require('querystring');

const server = http.createServer();

server.on('request', function (request, response) {
  const parsedUrl = url.parse(request.url);
  const parameters = querystring.parse(parsedUrl.query);

  const result = faker.fake(parameters.template);

  response.write(result);
  response.end();
});

server.listen(3000);
console.log('Server is running.');

Reiniciaremos a aplicação:

$ curl -G "localhost:3000" --data-urlencode "template=Hello {{name.firstName}}"

Hello Fidel

Vamos colocar mais coisas na aplicação?

Mas, antes, vamos colocar mais uma dependência, o nodemon.

Você já deve estar cansado de reiniciar sua aplicação toda vez que altera o código e ele irá resolver isso para nós.

$ npm install --save-dev nodemon

Uma dica é rodar o comando com a opção –save-dev, que irá incluir automaticamente a dependência no seu package.json, só que em uma seção chamada devDependencies. É bom concentrar bibliotecas que são utilizadas somente no momento do desenvolvimento aqui.

E alterar comando start no package.json.

{
  "name": "fakemytemplate",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "nodemon index.js",
    "test": "echo "Error: no test specified" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "faker": "^3.1.0"
  },
  "devDependencies": {
    "nodemon": "^1.9.2"
  }
}

Agora o nodemon irá reiniciar a aplicação toda vez que algum arquivo for alterado.

Vamos acrescentar uma funcionalidade: Toda vez que o servidor receber uma requisição POST, na rota /template, com o template no corpo da requisição, ele irá responder com o resultado do faker.fake().

$ curl 
    -X POST 
    -H "Content-Type: application/json" 
    -d '{"template": "Hello {{name.firstName}}"}' 
    localhost:3000/template

Hello Steve

Vamos modificar no nosso handler do evento request.

const faker = require('faker');
const http = require('http');
const url = require('url');
const querystring = require('querystring');

const server = http.createServer();

function RootController(request, response) {
  const parsedUrl = url.parse(request.url);
  const parameters = querystring.parse(parsedUrl.query);

  const result = faker.fake(parameters.template);

  response.write(result);
  response.end();
}

function TemplateController(request, response) {
  /* handle the POST /template request here */
  response.end();
}

const routes = {
  '/': {
    'GET': RootController
  },
  '/template': {
    'POST': TemplateController
  }
};

server.on('request', function (request, response) {
  const parsedUrl = url.parse(request.url);

  const routeHandler = routes[parsedUrl.pathname] &&
                       routes[parsedUrl.pathname][request.method];

  return route(request, response);
});

server.listen(3000);
console.log('Server is running.');

Como podemos ver, fizemos uma espécie de roteamento pelo caminho da url em parsedUrl.pathname e pelo método (GET, POST, PUT…) em request.method.

Para fazer uma associação com o tradicional MVC, separamos o código que trata da request e envia a resposta em uma função separada, que nomeamos RootController.

Note que estou passando os objetos request e response para a controller para que ele tenha acesso aos devidos objetos.

Vamos colocar também um “default”. Caso não for encontrado nenhuma controller para a rota, enviaremos um status code 404, Not Found.

const faker = require('faker');
const http = require('http');
const url = require('url');
const querystring = require('querystring');

const server = http.createServer();

function RootController(request, response) {
  const parsedUrl = url.parse(request.url);
  const parameters = querystring.parse(parsedUrl.query);

  const result = faker.fake(parameters.template);

  response.write(result);
  response.end();
}

function TemplateController(request, response) {
  /* handle the POST /template request here */
  response.end();
}

function NotFoundController(request, response) {
    response.statusCode = 404;
    response.write('Not found.');
    response.end();
}

const routes = {
  '/': {
    'GET': RootController
  },
  '/template': {
    'POST': TemplateController
  }
};

server.on('request', function (request, response) {
  const parsedUrl = url.parse(request.url);

  const routeHandler = routes[parsedUrl.pathname] &&
                       routes[parsedUrl.pathname][request.method];

  if (!routeHandler) {
    return NotFoundController(request, response);
  }

  return routeHandler(request, response);
});

server.listen(3000);
console.log('Server is running.');

<p>Recomendo que você vá testando a aplicação em cada modificação. Para fazer requests recomendo o próprio curl. Caso queira ficar na linha de comando, use o Postman, plugin para o Chrome.

Agora o nosso arquivo index.js está grande e confuso.

Vamos colocar essas controllers em arquivos separados.

Criaremos uma pasta chamada controllers onde teremos 3 controllers: o root.js, template.js e o not_found.js.

Separaremos as rotas também. Criaremos, na pasta raíz mesmo, um arquivo chamado router.js.

A estrutura de arquivos ficará mais ou menos assim:

| controllers
|   | not_found.js
|   | root.js
|   | template.js
|
| node_modules
|   | ...
|
| index.js
| package.json
| router.js

Queremos um index.js limpo. Sem as controllers e o roteamento.

/* ----- index.js ----- */

const http = require('http');
const router = require('./router');

const server = http.createServer();

server.on('request', function (request, response) {
  router(request, response);
});

server.listen(3000);
console.log('Server is running.');

Ficou bem mais simples, não?

Notou que importamos um módulo chamado router do caminho ‘./router’? O Node.JS acompanha o máximo das especificações feitas no CommonJS. Incluindo a especificação de módulos.

Na especificação, note que módulos que são nativos do Node.JS, ou módulos que estão instalados na pasta node_modules, devem ser requisitados somente com seu nome. Por exemplo: require(‘http’) ou require(‘faker’). Para módulos que não são esses casos, deve ser fornecido o seu caminho No exemplo, o require(‘./router’) irá procurar pelo arquivo router.js na mesma pasta de onde a aplicação está rodando.

Hora de migrar os devidos códigos para os arquivos. Começando pelo router.js.

/* ----- router.js ----- */

const url = require('url');

const RootController = require('./controllers/root');
const TemplateController = require('./controllers/template');
const NotFoundController = require('./controllers/not_found');

const routes = {
  '/': {
    'GET': RootController
  },
  '/template': {
    'POST': TemplateController
  }
};

function router(request, response) {
  const parsedUrl = url.parse(request.url);

  const routeHandler = routes[parsedUrl.pathname] &&
                       routes[parsedUrl.pathname][request.method];

  if (!routeHandler) {
    return NotFoundController(request, response);
  }

  return routeHandler(request, response);
}

module.exports = router;

Destaquei a última linha do código acima o module.exports.

Este é um objeto especial. É onde é associado o objeto, ou valor, ou função, que desejamos que o módulo exporte. No caso, o nosso módulo router.js está exportando apenas a função router.

Então, quando o módulo for importado no index.js…

/* ----- index.js ----- */

> const router = require('./router');

A variável router receberá a função router que estamos exportando via module.exports.

Também percebemos que estamos importante as controllers:

/* ----- router.js ----- */

> const RootController = require('./controllers/root');
> const TemplateController = require('./controllers/template');
> const NotFoundController = require('./controllers/not_found');

Então, vamos migrar o código das devidas controllers para seus respectivos arquivos e exportar suas funções.

/* ----- controllers/root_controller.js ----- */

const faker = require('faker');
const url = require('url');
const querystring = require('querystring');

function RootController(request, response) {
  const parsedUrl = url.parse(request.url);
  const parameters = querystring.parse(parsedUrl.query);

  const result = faker.fake(parameters.template);

  response.write(result);
  response.end();
}

module.exports = RootController;

Não vá esquecer de importar o faker, url e o querystring.

/* ----- controllers/template_controller.js ----- */

function TemplateController(request, response) {
  /* handle the POST /template request here */
  response.end();
}

module.exports = TemplateController;

Por enquanto ele não está fazendo nada, somente encerrando a resposta. Daqui a pouco nós vamos colocar mais coisas nele.

/* ----- controllers/not_found.js ----- */

function NotFoundController(request, response) {
    response.statusCode = 404;
    response.write('Not found.');
    response.end();
}

module.exports = NotFoundController;

Será que vai dar certo?

--- GET /
$ curl -G "localhost:3000" 
       --data-urlencode "template=Hello {{name.firstName}}"

Hello Trevor




--- POST /template
$ curl -X POST 
       -H "Content-Type: application/json" 
       -d '{"template": "Hello {{name.firstName}}"}' 
       localhost:3000/template

** não vai aparecer nada, pois estamos somente encerrando a resposta, por enquanto. **




--- GET /xablau (ou qualquer outro endereço)
$ curl localhost:3000/xablau

Not found.

Agora temos uma estrutura mais legal para prosseguir e construir o TemplateController, que ainda está em branco.

Atualmente:

/* ----- controllers/template_controller.js ----- */

function TemplateController(request, response) {
  /* handle the POST /template request here */
  response.end();
}

module.exports = TemplateController;

Nosso primeiro passo é conseguir pegar o conteúdo do body da request.

Caso ainda não tenha percebido, o request é um stream, ou seja, é uma instância do EventEmitter. Logo, poderá colocar listeners de eventos no request.

No Node.JS, quando ele recebe uma request, ele não espera que todo o conteúdo da request seja recebido. Para pegar informações da request, devemos esperar todo conteúdo dele chegar e, só então, extrair o conteúdo necessário.

Esta é uma característica bem comum de Node.JS. A maioria das operações que envolvem I/O são retornados objetos Streams.

Basicamente, para o nosso caso, vamos utilizar dois eventos. O data e o end, para implementar algo parecido com o que está nesse exemplo.

Vamos criar uma função que recebe dois argumentos: o objeto request e um callback. Ele irá extrair o conteúdo do body da request, e, ao encerrar, chamar o callback.

function extractBody(request, callback) {
  let body = '';

  request.setEncoding('utf-8');
  request.on('data', (chunk) => body += chunk);
  request.on('end', () => {
    if (request.headers['content-type'] === 'application/json') {
      return callback(JSON.parse(body));
    }

    return callback(body);
  });
}

O let, utilizado em let body = ‘’, define uma variável que pode ser modificada no futuro. No caso, estamos modificando ela no request.on(‘data’, (chunk) => body += chunk);

A sintaxe utilizada em (chunk) => body += chunk é chamda de Arrow Function. Essa linha seria o equivalente à function (chunk) { return body += chunk; }. Deixando ele muito mais curto.

Note que você usou a Arrow Function em seguida. Porém com {}. Ele é utilizado para colocar mais que uma linha no bloco de código da Arrow Function. Vale notar que quando não utilizamos as {} o return fica implícito.

Aproveitando: Quando recebermos no header que o Content-Type é application/json, parseamos o body para retornar um objeto.

Vamos implementar ele no TemplateController. Fazer ele criar o template e enviar o resultado.

const faker = require('faker');

function extractBody(request, callback) {
  let body = '';

  request.setEncoding('utf-8');
  request.on('data', (chunk) => body += chunk);
  request.on('end', () => {
    if (request.headers['content-type'] === 'application/json') {
      return callback(JSON.parse(body));
    }

    return callback(body);
  });
}

function TemplateController(request, response) {
  extractBody(request, (body) => {
    const result = faker.fake(body.template);

    response.write(result);
    response.end();
  });
}

module.exports = TemplateController;

Os iniciantes em Node.JS podem achar tudo isso estranho porque não fizemos algo assim no TemplateController:

function TemplateController(request, response) {
  const body = extractBody(request);
  const result = faker.fake(body.template);

  response.write(result);
  response.end();
}

Lembre-se! Operações de I/O são assíncronos. Incluindo o stream de dados da request. Por isso, devemos continuar executando o nosso código apenas quando recebermos todo o conteúdo da request.

O padrão de callback é muito utilizado no Node.JS para tratar esse tipo de instruções assíncronas. Onde você passará uma função como argumento de outra função e executa algo assíncrono. Só então chama de volta (callback) a função passada como argumento.

Vamos mover essa função extractBody para outro arquivo. Vamos criar uma pasta chamada utils e criar um arquivo extract_body.js dentro.

/* ----- utils/extract_body.js ----- */

function extractBody(request, callback) {
  let body = '';

  request.setEncoding('utf-8');
  request.on('data', (chunk) => body += chunk);
  request.on('end', () => {
    if (request.headers['content-type'] === 'application/json') {
      return callback(JSON.parse(body));
    }

    return callback(body);
 });
}

module.exports = extractBody;

Agora é só importar ela no TemplateController.

/* ----- controllers/template.js ----- */

const faker = require('faker');
const extractBody = require('../utils/extract_body');

function TemplateController(request, response) {
  extractBody(request, (body) => {
    const template = body.template;
    const result = faker.fake(template);

    response.write(result);
    response.end();
  });
}

module.exports = TemplateController;

Não custa testar para ver se está tudo ok.

$ curl -X POST 
       -H "Content-Type: application/json" 
       -d '{"template": "Hello {{name.firstName}}"}' 
       localhost:3000/template

Hello Urban

Para melhorar um pouco, vamos fazer o nosso TemplateController enviar a resposta em JSON.

const faker = require('faker');
const extractBody = require('../utils/extract_body');

function TemplateController(request, response) {
  extractBody(request, (body) => {
  const template = body.template;
  const result = faker.fake(template);

  response.setHeader(
    'content-type', 'application/json; charset=UTF-8'
  );

  response.write(JSON.stringify({ result }));
  response.end();
 });
}

module.exports = TemplateController;

Dá para notar, em JSON.stringify({ result }), que você utilizou uma funcionalidade nova no ES6. Ou seja, { result } é equivalente a { result: result }

$ curl -v -X POST 
       -H "Content-Type: application/json" 
       -d '{"template": "Hello {{name.firstName}}"}' 
       localhost:3000/template

< HTTP/1.1 200 OK
< content-type: application/json; charset=UTF-8
< Date: Wed, 08 Jun 2016 14:15:35 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked

{"result":"Hello Junius"}

Jornada longa, mas aprendemos a fazer uma pequena aplicação Node.JS

Temos vários pontos para melhorar nessa aplicação: Tratar os erros que podem dar no fake.fake(), responder corretamente com 400 Bad Request, fazer o nosso RootController mostrar uma espécie de ReadMe que mostre como utilizar o serviço ou escrever testes para a aplicação apenas para citar alguns exemplos.

Você não precisa se restringir aos módulos nativos do Node.JS. Existem frameworks e bibliotecas que facilitam bastante a maior parte do trabalho que tivemos aqui. Dê uma olhada, por exemplo, no koa.js ou restify, nos drivers de mongodb, mysql e postgres. Explore o npm.

Segue o link para o código final do nosso exemplo:Link

Até mais!