Como descrever uma mudança na arquitetura que quebra intencionalmente os padrões REST?

37

Estou propondo alterações em um projeto de software muito mal arquitetado que sofre de uma infinidade de problemas. Em um nível alto, o projeto utiliza Angular no front-end e consome várias APIs REST; o que é ótimo (não vejo a necessidade de mudar nossa tecnologia ou ferramentas). O problema é que a base de código é desproporcionalmente maior na interface do que as APIs do servidor. Grande parte da lógica de negócios reside na interface do usuário, com as APIs REST sendo simples interfaces de banco de dados CRUD para a camada da interface do usuário.

Por exemplo, um POST para o cliente criará um registro do cliente, enquanto um PUT modificará esse cliente. Não muito mais e não muito menos. No entanto, nossa lógica de negócios é mais exigente que isso. O processo geral de criação de um cliente faz muito mais do que inserir 1 registro no banco de dados. Ele fornecerá dados em outras tabelas necessárias, executará certas validações e cálculos, etc. Eu preferiria fazer uma única chamada POST / PUT que encapsule todo esse comportamento, aliviando a carga do cliente consumidor.

Portanto, meu ponto de vista é que essa orquestração abrangente deve residir no servidor (onde temos controle total, logs etc.), não na interface do usuário, mas um contra-argumento é que essa abordagem não seria mais RESTful. Portanto, não sei como descrever melhor essa abordagem quando minha recomendação é continuar com a pilha de tecnologia existente, mas implementar mudanças fundamentais nos locais onde o código pertence.

Ben Harrison
fonte
44
Confinar sua API a CRUD exige o objetivo de torná-la "RESTful" é uma desvantagem ruim.
Robert Harvey
38
@EsbenSkovPedersen: Melhor amigo para sempre?
Robert Harvey
5
Em vez de me preocupar se o seu serviço está em conformidade com o REST (iirc, quase nenhum funciona), eu me preocuparia mais em estar em conformidade com a especificação HTTP . A maioria das APIs com as quais trabalhei também não está de acordo com as especificações, mas é uma meta mais viável e valiosa.
aaaaaa
7
@aaaaaa, a razão pela qual quase nenhum serviço está em conformidade com o REST é que ninguém pode decidir sobre o que é REST. O único ponto de concordância que encontrei é "todo mundo está fazendo errado".
Mark
16
- "Como descrever uma mudança na arquitetura que quebra intencionalmente os padrões REST?" - desrespeitar . ( Desculpe por um comentário não profissional, era mais forte do que eu. ) #
Luk32

Respostas:

49

Não sei como descrever melhor essa abordagem quando minha recomendação é continuar com a pilha de tecnologia existente, mas implementar mudanças fundamentais nos locais onde o código pertence.

Service oriented architecture.

Você está propondo reprojetar seu sistema para que suas regras de negócios e seus dados estejam no mesmo local. Essa é efetivamente a definição de um serviço ; veja a palestra de Udi Dahan sobre Como encontrar limites de serviço .

Barra lateral: como observado por Eric, isso não tem nada a ver com "REST". Não há absolutamente nenhuma razão para que você não possa colocar uma API REST (ou seja, uma API que atenda às restrições do estilo de arquitetura REST ) na frente do seu serviço. Mas isso pode não ser óbvio para as pessoas que entendem REST como um mapeamento de operações do banco de dados para métodos HTTP.

Pode ou não valer a pena investir na alteração do entendimento do REST do seu público.

VoiceOfUnreason
fonte
32
Nem vale a pena investir em REST. Se você ler a dissertação de Roy Fielding (ou Como expliquei o REST para minha esposa ), o verdadeiro objetivo do REST é fornecer uma representação canônica de recursos na Internet, para que máquinas diferentes na Internet tenham uma maneira padrão de manipular esses recursos. . Um aplicativo de propriedade privada pode nem precisar desse recurso.
Robert Harvey
29

REST não é CRUD. Esse "contra-argumento" é baseado em um entendimento fundamentalmente defeituoso do que é REST. Não vi nada em sua postagem que indique que sua alteração tornaria sua API mais ou menos RESTful.

Eric Stein
fonte
6
Bem, não, não é um mapeamento perfeito para o CRUD, mas ele anda, fala e canta muito como o CRUD, pelo menos da maneira que a maioria das pessoas o interpreta.
Robert Harvey
11
@RobertHarvey Eu acho que é esse (des) entendimento que é o problema aqui.
JimmyJames
4
@ JimmyJames: É um mal-entendido generalizado. Há um forte impulso para tornar as coisas "tranqüilas" quando a maioria das pessoas nem entende quais são os benefícios ou como esses benefícios se aplicariam a eles.
Robert Harvey
4
@RobertHarvey Acho que você está dizendo que, se fazer do jeito errado é REST, então REST não deve ser uma meta. OK, mas do jeito que eu vejo, chamar isso de 'não REST' é besteira e eu sou um grande defensor de chamar besteira em besteiras. As palavras precisam de um significado comumente entendido para serem úteis.
precisa saber é o seguinte
5
@RobertHarvey Concedido, mas isso não acontecerá enquanto houver pessoas suficientes dispostas a corrigir esses usos indevidos do termo. Não estou pronta para jogar a toalha.
precisa saber é o seguinte
24

Mais uma coisa a ter em mente é o seguinte ... Não validar as regras de negócios no lado do servidor significa que você confia implicitamente em tudo que entra, por exemplo, uma solicitação POST, é válido.

Significando que, por exemplo, enquanto seu aplicativo angular pode verificar se o cliente tem uma faixa etária válida e garantir que usuários legítimos obtenham o feedback correto, qualquer pessoa que conheça o URL da sua API pode fazer uma solicitação POST contendo alguns valores não legítimos. não será mais validado.

Portanto, minha sugestão seria mover suas regras de negócios para a API, validar a entrada e retornar erros apropriados (ou talvez apenas códigos indicando o que deu errado) no corpo da resposta. Esses códigos podem ser usados ​​pelo aplicativo front-end para indicar o que deu errado.

mrsmn
fonte
5
Essa é de longe a resposta mais útil aqui: A API é a superfície de ataque, não a entrada para o cliente. Qualquer solicitação de API pode ser falsificada. Portanto, tudo o que pode ser feito com a API pura é o que um kiddie de script malicioso e sem talento pode fazer. O software cliente pode ser usado para fornecer uma melhor experiência ao usuário, mas é o servidor que precisa aplicar as regras.
22/06
10

Para adicionar às outras boas respostas aqui:

Sua interface, REST ou não, não deve ser restringida com base em algum tipo de suposição sobre os detalhes da implementação. Isso é completamente antitético à noção de serviços como uma camada de abstração.

Um dos principais benefícios do uso de serviços é que os detalhes da implementação podem ser alterados sem que os clientes tenham que fazer nada. Pelo que você descreveu, parece que não há uma camada de abstração real. Os detalhes da implementação foram expostos via HTTP. Nada no REST diz que é necessário, útil ou desejável. Na verdade, acho que eu poderia argumentar que certas partes da definição REST significam que essa é de fato uma implementação não RESTful.

O que você está sugerindo é como uma camada de serviço adequada deve ser projetada. Se alguém está lhe dizendo que você não pode fazer isso porque não é RESTful, isso é lamentável. Você pode ter certeza de que alguém que lhe diz que sabe pouco ou nada sobre o REST.

Com base na sua pergunta, você tem um recurso chamado customer. Tudo o que é necessário para criar um recurso válido do cliente pode e deve ser tratado em um POSTrecurso da base de clientes (ou alternativamente / opcionalmente em um PUT para um recurso específico do cliente, se ele não existir). O REST não diz nada sobre quantos registros de banco de dados que você precisa criar em uma determinada chamada. Como Colin Young comentou, não precisa haver um banco de dados, é totalmente irrelevante como os serviços são implementados da perspectiva REST.

JimmyJames
fonte
3
O REST não diz nada sobre registros de banco de dados, muito menos quantos. Eu poderia criar um serviço REST que controlasse uma válvula de água e expondo uma válvula de água, o suprimento de água e os recursos no nível do tanque. Você pode argumentar que os próprios objetos físicos são um "banco de dados", mas isso é um pouco complicado.
Colin Young
@ColinYoung Sim, obrigado por ajudar a esclarecer.
JimmyJames
3

Há algumas boas respostas aqui, mas não tenho certeza de que elas o ajudarão a convencer seus colegas de trabalho. Como muitos apontaram, o que você está sugerindo não é uma mudança do design do RESTful, e acho que é a chave para incorporá-los à sua proposta.

O REST não tem a ver com garantir que sua API permita apenas o armazenamento e a recuperação de dados. Em vez disso, preocupa-se em modelar ações como recursos. Sua API deve permitir que ações sejam executadas ( afinal, é uma interface de programação de aplicativos ). A questão é como modelar essas ações.

Em vez de encontrar um termo, exemplos são provavelmente a melhor maneira de explicar isso para seus colegas de trabalho . Dessa forma, você pode mostrar como eles estão fazendo isso agora, quais problemas isso causa, uma solução que resolve o problema e como ele ainda permanece RESTful.

Vamos dar uma olhada no seu objeto Customer.

Problema:

A interface do usuário POST um cliente, mas as tabelas subseqüentes ainda não foram atualizadas. E se uma das chamadas subseqüentes falhar devido a um erro no seu código de interface do usuário (ou um plug-in de navegador com comportamento inadequado, etc.)? Agora seus dados estão em um estado inconsistente. Pode até ser um estado que quebra outras partes da sua API ou interface do usuário, sem mencionar que é simplesmente inválido. Como você se recupera? Você precisaria testar todos os estados possíveis para ter certeza de que isso não quebraria algo, mas seria difícil saber o que é possível.

Solução:

Crie um terminal de API para criar clientes. Você sabe que não deseja ter um terminal "/ customer / create" ou mesmo "/ create-customer", porque create é um verbo e violaria o REST. Então, substantivo. "/ customer-creation" pode funcionar. Agora, quando você POSTAR o objeto CustomerCreation, ele enviará todos os campos necessários para que um cliente seja totalmente criado. O nó de extremidade garantirá que os dados estejam completos e válidos (retornando 400 ou algo se falhar na validação) e pode persistir em uma única transação de banco de dados, por exemplo.

Se você também precisar de um ponto de extremidade para objetos GET / cliente, tudo bem. Você pode ter os dois. O truque é criar pontos de extremidade que atendam às necessidades dos consumidores.

Vantagens:

  1. Você garante que não vai acabar com o mau estado
  2. Na verdade, é mais fácil para os desenvolvedores da interface do usuário se eles não precisam "saber" a ordem das solicitações, questões de validação etc.
  3. Não é tão falador quanto uma API, reduzindo a latência de solicitações de rede
  4. É mais fácil testar e conceber cenários (dados ausentes / malformados da interface do usuário não são distribuídos entre solicitações, algumas das quais podem falhar)
  5. Permite um melhor encapsulamento da lógica de negócios
  6. Geralmente facilita a segurança (porque a lógica de negócios e de orquestração na interface do usuário pode ser modificada pelos usuários)
  7. Provavelmente reduzirá a duplicação lógica (é mais provável que você tenha mais de 2 consumidores de uma API do que mais de 2 APIs que dão acesso aos mesmos dados)
  8. Ainda 100% RESTful

Desvantagens:

  1. É potencialmente mais trabalhoso para o desenvolvedor de back-end (mas pode não ser a longo prazo)

Pode ser difícil para as pessoas entenderem esse paradigma e o que é bom se não o experimentarem. Espero que você possa ajudá-los a ver usando um exemplo do seu próprio código.

Minha própria experiência é que, quando os desenvolvedores da minha equipe começaram a implementar essa estratégia, eles viram quase imediatamente os benefícios.

Um estudo mais aprofundado:

Este artigo da thinkworks realmente me ajudou a ter a idéia de modelar ações como objetos usando exemplos práticos: https://www.thoughtworks.com/insights/blog/rest-api-design-resource-modeling

Eu também sugeriria ler sobre CQRS e Event Sourcing, pois eles se preocupam exatamente com esse tipo de coisa (por exemplo, separando sua API da lógica de persistência real). Não sei como seus colegas de trabalho estariam dispostos a ler esse tipo de coisa, mas isso pode lhe dar mais clareza e ajudá-lo a explicar isso a eles.

Planky
fonte
" porque create é um verbo e violaria o REST " - Absolutamente correto. Em outras palavras, seria a abordagem 47.258.346ª para executar " RPC sobre REST ". O que é algo que eu chamaria de "antinatural", pelo menos, porque usa e representa mal as abordagens RESTful (elas têm seus casos de uso, mas a RPC não é uma delas) e também tende a ser ineficiente.
JensG