Fundamentos para sistemas com arquiteturas REST

Não projete APIs para serem RESTful, projete-as para terem as propriedades que você necessita!
Roy Fielding
APIs têm importância crescente no design de aplicações. Boas APIs facilitam o estabelecimento de parcerias, permitindo que sistemas se comuniquem de maneira sólida, facilitando a automação dos negócios.
O projeto de APIs, em consequência dessa importância, é atividade fundamental de arquitetura. A criação de APIs intuitivas e fáceis é essencial. É essencial que o arquiteto responsável garanta a seleção do estilo mais adaptado as necessidades.
Desde o início dos anos 2000, vem ganhando destaque APIs projetadas conforme o estilo arquitetural REST, embora, infelizmente, as implementações não sejam, muitas vezes, “fiéis” aos princípios estabelecidos nesse estilo.

Buscando referências práticas

Este capítulo não visa ser um guia de referência de soluções REST, mas sim, fundamento para pensamento arquitetural.

Há uma pequena lista de “receitas de bolo” para problemas REST no Apêndice A.

Filosofia REST

O pleno entendimento de REST começa pela interpretação do que o acrônimo significa. REpresentational State Transfer literalmente expressa a intencionalidade do estilo arquitetural: transferência de estado através de representações.

As transferências de estado, em sentido amplo, não se restringem apenas pelo conjunto de dados associados a um recurso, mas também às operações que este recurso suporta. Os diversos componentes computacionais que formam uma solução REST “transferem estado” entre si, afim de preservar consistência.

A transferência de estado entre componentes, coloca os recursos como as “estrelas da festa”, ou seja, o centro de qualquer interação. Afinal, em sentido amplo, transferências de estado acontecem pela criação, modificação, recuperação e remoção de recursos, orquestradas por um componente em outro remoto.

O conjunto limitado e padronizado de operações que transferem estado conferem a arquiteturas RESTful simplicidade. Ou mesmo conjunto uniforme de operações pode ser aplicado a qualquer recursos, de maneira consistente, através de um conjunto também bem delimitado de verbos HTTP.

A transferência mais óbvia de estado acontece quando um componente solicita a outro a representação correspondente a uma versão, geralmente o “momento atual”, de um recurso, utilizando para isso o verbo HTTP GET.

Menos evidentes são as transferências de estado que acontecem quando um componente envia estado – representações de um recurso – para outro, geralmente com verbos HTTP POST e HTTP PUT.

Finalmente, também são transferências de estado atualizações parciais de recursos, geralmente aplicadas com verbos HTTP POST e HTTP PATCH, bem como operações de exclusão de recursos realizadas com HTTP DELETE.

Embora seja comum associar REST ao desenvolvimento de APIs, suas motivações são muito mais ambiciosas. REST nasceu como uma abordagem para orientar a evolução da arquitetura da Web!

Desde 1994, o estilo arquitetônico REST tem sido usado para guiar o design e o desenvolvimento da arquitetura para a Web moderna.

Roy Fielding

Em sua tese, Roy Fielding descreve, também, um combinado de lições aprendidas com a aplicação de REST durante a criação dos padrões da Internet para o protocolo de transferência de hipertexto (HTTP) e identificadores de recursos uniformes (URI), as duas especificações que definem a interface genérica usada por todas as interações de componentes na Web, como bem como da implantação dessas tecnologias na forma da biblioteca cliente libwww-perl, o Projeto de servidor HTTP Apache e outras implementações de padrões de protocolo.

A motivação para desenvolver REST foi criar um modelo de arquitetura de como a Web deveria funcionar, de forma que pudesse servir como a estrutura de orientação para os padrões de protocolo da Web. [..] Este trabalho foi feito como parte dos esforços do Internet Engineering Taskforce (IETF) e do World Wide Web Consortium (W3C) para definir os padrões de arquitetura para a Web: HTTP, URI e HTML.

Roy Fielding

Conceito fundamental

Com frequência, APIs que utilizam verbos padrões HTTP – GET, PUT, POST e DELETE – e entregam conteúdo em XML ou JSON são designadas como RESTful. Entretanto, estas características não são suficientes para tal designação.

REST, acrônimo para Representational State Transfer, é um estilo arquitetural para sistemas hipermídia distribuídos. Ele foi introduzido e definido, no ano 2000, por Roy Fielding, em sua tese de doutorado. Trata-se de um conjunto de restrições arquiteturais aplicados a World Wide Web.

Apenas sistemas desenvolvidos observando corretamente o estilo REST podem ser identificados como RESTful

Null Style

Em sua tese, Roy Fielding, defende a existência de duas abordagens para a elaboração de um design arquitetural.

A primeira abordagem é aquela onde um projeto de sistema começa “do zero” – como que em uma “tela em branco” – e vai sendo elaborado utilizando elementos familiares até que, em dado momento, satisfaça as necessidades pretendidas.

A segunda abordagem parte de um sistema “pronto”, com todos os elementos demandados para atender uma determinada necessidade já presentes, porém sem restrições. Então, restrições são aplicadas para “aparar” os elementos do sistema até que ele satisfaça apenas a um conjunto de especificações bem determinado. Este “ponto de partida”, sem restrições, é designado por Roy Fielding como Null Style.

REST, como estilo arquitetural, tem como Null Style World Wide Web.

Sistemas RESTful destacam-se por terem atributos de qualidade como portabilidade, escalabilidade, visibilidade (facilidade para monitoramento), confiabilidade e desempenho percebido (responsividade). Além disso, tem ótimo evolvability.

World Wide Web

A World Wide Web (WWW) é um sistema de informação onde documentos e outros recursos são identificados por Uniform Resource Locators (URLs, como https://example.com/), interligáveis por hiperlinks, acessíveis ​​pela Internet.

Os recursos da Web são transferidos por meio de implementações de protocolos, como HTTP, e podem ser acessados ​​pelos usuários por aplicativos navegadores  e publicados por um aplicativos servidores.

O cientista inglês Sir Timothy Berners-Lee inventou a World Wide Web em 1989. Ele escreveu o primeiro navegador da web em 1990 enquanto trabalhava no CERN (European Organization for Nuclear Research) perto de Genebra, Suíça. O navegador foi lançado fora do CERN para outras instituições de pesquisa a partir de janeiro de 1991, e depois para o público em geral em agosto de 1991. A Web começou a entrar no uso diário em 1993, quando sites de uso geral começaram a se tornar disponíveis.

Definição: Recurso

Um recurso é qualquer artefato na rede que tenha uma identidade. Exemplos comuns são documentos eletrônicos, imagens, serviços ou, eventualmente, coleção de outros recursos.

URI e URL

URI, acrônimo para Uniform Resource Identificator, é uma identificação simples para um recurso. Enquanto isso, URL, acrônimo para Uniform Resource Locator, especifica também como este recurso (indicando protocolo) deve ser acessado.

Todas URLs são URIs, mas nem toda URI é uma URL.

Tipos de elementos encontrados em arquiteturas REST

O estilo arquitetural REST define abstrações para os elementos arquitetônicos em um sistema hipermídia distribuído, enquanto ignora os detalhes de implementação.

Sistemas RESTful geralmente serão compostos por componentes, conectores que ligam esses componentes e os dados que eles utilizam.

Elementos arquiteturais relacionados com “Dados”

Sistemas RESTful se caracterizam pela movimentação dos dados através de componentes de processamento, em oposição a outros estilos onde os diversos componentes operam sobre uma única “fonte da verdade”. Essa característica, reforça a coesão, eventualmente comprometendo a eficiência.

Ao projetar dados, um componente “servidor” pode-se adotar uma das seguintes três estratégias:

  1. renderizar os dados para uma representação específica;
  2. enviar os dados em sua representação nativa, acompanhados de código que realiza a renderização para uma representação específica;
  3. enviar os dados em sua representação nativa, acompanhados de metadados para que o componente “cliente” adote uma estratégia de processamento;

São elementos arquiteturais relacionados com dados:

  • o próprio recurso;
  • sua identificação, geralmente uma URI ou URN;
  • alternativas para representação, como HTML, JSON e XML;
  • metadados da representação, como cabeçalhos como media-type last-modified
  • metadados do recurso, com cabeçalhos como alternates vary
  • metadados de controle, com cabeçalhos como if-modified-since cache-control

Elementos arquiteturais “Conectores”

Os conectores são as tecnologias responsáveis por acessar e transportar os dados entre dois ou mais componentes. Basicamente, eles podem ser agrupados em tecnologias clientes, servidoras, para caching, transporte (tunnel) e resolver (ex: servidores DNS).

Os principais tipos de conectores são “cliente” e “servidor”. A diferença essencial entre os dois é que um cliente inicia a comunicação fazendo uma requisiçã0, enquanto um servidor escuta as conexões e responde às requisições para fornecer acesso aos seus serviços. Eventualmente, um mesmo componente pode incluir conectores de cliente e de servidor.

Um terceiro tipo de conector, o conector de “caching”, pode ficar localizado próximo do “cliente” ou ou do “servidor” a fim de salvar respostas armazenáveis em cache para interações atuais para que possam ser reutilizadas para interações posteriores. Um cache pode ser usado por um cliente para evitar a repetição da comunicação da rede, ou por um servidor para evitar a repetição do processo de geração de uma resposta, com ambos os casos servindo para reduzir a latência de interação.

Elementos arquiteturais “Componentes”

Os componentes são elementos de processamento que se conectam a outros por meio de conectores. Os componentes mais comuns são o “cliente” e o “servidor”. Em um modelo em camadas, um mesmo componente pode ser, ao mesmo tempo, “cliente” e “servidor” realizando algum tipo de transformação ou segurança.

As restrições determinadas por REST

Sistemas RESTful são “cliente-servidor”

A primeira restrição definida for Fielding é que sistemas que seguem o estilo arquitetural REST sejam implementações cliente-servidor. Cabe ao componente “cliente” disponibilizar interfaces com o usuário. Enquanto isso, componentes “servidor” fornecem dados. Em sistemas RESTful, eventualmente, um mesmo componente de software poderá operar como cliente e servidor.

Um software navegador utilizado para navegar na internet atua como cliente. Afinal, envia requisições HTTP, para um servidor, de forma a acessar e manipular dados.

A separação de responsabilidades, segundo Fielding, reforça atributos de qualidade como portabilidade – permitindo que implementações “cliente” independentes sejam realizadas em diversas plataformas – e a escalabilidade – simplificando os componentes “servidor”. Além disso, por habilitar que “cliente” e “servidor” evoluam de forma independente, colaboram para o evolvability.

Componentes “servidor” são stateless

A segunda restrição definida por Fielding é que sistemas RESTful sejam stateless. Ou seja, cada requisição de componentes “cliente”  deve conter todas as informações contextuais necessárias para serem atendidas, sem depender de qualquer dado de contexto armazenado no componente “servidor”. Assim, informações de sessão devem ser mantidas, inteiramente, apenas no componente “cliente”.

Por serem stateless, sistemas RESTful têm melhor visibilidade, confiabilidade e escalabilidade. Afinal:

  • cada solicitação pode ser verificada, completamente, de maneira isolada, já que contem todos os dados necessários para a análise;
  • por não manterem estado de contexto, é mais fácil recuperar o “lado servidor” de falhas parciais;
  • por não haver necessidade de manter estado de contexto, sistemas RESTful são mais fáceis de implementar e de escalar.

Como pontos potencialmente negativos, a restrição de que componentes “servidor” sejam stateless implica em tráfego de dados maior na rede, pelo transporte da informação de estado contexto. Além disso, há potencial excesso de autonomia dos componentes “cliente” (que operam sem supervisão do servidor).

Recursos devem ser indicados como sendo “cacheáveis” ou “não-cacheáveis”

A terceira restrição definida por Fielding é que sistemas RESTful devem indicar a possibilidade de adoção de caching nos componentes “cliente”. Para isso, todas as respostas do componente “servidor” devem ser identificadas, implícita ou explicitamente, como armazenáveis ou não armazenáveis em cache.

A adoção de caching melhora a eficiência, colaborando para a escalabilidade e desempenho. Entretanto, dados armazenados em cache podem ficar desatualizados, antes de serem invalidados, comprometendo a confiabilidade.

Comunicações entre “cliente” e “servidor” devem ocorrer através de interface uniforme

A quarta restrição definida por Fielding é que as comunicações entre componentes “cliente” e “servidor”, em sistemas RESTful, ocorram através de interfaces uniformes (consistentes). Dessa forma, a implementação dos componentes “cliente” e “servidor” podem ocorrer de forma desacoplada (e independente).


Há quatro restrições arquiteturais adicionais derivadas da decisão de adotar interfaces uniformes:

  1. Recursos devem ser identificados consistentemente. Na prática, recursos em um sistema RESTful devem estar associados a identificações estáveis, ou seja, que não mudam durante as interações, tampouco quando o estado interno do recurso (conjunto de dados que o compõe) é alterado.
  2. Recursos devem ser manipulados a partir de representações. A representação de um recurso é composta por uma sequência de bytes e metadados que a descrevem. Opcionalmente, uma representação também contém metadados que descrevem o recurso em si. Em implementações REST usando HTTP, por exemplo, entidades de domínio são recursos que podem ser expostos em representações usando XML, JSON e mais; enquanto isso, metadados descrevendo uma representação são fornecidos no cabeçalho;
  3. Mensagens devem ser auto-descritivas. Ou seja, devem conter todas as informações para que o receptor – cliente ou servidor – tenha condições realizar interpretação correta, sem necessitar de mensagens adicionais ou documentação em separado.
  4. Hipermídia deve ser utilizada como mecanismo de estado (HATEOAS). Utilizando hiperlinks e, possivelmente, modelos consistentes de URI, como parte dos metadados que descrevem o recurso, seja para descrever documentos ligados como ativações de estado.

Implementações do “servidor” podem ser compostas em camadas

A quinta restrição definida por Fielding é que componentes “servidor” podem ser desenvolvidos a partir de composições que obedecem o estilo de arquitetura em camadas. Ou seja, componentes “cliente” tem acesso apenas a camada mais externa, e esta pode utilizar recursos de camadas inferiores, em diversas representações, para compor novos recursos.

 

Camadas podem ser utilizadas para encapsular sistemas legados, protegendo tanto novos “clientes” de “servidores” legados, como para proteger novos “servidores”  de “clientes” legados.

Camadas diferentes podem operar, inclusive, em níveis de abstração distintos, prevenindo changing coupling. Por exemplo:

  • em nível mais baixo, expondo “entidades” como recursos nativos de sistemas pesados,
  • em nível intermediário, expondo recursos relacionados a processos de negócio que são composições das “entidades”
  • em nível mais alto, expondo recursos relacionados a “experiência” que são composições dos “processos”.

Finalmente, tecnicamente, camadas também podem ser utilizadas para melhorar a escalabilidade habilitando funcionalidades como balanceamento de carga e represamento, protegendo sistemas legados não preparados para escalabilidade.

Componentes “servidor” podem fornecer code-on-demand para “clientes”

A sexta, e última, restrição indicada por Fielding é que componentes “servidor” podem fornecer code-on-demand para componentes “cliente”. Ou seja, em sistemas RESTful componentes “servidor” podem extender funcionalidades de componentes “cliente” através do download de código executável na forma de applets ou scripts. Teoricamente, isso deve simplificar a implementação de features comuns com implementações pré-implementadas.

HATEOAS

‘Hypermedia as the engine of application state’ is a REST constraint. Not an option. Not an ideal. Hypermedia is a constraint. As in, you either do it or you aren’t doing REST.

Roy Fielding

Hypermedia as the Engine of Application State, ou HATEOAS, é uma “maneira” de implementar APIs REST utilizando hipermídia para indicar que ações ou navegações estão disponíveis para um determinado recurso. Estas  ações e a navegação são derivadas do estado do recurso e, eventualmente, da própria API. Elas são disponibilizadas para o cliente através de uma coleção de links.

{
  "custormerId": 1, 
  "firstName": "John", 
  "lastName": "Doe", 
  ...
  
  "links": []
}

Não há uma definição universalmente aceita sobre onde esta coleção de links deve ser fornecida. Há quem defenda a inclusão na representação do recurso. Outros, defendem a utilização dos cabeçalhos da “response HTTP”. Quanto aos dados necessários em cada link, há a RFC (5598).

O link para Self

O primeiro link da coleção costuma ser uma referência para o próprio objeto.

{
  "custormerId": 1, 
  "firstName": "John", 
  "lastName": "Doe", 
  ...
  
  "links": [{
    "rel": "self",
    "method": "GET",
    "href": "/customers/1" 
  }]
}

Dessa forma, caso a representação do recurso “se perca” na aplicação cliente, ou, caso ela, eventualmente, seja persistida ou compartilhada com outros contextos, em qualquer momento, seria possível determinar sua origem sem “inferências no código”.

Links para as ações suportadas pelo recurso

A cup wants to be held and lifted, or a button wants to be pushed.

Don Norman

Para entender, efetivamente HATEOAS, devemos aplicar o mesmo raciocínio que Don Norman recomenda em The Design of Everyday Things para recursos. Ou seja, devemos perguntar, sempre, que operações um “recurso” espera.

{
  "id": "123", 
  "balance": {
    "currency": "usd",
    "amount": 150
  },
  
  "links": [{
    "rel": "self",
    "method": "GET",
    "href": "/accounts/123"
  }, {
    "rel": "withdrawals",
    "method": "GET",
    "href": "/accounts/123/withdrawals"
  }, {
    "rel": "withdrawals",
    "method": "POST",
    "href": "/accounts/123/withdrawals",
    "sample": {
        "currency": "usd",
        "amount": 0
      }
  }, {
    "rel": "deposits",
    "method": "GET",
    "href": "/accounts/123/deposits",
  }, {
    "rel": "deposits",
    "method": "POST",
    "href": "/accounts/123/deposits",
    "sample": {
        "currency": "usd",
        "amount": 0
      }
  }]
}

No exemplo acima, por exemplo, temos um exemplo (obviamente simplificado) de um recurso representando uma conta bancária, cujo links relacionam as operações que este recurso suporta.

Abaixo, verificamos uma versão atualizada do recurso, com operações restritas em função do saldo negativo.

{
  "id": "123", 
  "balance": {
    "currency": "usd",
    "amount": 0
  },
  
  "links": [{
    "rel": "self",
    "method": "GET",
    "href": "/accounts/123"
  }, {
    "rel": "withdrawals",
    "method": "GET",
    "href": "/accounts/123/withdrawals"
  }, {
    "rel": "deposits",
    "method": "GET",
    "href": "/accounts/123/deposits",
  }, {
    "rel": "deposits",
    "method": "POST",
    "href": "/accounts/123/deposits",
    "sample": {
        "currency": "usd",
        "amount": 0
      }
  }]
}

A presença da coleção de links direciona a composição da experiência do usuário direcionando que opções mostrar e quais não mostrar. Fornecer a lista de ações possíveis para um recurso na coleção de links permite que essa lógica seja implementada totalmente no serviço e simplifica muito a implementação da aplicação cliente.

Links para navegação

Eventualmente, um recurso retornado pela API possuirá outros recursos relacionados. Por exemplo, em uma aplicação empresarial, um “cliente” possuirá uma coleção de “pedidos” que realizou.

{
  "custormerId": 1, 
  
  "links": [
  ...
  {
    "rel": "orders",
    "method": "GET"
    “href”: “http://mydomain/customers/1/orders”
  }]
}

Toda URI é RESTful

Não há dúvidas sobre a utilidade de um bom projeto de URIs. Entretanto, é importante destacar que não há qualquer especificação sobre como URIs devem ser construídas para ser mais ou menos aderentes a REST. Toda URI é RESTful!

Sistemas RESTful são compostos por conjuntos de recursos, conectados via hipermídia, obedecendo a formatos e padrões. URIs consistentes funcionam como identidades universais perenes para recursos que devem funcionar, todos, como “ponto de entrada” para o sistema.

URIs são “identificadores”… e só isso!

O projeto de URIs deixa de ser RESTful quando, por qualquer razão, eleva URIs a assumir responsabilidades além de identificar recursos.

Sejamos claros! URIs como http://my-domain/hdservices/format?drive=c ou, ainda, http://my-domain/customers/delete?id=123, ou http://my-domain/customers/123/delete são, por definição, RESTful porque, em teoria, é uma sequência válida de caracteres. Agora, o problema é atribuir, além da “responsabilidade” de identificar um recurso, semântica de ação – é esse o erro conceitual.

O projeto de URIs não substitui HATEOAS

Não é incomum, no projeto de APIs, estabelecer relações de hierarquia implicitamente e isso é risco para implementações RESTful. Por exemplo, é natural que assumir que:

  • http://my-service/customers retorne uma (representação do recurso) relação de clientes;
  • http://my-service/customers/123 retorne uma (representação do recurso) cliente 123;
  • http://my-service/customers/123/orders retorne uma (representação do recurso) relação dos pedidos do cliente 123;

Tamanha naturalidade incentiva o componentes “cliente” a navegar pelos diversos recursos fazendo “concatenações de string”, criando um acoplamento indesejado. Daí, a ênfase a HATEOAS.

REST preconiza que a navegação entre recursos relacionados aconteça através de links como metadados do recurso. Isso confere a cada recurso a possibilidade de operar como um ponto de entrada no sistema.

REST não é CRUD

Há uma confusão frequente entre os conceitos de transferências de estado, através de representações, e operações CRUD. Não é incomum ver, por exemplo, a associações de CREATE com o verbo HTTP POST, RETRIEVE com o verbo HTTP GET, UPDATE com HTTP PUT e, finalmente, DELETE com HTTP DELETE. Esta é uma visão ingênua e superficial.

Algumas pessoas pensam que REST sugere não usar POST para atualizações. Pesquise minha dissertação e você não encontrará nenhuma menção a CRUD ou POST. A única menção de PUT é em relação à falta de cache de write-back do HTTP.

Roy Fielding

Não há restrições quanto a utilizar HTTP POST para atualizações

Uma das “verdades absolutas” sobre REST, que não é verdade, é a ideia de que o verbo HTTP POST não pode ser utilizado para atualizar recursos. Aliás, o próprio Roy Fielding é bastante opinativo a este respeito.

A única coisa que o REST exige dos métodos é que eles sejam definidos uniformemente para todos os recursos (ou seja, para que os intermediários não precisem saber o tipo de recurso para entender o significado da solicitação). Enquanto o método está sendo usado de acordo com sua própria definição, REST não tem muito a dizer sobre isso.

Por exemplo, não é RESTful usar GET para executar operações inseguras porque isso violaria a definição do método GET em HTTP, o que, por sua vez, enganaria intermediários e spiders. Não é RESTful usar POST para recuperação de informações quando essas informações correspondem a um recurso potencial, porque esse uso impede a reutilização segura e o efeito de rede de ter um URI. Mas por que você não deve usar o POST para realizar uma atualização? O hipertexto pode informar ao cliente qual método usar quando a ação executada não for segura. PUT é necessário quando não há hipertexto dizendo ao cliente o que fazer, mas a falta de hipertexto não é particularmente RESTful.

Roy Fielding

Versionamento, que versionamento?

Uma discussão recorrente (e importante) relacionada ao design de APIs tem relação com políticas de versionamento. Com frequência, assume-se a necessidade de versionar APIs e, não raro, a solução é indicar versão das URLs dos recursos (o que entra em conflito com a estabilidade dos identificadores).

Dados de um recurso são naturalmente modificados ao longo do tempo e, seguramente, demandam uma estratégia de versionamento, seja ETags ou Last-Modified, que ocorre quase de forma natural.

A documentação das APIs também é versionável, embora, quanto mais “HATEOAS“, mais evolucionária e menos revolucionária (evolvability) é a mecânica de interação devido a natureza auto-descritiva das mensagens.

Finalmente, a evolução das representações também é mais fácil frente a possibilidade de usar negociação e especialização.

O versionamento combinado de dados, documentação e representações mitiga a necessidade de versionamento explícito de APIs.

O “jeito certo” de retornar erros (RFC 7807)

A beleza da opção por Null Style de Roy Fielding é que REST continua evoluindo junto com a WWW. Ou seja, como REST é WWW com restrições, sempre que WWW evolui, então, REST também evolui.

Um das dificuldades frequentes no projeto de APIs era a estruturação de responses indicando falhas de processamento. Não havia, um padrão formal para apresentar detalhes sobre problemas ocorridos. Felizmente, isso muda com a RFC 7807, que embora ainda seja uma proposição, já é madura.

Abaixo, um exemplo de retorno conforme a RFC:

HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
Content-Language: en

{
  "type": "https://example.com/probs/out-of-credit",
  "title": "You do not have enough credit.",
  "detail": "Your current balance is 30, but that costs 50.",
  "instance": "/account/12345/msgs/abc",
  "balance": 30,
  "accounts": ["/account/12345",
               "/account/67890"]
 }

Outro exemplo, indicando problemas com parâmetros:

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
Content-Language: en

{
  "type": "https://example.net/validation-error",
  "title": "Your request parameters didn't validate.",
  "invalid-params": [ {
                         "name": "age",
                         "reason": "must be a positive integer"
                       },
                       {
                         "name": "color",
                         "reason": "must be 'green', 'red' or 'blue'"}
                     ]
}

Algumas “leis de engenharia” aplicadas a REST

Hyrum

A lei de Hyrum, que governa as integrações, também é válida para o design de APIs REST.

Com um número suficiente de usuários, não importa o que estiver acertado em contrato: todos os comportamentos observáveis de um sistema serão premissas para funcionamento de outros artefatos.

Hyrum

A perversidade dessa lei é o fundamento para o cuidado do projeto cuidadoso. Se não houver ênfase em HATEOAS, há tendência de sobrecarga na padronização de URLs e na utilização de convenções de verbos, transformando sistemas, perigosamente, em aglomerados de CRUD.

Postel

A  lei de Postel — ou Lei da Robustez — preconiza que sistemas sejam 1) conservadores no que enviam e ; 2) liberais no que recebem. Daí é importante observar algumas recomendações:

  1. Desenvolvedores “cliente” devem operar sem dependências para estruturas de URI. Enquanto isso, desenvolvedores “servidor” não devem quebrar estruturas de URI  desnecessariamente.
  2. Desenvolvedores “cliente” devem suportar novos links em hipermídia. Desenvolvedores “servidor” devem evoluir via novos links hipermídia.
  3. Desenvolvedores “cliente” devem ignorar “conteúdo desconhecido”. Desenvolvedores “servidor” devem suportar formatos antigos.

Conway

O desenvolvimento de sistemas RESTful preconiza clara separação das equipes em desenvolvedores de componentes “cliente” e componentes “servidor”.

Quando o modelo “em camadas” de componentes “servidor” é adotado, é comum, que cada camada seja mantida por um time dedicado. Aliás, em casos extremos, cada componente “servidor”, em cada camada, poderá ser mantido por um time especialista.

Eventualmente, um time de operações poderá ser estabelecido para projeto, implementação e manutenção de conectores. O mesmo também pode ocorrer para manutenção das fontes de dados.

O modelo de maturidade de Leonard Richardson (RMM)

Leonard Richardson, famoso autor de livros sobre REST, propôs um modelo de quatro categorias de compatibilidade (melhor do que maturidade)  com REST. Trata-se Richardson Maturity Model (RMM)

O primeiro nível proposto por Richardson (level zero) é dedicado aos serviços que não fazem uso apropriado de identificadores, tampouco dos verbos HTTP ou HATEOAS. São exemplos de APIs nesse nível aquelas desenvolvidas usando XML-RPC.

Serviços no segundo nível (level one), segundo o RMM, utilizam URIs de maneira consistente, porém apenas com um único verbo HTTP (geralmente POST).

No terceiro nível (level two), estão os serviços que já fazem usof adequado de URIs e também semanticamente ajustado dos verbos HTTP. Trata-se da maioria das implementações REST-like. Finalmente, serviços no quarto nível (level three) tem recursos implementando HATEOAS.

Conforme Roy Fielding, apenas serviços no quarto nível no RMM são RESTful.

Indicações e contraindicações

APIs REST parecem ser uma unanimidade. Infelizmente, essa “unanimidade” é questionável frente ao fato de que muitas implementações não respeitam alguns de seus princípios.

APIs REST são, seguramente, mais acessíveis e fáceis de usar do que APIs SOAP. Entretanto, é importante destacar que são, fundamentalmente, data-driven. Eventualmente, alguns domínios são melhor expressados  frente a modelos RPC.

// TODO

Antes de avançar para o próximo capítulo, recomendo as seguintes reflexões:

  1. As implementações auto-proclamadas RESTful que você conhece realmente o são?
  2. Em que cenários você não utilizaria REST como estilo arquitetural para desenho de APIs?
  3. Você está habituado a utilizar HATEOAS?

Referências bibliográficas

FIELDING, Roy. Architectural Styles and the Design of Network-based Software Architectures. 2000. 162 f. Tese (Doutorado) – Curso de Information And Computer Science, University Of California, Irvine, Ca, 2000. Disponível em: https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm. Acesso em: 5 jun. 2021.

FIELDING, Roy. It is OK to use POST. 2009. Disponível em: https://roy.gbiv.com/untangled/2009/it-is-okay-to-use-post. Acesso em: 5 jun. 2021.

FOWLER, Martin. Richardson Maturity Model: steps toward the glory of rest. steps toward the glory of REST. 2010. Disponível em: https://martinfowler.com/articles/richardsonMaturityModel.html. Acesso em: 7 jun. 2021.

Compartilhe este capítulo:

Compartilhe:

Comentários

Participe da construção deste capítulo deixando seu comentário:

Inscrever-se
Notify of
guest
0 Comentários
Feedbacks interativos
Ver todos os comentários

Fundador e CEO da EximiaCo, atua como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Mentorias

para arquitetos de software

Imersão, em grupo, supervisionada por Elemar Júnior, onde serão discutidos tópicos avançados de arquitetura de software, extraídos de cenários reais.

Consultoria e Assessoria em

Arquitetura de Software

EximiaCo oferece a alocação de um Arquiteto de Software em sua empresa para orientar seu time no uso das melhores práticas de arquitetura para projetar a evolução consistente de suas aplicações.

ElemarJúnior

Fundador e CEO da EximiaCo, atua como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Podcast

Arquitetura de Software Online

55 51 9 9942 0609  |  me@elemarjr.com

+55 51 99942-0609 |  contato@eximia.co

+55 51 99942-0609  contato@eximia.co

0
Quero saber a sua opinião, deixe seu comentáriox
()
x