Gulp - Criando redirecionamentos com gulp-connect + connect-modrewrite

A situação é basicamente essa: Você está trabalhando em uma SPA, e usando Gulp para subir seu webserver. Você tem uma API Rest que foi feita em outra linguagem, e responde em outra porta. E o pior: essa aplicação não tem um header que previna o problema com CORS. Como resolver isso?

Vou te mostrar nesse post! Vem comigo :D

Na situação acima, você teria algumas URLs locais da API Rest para consultar, que na verdade, deveriam responder em outra porta. Vamos exemplificar.

Estrutura de arquivos

Primeiro precisamos criar nossa estrutura de arquivos. Crie um novo diretório e use o comando abaixo para criá-la:

1
mkdir api app && touch app/gulpfile.js app/index.html app/main.js api/app.js && echo "{}" > api/package.json && echo "{}" > app/package.json

Que vai gerar a seguinte estrutura:

1
2
3
4
5
6
7
8
9
.
├── api
│   ├── app.js
│   └── package.json
└── app
├── gulpfile.js
├── index.html
├── main.js
│   └── package.json

Agora, acesse o diretório api, e instale os módulos abaixo:

1
npm i --save-dev connect connect-route

Criando a API Rest

Feito isso, vamos criar a API Rest. No arquivo api/app.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
'use strict';

var connect = require( 'connect' );
var connectRoute = require( 'connect-route' );
var app = connect();

var users = {
joao: { name: 'João da Silva', age: 30 },
maria: { name: 'Maria Firmina', age: 26 },
paulo: { name: 'Paulo Torres', age: 25 }
};

app.use( connectRoute( function( router ) {
router.get( '/api/users', function( req, res, next ) {
res.setHeader( 'Content-Type', 'application/json' );
res.end( JSON.stringify( users ) );
});

router.post( '/api/user/:slug', function( req, res, next ) {
res.setHeader( 'Content-Type', 'application/json' );
res.end( JSON.stringify( users[ req.params.slug ] ) );
});
}));

app.listen( 3000 );

Prometo que em breve eu escrevo um post só explicando como criar uma API Rest :)

Esse arquivo está bastante simples: incluímos nossos módulos connect e connect-route, criamos uma lista de usuários em users que irá responder às URLs: /api/users via GET, onde todos os usuários do objeto serão retornados; e URL:/api/user/:slug`, via POST.

Vamos ver se isso funciona? Execute dentro do diretório api:

1
node app.js

E acesse no seu navegador:

1
http://localhost:3000

Se tudo deu certo, você deve ter um retorno como esse:

1
{"joao":{"name":"João da Silva","age":30},"maria":{"name":"Maria Firmina","age":26},"paulo":{"name":"Paulo Torres","age":25}}

Ótimo, nosso método GET funciona! Agora vamos testar o POST! Para o Chrome, existe uma extensão chamada Postman. Instale-a para testarmos outros verbos HTTP.

Após fazer isso, vamos testar o POST da nossa API:

Fazemos a requisição, via POST, para a URL http://localhost:3000/api/user/joao, e o resultado retornado é o objeto joao!

Pronto! Deixe a API executando e abra uma nova aba no seu terminal. Vamos agora subir o frontend da nossa aplicação em uma porta diferente, para testar um cenário real.

Criando o frontend da aplicação que consumirá o Rest

Vamos começar instalando os módulos do Gulp necessários:

1
npm i --save-dev gulp gulp-connect

Vamos somente subir nosso servidor, por enquanto. No arquivo app/gulpfile.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
'use strict';

var gulp = require( 'gulp' );
var connect = require( 'gulp-connect' )();

gulp.task( 'watch', function() {
// task watch
});

gulp.task( 'connect', function() {
connect.server({
root: '.',
port: 3001
});
});

gulp.task( 'default', [ 'connect', 'watch' ]);

E no arquivo app/index.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Test Gulp ModRewrite</title>
</head>
<body>
<h1>Test Gulp ModRewrite</h1>
<h2>Users:</h2>
<div data-js="container"></div>

<script src="main.js"></script>
</body>
</html>

Agora, precisamos requisitar os dados à nossa API, para que eles sejam mostrados na nossa aplicação. No arquivo app/main.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
;(function( win, doc, undefined ) {
function app() {
var $private = {};
var $public = {};

$public.init = function init() {
$private.getUsers();
};

$private.getUsers = function getUsers() {
var xhr = new XMLHttpRequest();
xhr.open( 'GET', 'http://localhost:3000/api/users' );
xhr.addEventListener( 'readystatechange', $private.readyStateChange, false );
xhr.send();
};

$private.readyStateChange = function readyStateChange() {
var xhr = this;
var $container = doc.querySelector( '[data-js="container"]' );
if( xhr.readyState === 4 ) {
if( xhr.status >= 200 && xhr.status < 300 ) {
$container.innerHTML = xhr.responseText;
}
}
};

return $public;
}

app().init();
})( window, document );

Basicamente fazemos uma requisição Ajax à http://localhost:3000/api/users, via GET, tentando inserir o resultado no elemento div[data-js="container"], que colocamos na tela. E a resposta que nós temos é:

É isso que a gente merece mesmo! :(

Mas podemos contornar essa situação, usando um módulo chamado connect-modrewrite, (valeu Becker xD) que faz reescritas de URL, semelhante ao que você faz com o .htaccess em PHP, mas em NodeJS :D

Como faz?

Instale o módulo em app/:

1
npm i --save-dev connect-modrewrite

Agora, vamos configurá-lo no app/gulpfile.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
'use strict';

var gulp = require( 'gulp' );
var connect = require( 'gulp-connect' );
var modrewrite = require( 'connect-modrewrite' );

gulp.task( 'watch', function() {
// task watch
});

gulp.task( 'connect', function() {
connect.server({
root: '.',
port: 3001,
middleware: function() {
return [
modrewrite([ '/api/users http://localhost:3000/api/users [P]' ])
];
}
});
});

gulp.task( 'default', [ 'connect', 'watch' ]);

Incluímos o módulo e adicionamos, no retorno do parâmetro middleware, dentro de connect.server, o código que vai fazer o proxy da nossa URL. Sempre que a nossa URL apontar para /api/users, na verdade será buscado o endereço http://localhost:3000/api/users.

Agora só precisamos alterar a URL no arquivo app/main.js de http://localhost:3000/api/users para /api/users e testar:

E olha que loucura! Agora temos o resultado correto, e sem erros!

Esse módulo ajuda muito, principalmente nesses casos. Mas ele serve ainda para qualquer tipo de redirect que você precisar fazer :D

Era isso que eu queria mostrar hoje! Até o próximo post! :D

Sobre o #1postperday: https://blog.da2k.com.br/2014/12/31/um-post-por-dia/

Tem alguma sugestão para os próximos posts do #1postperday? Deixe ela aqui: https://github.com/fdaciuk/fdaciuk.github.io/issues/1