Introdução
Recentemente resolvi começar a estudar frontend um pouco mais à sério, e resolvi aproveitar um projeto que estava desenvolvendo a algum tempo, e resolvi aplicar Angular no frontend substituindo completamente o que havia anteriormente, que basicamente eram templates construídos com Template Toolkit dentro do ambiente do Catalyst. Por quê? Bom, várias razões:
1. Mercado
2. Necessidade
Resumidamente, algum engravatado filho da p.. resolveu que 'não valia à pena' pagar 3 pessoas em um time de TI para fazer a porra toda funcionar, e determinou que 'profissionais multifunção'(ou qualquer buzzword bosta do tipo), são a nova tendência de mercado, e deu um nome 'bonitinho' para isso: 'fullstack developer'. A tradução disso é 'especialista em tudo SQN', mas que ganha por apenas uma pessoa. Como 'morrer na praia' não está nos meus planos ainda, resolvi juntar minha atração pelo Angular com a necessidade de aprendê-lo e tentar me divertir enquanto faço isso, se possível.Pessoalmente acho que a idéia do 'fullstack developer' é um grande erro. Mas foda-se a minha opinião! Se valesse alguma coisa nem estaria escrevendo esse artigo pra começo de conversa... :P
Contextualizando o Problema
CORS - Cross Origin Resource Sharing ou, 'Compartilhamento de Recursos com Origem Cruzada' em tradução livre. Trata-se de uma especificação que é utilizada para determinar se um recurso pode ser acessado de um outro domínio ou não, sendo que essa interação pode ou não ocorrer entre o browser e o servidor onde o recurso se encontra. Resumidamente isso acontece segundo as regras do 'same origin police'.
Recursos - No caso de APIs REST, correspondem aos endpoints. Esses tem origem em seus hosts e portas, que são o objeto de foco do CORS.
AngularJS - Trata-se de um framework MVC escrito em Javascript que facilita a organização e manipulação de objetos DOM oferecendo ferramentas úteis para organizar código HTML + CSS + Javascript, e tratar eventos diversos dentro de uma plataforma MVC. É bem popular e bem utilizado para se consumir serviços REST com APIs, por exemplo.
Catalyst - Bom e velho framework MVC feito em Perl. Confiável, flexível e cheio de coisas legais!
Problema
Visão geral da arquitetura do serviço REST
Solução
Na verdade são duas:
1 - Garanta que a origem das requisições(host + porta) são iguais as do seu recurso;
2 - Implemente CORS nos seus recursos
Isso signfica devolver um 'response' com uma série de headers. Os headers são os seguintes:
Access-Control-Allow-Origin: Controla exatamente as origens de requisições permitidas para esse recurso. Você pode ter uma, uma lista deles, ou simplesmente aceitar todos(*)!
Access-Control-Allow-Methods: Controla os métodos http que são aceitos de outras origens pelo recurso.
Access-Control-Allow-Headers: Idem para headers;
Onde colocar isso? Atenção, porque agora falarei apenas em Catalyst!
Considerando que você está(e deveria estar) usando Catalyst::DispatchType::Chained, você deve setar os headers sempre no 'setup' da feature, ou seja, action que representa o primeiro nível da cadeia depois do '/' que é controlado pelo Controller Root. Mas porque não no root? Bom, pra dizer a verdade eu tentei, mas a requisição ficava travada e eu não entendi o porque ainda. Exemplo:
package api::Controller::Login;BEGIN{extends 'Catalyst::Controller';}sub setup :Chained('/') :PathPart('login') :CaptureArgs(0) { my ($self,$c) = @_; $c->response->headers->header( 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers' => $c->request->headers->header("Access-Control-Request-Headers") );
}
É possível centralizar isso, removendo esse código e criando um método dentro da classe da aplicação. Nesse caso, em lib/api.pm. Depois é só referenciar o método utilizando o objeto de contexto do Catalyst ($c).
Fim...
