paint-brush
Quando é hora de dar um descanso ao RESTpor@johnjvester
2,364 leituras
2,364 leituras

Quando é hora de dar um descanso ao REST

por John Vester13m2024/05/13
Read on Terminal Reader

Muito longo; Para ler

Este artigo compara APIs GraphQL e REST para recuperação de dados, mostrando como a flexibilidade e eficiência do GraphQL se destacam em cenários complexos. Ele detalha a implantação do Apollo Server com Heroku e apresenta conteúdo futuro sobre autenticação e dados em tempo real no GraphQL.
featured image - Quando é hora de dar um descanso ao REST
John Vester HackerNoon profile picture
0-item
1-item


Ao longo dos meus anos de construção de serviços, a API RESTful tem sido minha principal opção. No entanto, embora REST tenha seus méritos, isso não significa que seja a melhor abordagem para todos os casos de uso. Ao longo dos anos, aprendi que, ocasionalmente, pode haver alternativas melhores para determinados cenários. Continuar com REST só porque sou apaixonado por ele – quando não é a opção certa – só resulta em dívida tecnológica e em um relacionamento tenso com o proprietário do produto.


Um dos maiores problemas da abordagem RESTful é a necessidade de fazer diversas solicitações para recuperar todas as informações necessárias para uma decisão de negócios.


Por exemplo, vamos supor que eu queira uma visão 360º de um cliente. Eu precisaria fazer os seguintes pedidos:


  • GET /customers/{some_token} fornece as informações básicas do cliente
  • GET /addresses/{some_token} fornece um endereço obrigatório
  • GET /contacts/{some_token} retorna as informações de contato
  • GET /credit/{some_token} retorna informações financeiras importantes


Embora eu entenda que o objetivo subjacente do REST é manter as respostas focadas em cada recurso, esse cenário exige mais trabalho do lado do consumidor. Apenas para preencher uma interface de usuário que ajude uma organização a tomar decisões relacionadas a negócios futuros com o cliente, o consumidor deve fazer várias chamadas


Neste artigo, mostrarei por que o GraphQL é a abordagem preferida em vez de uma API RESTful aqui, demonstrando como implantar o Apollo Server (e o Apollo Explorer) para começar a funcionar rapidamente com o GraphQL.


Pretendo construir minha solução com Node.js e implantar minha solução no Heroku.

Quando usar GraphQL sobre REST

Existem vários casos de uso comuns em que GraphQL é uma abordagem melhor que REST:


  • Quando você precisar de flexibilidade na forma como recupera dados: você pode buscar dados complexos de vários recursos, mas tudo em uma única solicitação . (Vou mergulhar nesse caminho neste artigo.)
  • Quando a equipe de front-end precisa evoluir a UI com frequência: Os requisitos de dados em rápida mudança não exigirão que o back-end ajuste os endpoints e cause bloqueadores.
  • Quando você deseja minimizar a busca excessiva e insuficiente : às vezes, o REST exige que você atinja vários endpoints para coletar todos os dados necessários (busca insuficiente), ou atingir um único endpoint retorna muito mais dados do que você realmente precisa (busca excessiva). buscando).
  • Quando você trabalha com sistemas e microsserviços complexos: às vezes, várias fontes só precisam acessar uma única camada de API para seus dados. GraphQL pode fornecer essa flexibilidade por meio de uma única chamada de API .
  • Quando você precisa de dados em tempo real enviados para você: GraphQL apresenta assinaturas , que fornecem atualizações em tempo real. Isso é útil no caso de aplicativos de bate-papo ou feeds de dados ao vivo. (Abordarei esse benefício com mais detalhes em um artigo de acompanhamento.)

O que é o servidor Apollo?

Como minhas habilidades com GraphQL não são refinadas, decidi usar o Apollo Server para este artigo.


Apollo Server é um servidor GraphQL que funciona com qualquer esquema GraphQL. O objetivo é simplificar o processo de construção de uma API GraphQL. O design subjacente integra-se bem com estruturas como Express ou Koa. Explorarei a capacidade de aproveitar assinaturas (por meio da biblioteca graphql-ws ) para dados em tempo real em meu próximo artigo.


Onde o Apollo Server realmente brilha é o Apollo Explorer, uma interface web integrada que os desenvolvedores podem usar para explorar e testar suas APIs GraphQL. O estúdio será perfeito para mim, pois permite a fácil construção de consultas e a possibilidade de visualizar o esquema da API em formato gráfico.

Meu caso de uso do Customer 360

Para este exemplo, vamos supor que precisamos do seguinte esquema para fornecer uma visão 360º do cliente:


 type Customer { token: String name: String sic_code: String } type Address { token: String customer_token: String address_line1: String address_line2: String city: String state: String postal_code: String } type Contact { token: String customer_token: String first_name: String last_name: String email: String phone: String } type Credit { token: String customer_token: String credit_limit: Float balance: Float credit_score: Int }


Pretendo me concentrar nas seguintes consultas GraphQL:


 type Query { addresses: [Address] address(customer_token: String): Address contacts: [Contact] contact(customer_token: String): Contact customers: [Customer] customer(token: String): Customer credits: [Credit] credit(customer_token: String): Credit }


Os consumidores fornecerão o token para o Cliente que desejam visualizar. Esperamos também recuperar os objetos Endereço, Contato e Crédito apropriados. O objetivo é evitar fazer quatro chamadas de API diferentes para todas essas informações, em vez de fazer uma única chamada de API.

Primeiros passos com o servidor Apollo

Comecei criando uma nova pasta chamada graphql-server-customer em minha estação de trabalho local. Em seguida, usando a seção Introdução da documentação do Apollo Server, segui as etapas um e dois usando uma abordagem Typescript.


A seguir, defini meu esquema e também incluí alguns dados estáticos para teste. Normalmente, nos conectaríamos a um banco de dados, mas os dados estáticos funcionarão bem para esta demonstração.


Abaixo está meu arquivo index.ts atualizado:


 import { ApolloServer } from '@apollo/server'; import { startStandaloneServer } from '@apollo/server/standalone'; const typeDefs = `#graphql type Customer { token: String name: String sic_code: String } type Address { token: String customer_token: String address_line1: String address_line2: String city: String state: String postal_code: String } type Contact { token: String customer_token: String first_name: String last_name: String email: String phone: String } type Credit { token: String customer_token: String credit_limit: Float balance: Float credit_score: Int } type Query { addresses: [Address] address(customer_token: String): Address contacts: [Contact] contact(customer_token: String): Contact customers: [Customer] customer(token: String): Customer credits: [Credit] credit(customer_token: String): Credit } `; const resolvers = { Query: { addresses: () => addresses, address: (parent, args, context) => { const customer_token = args.customer_token; return addresses.find(address => address.customer_token === customer_token); }, contacts: () => contacts, contact: (parent, args, context) => { const customer_token = args.customer_token; return contacts.find(contact => contact.customer_token === customer_token); }, customers: () => customers, customer: (parent, args, context) => { const token = args.token; return customers.find(customer => customer.token === token); }, credits: () => credits, credit: (parent, args, context) => { const customer_token = args.customer_token; return credits.find(credit => credit.customer_token === customer_token); } }, }; const server = new ApolloServer({ typeDefs, resolvers, }); const { url } = await startStandaloneServer(server, { listen: { port: 4000 }, }); console.log(`Apollo Server ready at: ${url}`); const customers = [ { token: 'customer-token-1', name: 'Acme Inc.', sic_code: '1234' }, { token: 'customer-token-2', name: 'Widget Co.', sic_code: '5678' } ]; const addresses = [ { token: 'address-token-1', customer_token: 'customer-token-1', address_line1: '123 Main St.', address_line2: '', city: 'Anytown', state: 'CA', postal_code: '12345' }, { token: 'address-token-22', customer_token: 'customer-token-2', address_line1: '456 Elm St.', address_line2: '', city: 'Othertown', state: 'NY', postal_code: '67890' } ]; const contacts = [ { token: 'contact-token-1', customer_token: 'customer-token-1', first_name: 'John', last_name: 'Doe', email: '[email protected]', phone: '123-456-7890' } ]; const credits = [ { token: 'credit-token-1', customer_token: 'customer-token-1', credit_limit: 10000.00, balance: 2500.00, credit_score: 750 } ];


Com tudo configurado conforme o esperado, executamos o seguinte comando para iniciar o servidor:


 $ npm start


Com o servidor Apollo rodando na porta 4000, usei a URL http://localhost:4000/ para acessar o Apollo Explorer. Então configurei o seguinte exemplo de consulta:


 query ExampleQuery { addresses { token } contacts { token } customers { token } }


É assim que fica no Apollo Explorer:


Apertando o botão Consulta de exemplo , validei que a carga útil da resposta estava alinhada com os dados estáticos que forneci no index.ts :


 { "data": { "addresses": [ { "token": "address-token-1" }, { "token": "address-token-22" } ], "contacts": [ { "token": "contact-token-1" } ], "customers": [ { "token": "customer-token-1" }, { "token": "customer-token-2" } ] } }


Antes de prosseguir no meu caso de uso do Customer 360, eu queria executar esse serviço na nuvem.

Implantando o Apollo Server no Heroku

Como este artigo é sobre como fazer algo novo, eu queria ver o quão difícil seria implantar meu servidor Apollo no Heroku.


Eu sabia que precisava resolver as diferenças de número de porta entre a execução local e a execução em algum lugar na nuvem. Atualizei meu código para iniciar o servidor conforme mostrado abaixo:


 const { url } = await startStandaloneServer(server, { listen: { port: Number.parseInt(process.env.PORT) || 4000 }, });


Com esta atualização, usaremos a porta 4000, a menos que haja um valor PORT especificado em uma variável de ambiente.


Usando o Gitlab, criei um novo projeto para esses arquivos e entrei em minha conta Heroku usando a interface de linha de comando (CLI) do Heroku:


 $ heroku login


Você pode criar um novo aplicativo no Heroku com sua CLI ou a interface da web do painel do Heroku. Para este artigo, usaremos a CLI:


 $ heroku create jvc-graphql-server-customer


O comando CLI retornou a seguinte resposta:


 Creating ⬢ jvc-graphql-server-customer... done https://jvc-graphql-server-customer-b62b17a2c949.herokuapp.com/ | https://git.heroku.com/jvc-graphql-server-customer.git


O comando também adicionou o repositório usado pelo Heroku como remoto automaticamente:


 $ git remote heroku origin


Por padrão, o Apollo Server desativa o Apollo Explorer em ambientes de produção. Para minha demonstração, quero deixá-lo rodando no Heroku. Para fazer isso, preciso definir a variável de ambiente NODE_ENV para desenvolvimento. Posso definir isso com o seguinte comando CLI:


 $ heroku config:set NODE_ENV=development


O comando CLI retornou a seguinte resposta:


 Setting NODE_ENV and restarting ⬢ jvc-graphql-server-customer... done, v3 NODE_ENV: development


Agora estamos em condições de implantar nosso código no Heroku:


 $ git commit --allow-empty -m 'Deploy to Heroku' $ git push heroku


Uma visualização rápida do painel Heroku mostra meu servidor Apollo funcionando sem problemas:


Se você é novo no Heroku, este guia mostrará como criar uma nova conta e instalar o Heroku CLI.

Critérios de aceitação atendidos: exemplo do meu cliente 360

Com o GraphQL, posso atender aos critérios de aceitação para meu caso de uso do Customer 360 com a seguinte consulta:


 query CustomerData($token: String) { customer(token: $token) { name sic_code token }, address(customer_token: $token) { token customer_token address_line1 address_line2 city state postal_code }, contact(customer_token: $token) { token, customer_token, first_name, last_name, email, phone }, credit(customer_token: $token) { token, customer_token, credit_limit, balance, credit_score } }


Tudo o que preciso fazer é passar uma única variável token Customer com um valor customer-token-1 :


 { "token": "customer-token-1" }


Podemos recuperar todos os dados usando uma única chamada de API GraphQL:


 { "data": { "customer": { "name": "Acme Inc.", "sic_code": "1234", "token": "customer-token-1" }, "address": { "token": "address-token-1", "customer_token": "customer-token-1", "address_line1": "123 Main St.", "address_line2": "", "city": "Anytown", "state": "CA", "postal_code": "12345" }, "contact": { "token": "contact-token-1", "customer_token": "customer-token-1", "first_name": "John", "last_name": "Doe", "email": "[email protected]", "phone": "123-456-7890" }, "credit": { "token": "credit-token-1", "customer_token": "customer-token-1", "credit_limit": 10000, "balance": 2500, "credit_score": 750 } } }


Abaixo está uma captura de tela do Apollo Explorer em execução no meu aplicativo Heroku:


Conclusão

Lembro-me no início da minha carreira, quando Java e C# competiam entre si pela adoção do desenvolvedor. Os defensores de cada lado do debate estavam prontos para provar que a tecnologia escolhida era a melhor escolha... mesmo quando não era.


Neste exemplo, poderíamos ter atendido meu caso de uso do Customer 360 de várias maneiras. Usar uma API RESTful comprovada teria funcionado, mas seriam necessárias várias chamadas de API para recuperar todos os dados necessários. Usar o Apollo Server e o GraphQL me permitiu atingir meus objetivos com uma única chamada de API.


Também adoro como é fácil implantar meu servidor GraphQL no Heroku com apenas alguns comandos em meu terminal. Isso permite que eu me concentre na implementação – aliviando a carga da infraestrutura e executando meu código em um provedor terceirizado confiável. Mais importante ainda, isso está de acordo com minha declaração de missão pessoal:


“Concentre seu tempo em fornecer recursos/funcionalidades que ampliem o valor de sua propriedade intelectual. Aproveite estruturas, produtos e serviços para todo o resto.”

– J. Vester


Se você estiver interessado no código-fonte deste artigo, ele está disponível no GitLab .


Mas espere... tem mais!


Na minha postagem de acompanhamento, desenvolveremos ainda mais nosso servidor GraphQL, para implementar autenticação e recuperação de dados em tempo real com assinaturas.


Tenha um ótimo dia!