Adicione suporte CORS à sua API Express + TypeScript

April 07, 2021
Escrito por
Mia Adjei
Twilion
Revisado por

Adicione suporte CORS à sua API Express + TypeScript

Imagine que você acabou de criar uma excelente API usando Node.js, Express e TypeScript. Você também criou um aplicativo da Web do lado do cliente e está pronto para acionar o aplicativo em seu navegador, colocá-lo para funcionar com seu servidor e, esperamos, compartilhá-lo com o mundo.

Você abre uma janela do navegador e vai até onde seu aplicativo está sendo executado e, em seguida, abre o console em suas ferramentas de desenvolvedor. Seu aplicativo faz sua primeira chamada de API para seu servidor... mas, em vez dos dados esperados para preencher seu aplicativo, você recebe um erro em seu console como este:

Access to fetch at 'http://localhost:5000/rooms' from origin 'http://localhost:3000' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present 
on the requested resource. If an opaque response serves your needs, set the 
request's mode to 'no-cors' to fetch the resource with CORS disabled.

Nossa! Este erro é devido a restrições de Compartilhamento de recursos de origem cruzada (CORS). Embora isso possa ser frustrante, é uma situação comum para muitos desenvolvedores.

Mas, o que é o CORS? E como você pode contornar essa mensagem de erro e obter os dados do seu servidor para o seu aplicativo? Este tutorial mostrará como adicionar suporte de CORS à sua API Express e TypeScript para que você possa continuar avançando com seus projetos interessantes.

O que é o Compartilhamento de recursos de origem cruzada (CORS)?

O compartilhamento de recursos de origem cruzada (CORS) é um protocolo de segurança em navegadores modernos que permite ou restringe o compartilhamento de recursos entre diferentes origens, dependendo de qual origem iniciou a solicitação HTTP.

Uma origem descreve onde uma solicitação é iniciada. As origens têm duas partes necessárias (esquema e nome de host) e uma parte opcional (porta), como mostrado abaixo:

https://www.twilio.com
  ^       ^
  |       |
scheme hostname


http://localhost:5000
  ^       ^       ^
  |       |       |
scheme hostname  port

O navegador adiciona um cabeçalho de Origem a todas as solicitações que faz. Quando uma solicitação chega ao servidor, se a origem na solicitação for incluída na lista de origens que têm permissão para recuperar recursos desse servidor, ele adicionará um cabeçalho Access-Control-Allow-Origin à sua resposta para informar ao navegador que o conteúdo está acessível a essa origem específica.

Por exemplo, o seguinte mostra que todas as origens têm permissão para solicitar recursos:

Access-Control-Allow-Origin : *

No entanto, o cabeçalho abaixo informa ao navegador que somente solicitações de https://www.twilio.com são recursos permitidos:

Access-Control-Allow-Origin : https://www.twilio.com

É provável que você esteja usando portas diferentes durante seu trabalho de desenvolvimento local. Se você observar a mensagem de erro de exemplo da introdução desta postagem, poderá ver que, neste exemplo, o aplicativo está sendo veiculado em localhost:3000, mas está tentando buscar dados de localhost:5000. Como as duas portas são diferentes, isso significa que elas são de origens diferentes. Assim, por padrão, o navegador negará essa solicitação:

Access to fetch at 'http://localhost:5000/rooms' from origin 'http://localhost:3000' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present 
on the requested resource. If an opaque response serves your needs, set the 
request's mode to 'no-cors' to fetch the resource with CORS disabled.

Para corrigir isso e permitir que os dados fluam entre o servidor e o cliente, você pode adicionar o suporte CORS ao servidor. Neste tutorial, você usara o pacote npm cors para adicionar o middleware que definirá o cabeçalho Access-Control-Allow-Origin e especificar os domínios que são permitidos para acessar os recursos de seu servidor.

Se quiser ler ainda mais sobre o CORS, consulte a documentação do Mozilla sobre este assunto.

Configure o CORS no seu servidor Express

Para começar, você precisará de:

As informações do CORS neste tutorial podem ser usadas para qualquer projeto Express. No entanto, para os fins deste exemplo, você pode querer seguir o código no projeto Express listado acima. Esta API de vídeo é criada com Express e TypeScript, portanto, é um ótimo projeto de amostra com o qual trabalhar.

Se você estiver seguindo o projeto de amostra, siga as instruções no README.md do repositório para começar a trabalhar.

Depois de executar o comando npm run start, você verá uma instrução de log no terminal que permite saber se o servidor está sendo executado na porta 5000:

Express server listening on port 5000

Se, em vez disso, você estiver usando sua própria API Express, isso também é ótimo! Suas solicitações cURL provavelmente serão diferentes, então substitua os parâmetros que fazem sentido para o seu projeto.

Execute uma simulação com um comando cURL

Se você estiver usando o código de exemplo do repositório acima, abra uma segunda janela de terminal e tente executar o seguinte comando cURL:

curl -H "Origin: http://localhost:3000" --head http://localhost:5000/rooms

Com esse comando cURL, você está simulando como o navegador emite uma solicitação. Neste caso, seu servidor está executando http://localhost:5000 e seu aplicativo está sendo executado e fazendo uma solicitação a partir da origem localhost:3000. Neste exemplo, seu "aplicativo" está tentando solicitar uma lista de salas de bate-papo com vídeo.

A resposta exibida na janela do terminal será semelhante à resposta abaixo:

HTTP/1.1 200 OK
X-Powered-By: Express
Vary: Origin
Content-Type: application/json; charset=utf-8
Content-Length: 52
ETag: <ETag>
Date: Tue, 30 Mar 2021 16:45:54 GMT
Connection: keep-alive
Keep-Alive: timeout=5

Se você examinar essa saída, perceberá que não há um cabeçalho Access-Control-Allow-Origin nesta resposta. Se essa fosse realmente uma resposta recebida por um navegador, ele bloquearia a solicitação.

É hora de atualizar seu servidor para que ele responda com o cabeçalho Access-Control-Allow-Origin para solicitações específicas de origem cruzada.

Adicione o pacote npm cors ao seu projeto Express

Na janela do terminal, navegue até a raiz do projeto. Se você estiver acompanhando o código de exemplo, a raiz do projeto é o diretório express-video-api.

Instale o pacote cors e seus tipos TypeScript executando os seguintes comandos:

npm install cors
npm install --save-dev @types/cors

Se você observar o arquivo package.json, você verá que o cors foi adicionado como uma dependency e @types/cors foi adicionado a devDependencies.

Configure as opções de CORS

Em seguida, abra o arquivo que é o ponto de entrada para seu aplicativo. Se você estiver seguindo com o código de exemplo, este arquivo é src/index.ts.

Em seu editor de código e abaixo da linha em que você importou express, importe cors também:

import cors from 'cors';

Adicione a seguinte linha acima de app.use(express.json()); para permitir que seu servidor Express use o middleware cors:

app.use(cors); /* NEW */

app.use(express.json());

Em seguida, adicione uma lista das origens que você deseja permitir acessar recursos em seu servidor e passe essa lista para suas opções de CORS. Neste tutorial, você adicionará localhost:3000 como a origem que você quer permitir:

// Add a list of allowed origins.
// If you have more origins you would like to add, you can add them to the array below.
const allowedOrigins = ['http://localhost:3000'];

const options: cors.CorsOptions = {
  origin: allowedOrigins
};

Em seguida, passe estas opções como um argumento para seu middleware cors:

app.use(cors(options));

Seu servidor Express notará as alterações e a atualização.

Neste ponto, se você estiver acompanhando o projeto de exemplo, seu código deverá ser parecido com o código abaixo:

import express from 'express';
import cors from 'cors';
import config from './config';
import roomsRouter from './routes/room';
import { Twilio } from 'twilio';

// Initialize Twilio client
const getTwilioClient = () => {
  if (!config.TWILIO_ACCOUNT_SID || !config.TWILIO_API_KEY || !config.TWILIO_API_SECRET) {
    throw new Error(`Unable to initialize Twilio client`);
  }
  return new Twilio(config.TWILIO_API_KEY, config.TWILIO_API_SECRET, { accountSid: config.TWILIO_ACCOUNT_SID })
}

export const twilioClient = getTwilioClient();

const app = express();

// Add a list of allowed origins.
// If you have more origins you would like to add, you can add them to the array below.
const allowedOrigins = ['http://localhost:3000'];

const options: cors.CorsOptions = {
  origin: allowedOrigins
};

// Then pass these options to cors:
app.use(cors(options));

app.use(express.json());

// Forward requests for the /rooms URI to our rooms router
app.use('/rooms', roomsRouter);

app.listen(5000, () => {
  console.log('Express server listening on port 5000');
});

Teste se o CORS está funcionando

Agora que você configurou as opções de CORS no servidor, tente executar a seguinte simulação de comando cURL no terminal novamente:

curl -H "Origin: http://localhost:3000" --head http://localhost:5000/rooms

Se você verificar a resposta, perceberá que agora há um cabeçalho Access-Control-Allow-Origin com a origem http:://localhost:3000! Isso significa que, quando você executar seu aplicativo do lado do cliente localhost:3000, o aplicativo conseguirá recuperar recursos de seu servidor.

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://localhost:3000
Vary: Origin
Content-Type: application/json; charset=utf-8
Content-Length: 52
ETag: <ETag>
Date: Tue, 30 Mar 2021 16:46:39 GMT
Connection: keep-alive
Keep-Alive: timeout=5

Em um teste separado, tente executar o seguinte comando cURL também:

curl -H "Origin: http://localhost:4000" --head http://localhost:5000/rooms

Observe que, neste comando, você alterou a origem em sua solicitação para http://localhost:4000, que não estava na sua lista de origens permitidas. A resposta que retorna não tem o cabeçalho Access-Control-Allow-Origin:

HTTP/1.1 200 OK
X-Powered-By: Express
Vary: Origin
Content-Type: application/json; charset=utf-8
Content-Length: 52
ETag: <ETag>
Date: Tue, 30 Mar 2021 16:40:47 GMT
Connection: keep-alive
Keep-Alive: timeout=5

Isso significa que se alguém tentar acessar seu servidor a partir de um aplicativo em execução em localhost:4000, não conseguirá acessar os recursos. Em vez disso, um erro CORS semelhante ao anterior aparecerá em seu console.

O que vem a seguir para seu projeto Express API?

Se quiser conferir todo o código de exemplo atualizado deste tutorial, você encontra esse código no branch added-cors deste repositório no GitHub. Ou, se você quiser apenas uma 'colinha' de como implementar o CORS em seu próprio aplicativo, confira o gist aqui.

Agora que sabe como adicionar o suporte CORS ao seu servidor Express e TypeScript, está tudo pronto para ligar o seu servidor a um aplicativo do lado do cliente. Que tipo de aplicativo você tem em mente? Estamos ansiosos para ver o que você vai criar.

Este artigo foi traduzido do original "Add CORS Support to Your Express + TypeScript API". Enquanto melhoramos nossos processos de tradução, adoraríamos receber seus comentários em help@twilio.com - contribuições valiosas podem render brindes da Twilio.