Estruturar microsserviços: Estrutura da APIDesigning microservices: API design

Um bom design de API é importante numa arquitetura de microsserviços, uma vez que todos os troca de dados entre serviços acontece por meio de mensagens ou chamadas de API.Good API design is important in a microservices architecture, because all data exchange between services happens either through messages or API calls. APIs tem de ser eficientes para evitar a criação e/s chatty.APIs must be efficient to avoid creating chatty I/O. Como os serviços são concebidos pelas equipas de trabalhar de forma independente, APIs deve ter semântica bem definida e esquemas de controlo de versões, para que as atualizações não viole a outros serviços.Because services are designed by teams working independently, APIs must have well-defined semantics and versioning schemes, so that updates don't break other services.

Design de API para microsserviços

É importante distinguir entre dois tipos de API:It's important to distinguish between two types of API:

  • Chamam APIs públicas que aplicações de cliente.Public APIs that client applications call.
  • APIs de back-end que são utilizadas para comunicação entre serviços.Backend APIs that are used for interservice communication.

Esses casos de utilização de dois têm requisitos de um pouco diferentes.These two use cases have somewhat different requirements. Uma API pública tem de ser compatível com aplicativos cliente, normalmente, os aplicativos de navegador ou aplicações móveis nativas.A public API must be compatible with client applications, typically browser applications or native mobile applications. Maioria das vezes, isso significa que a API pública irá utilizar o REST através de HTTP.Most of the time, that means the public API will use REST over HTTP. No entanto, para o back-end APIs, precisa tomar o desempenho da rede para a conta.For the backend APIs, however, you need to take network performance into account. Consoante a granularidade dos seus serviços, comunicação originar pode resultar em muita de tráfego de rede.Depending on the granularity of your services, interservice communication can result in a lot of network traffic. Os serviços podem rapidamente tornar-se e/s.Services can quickly become I/O bound. Por esse motivo, as considerações, como o tamanho de velocidade e payload de serialização ainda mais importantes.For that reason, considerations such as serialization speed and payload size become more important. Algumas alternativas populares para usar o REST através de HTTP incluem gRPC e Apache Thrift Apache Avro.Some popular alternatives to using REST over HTTP include gRPC, Apache Avro, and Apache Thrift. Esses protocolos suportam a serialização binária e são geralmente mais eficientes do que o HTTP.These protocols support binary serialization and are generally more efficient than HTTP.

ConsideraçõesConsiderations

Aqui estão algumas coisas a considerar ao escolher como implementar uma API.Here are some things to think about when choosing how to implement an API.

REST vs RPC.REST vs RPC. Considere as compensações entre a utilização de uma interface de estilo REST em relação a uma interface de estilo RPC.Consider the tradeoffs between using a REST-style interface versus an RPC-style interface.

  • Recursos de modelos REST, que podem ser uma forma natural expressam o seu modelo de domínio.REST models resources, which can be a natural way express your domain model. Define uma interface uniforme com base em verbos HTTP, que encoraja evolvability.It defines a uniform interface based on HTTP verbs, which encourages evolvability. Ele tem semântica bem definida em termos de idempotência, efeitos colaterais e códigos de resposta.It has well-defined semantics in terms of idempotency, side effects, and response codes. E impõe comunicação sem monitoração de estado, o que melhora a escalabilidade.And it enforces stateless communication, which improves scalability.

  • RPC é mais orientado a em torno de operações ou comandos.RPC is more oriented around operations or commands. Uma vez que RPC interfaces como chamadas de método local, pode levar a conceção de APIs excessivamente comunicativas.Because RPC interfaces look like local method calls, it may lead you to design overly chatty APIs. No entanto, isso não significa a RPC deve estar chatty.However, that doesn't mean RPC must be chatty. Apenas significa que precisa usar cuidado ao projetar a interface.It just means you need to use care when designing the interface.

Para uma interface RESTful, a escolha mais comum é REST HTTP por meio de JSON.For a RESTful interface, the most common choice is REST over HTTP using JSON. Para uma interface de estilo RPC, há várias estruturas populares, incluindo gRPC, Apache Avro e Apache Thrift.For an RPC-style interface, there are several popular frameworks, including gRPC, Apache Avro, and Apache Thrift.

Eficiência.Efficiency. Considere a eficiência em termos de velocidade, memória e payload de tamanho.Consider efficiency in terms of speed, memory, and payload size. Normalmente, uma interface baseada em gRPC é mais rápida do que REST através de HTTP.Typically a gRPC-based interface is faster than REST over HTTP.

Interface (IDL) de linguagem de definição.Interface definition language (IDL). Um IDL é usado para definir os métodos, parâmetros e valores de retorno de uma API.An IDL is used to define the methods, parameters, and return values of an API. Um IDL pode ser utilizado para gerar o código de cliente, o código de serialização e documentação da API.An IDL can be used to generate client code, serialization code, and API documentation. IDLs também podem ser consumidos por ferramentas, como o Postman de teste de API.IDLs can also be consumed by API testing tools such as Postman. Estruturas como gRPC, Avro e Thrift definem suas próprias especificações IDL.Frameworks such as gRPC, Avro, and Thrift define their own IDL specifications. REST através de HTTP não tem um formato IDL padrão, mas uma opção comum é OpenAPI (anteriormente Swagger).REST over HTTP does not have a standard IDL format, but a common choice is OpenAPI (formerly Swagger). Também pode criar uma API de REST de HTTP sem utilizar uma linguagem de definição formal, mas, em seguida, perder os benefícios de geração de código e teste.You can also create an HTTP REST API without using a formal definition language, but then you lose the benefits of code generation and testing.

Serialização.Serialization. Como os objetos são serializados durante a transmissão?How are objects serialized over the wire? As opções incluem formatos baseados em texto (principalmente JSON) e formatos binários, como o buffer de protocolo.Options include text-based formats (primarily JSON) and binary formats such as protocol buffer. Formatos binários são geralmente mais rápidos do que formatos baseados em texto.Binary formats are generally faster than text-based formats. No entanto, o JSON tem vantagens em termos de interoperabilidade, porque a maioria das linguagens e arquiteturas suportam serialização JSON.However, JSON has advantages in terms of interoperability, because most languages and frameworks support JSON serialization. Alguns formatos de serialização requerem um esquema fixo e alguns requerem a compilação de um ficheiro de definição de esquema.Some serialization formats require a fixed schema, and some require compiling a schema definition file. Nesse caso, será necessário incorporar este passo em seu processo de compilação.In that case, you'll need to incorporate this step into your build process.

Suporte de arquitetura e linguagem.Framework and language support. HTTP é suportado em quase todos os framework e linguagem.HTTP is supported in nearly every framework and language. gRPC, Avro e Thrift tem bibliotecas para C++, c#, Java e Python.gRPC, Avro, and Thrift all have libraries for C++, C#, Java, and Python. Thrift e gRPC também oferecem suporte Go.Thrift and gRPC also support Go.

Compatibilidade e interoperabilidade.Compatibility and interoperability. Se escolher um protocolo, como gRPC, poderá ter uma camada de tradução do protocolo entre a API pública e o back-end.If you choose a protocol like gRPC, you may need a protocol translation layer between the public API and the back end. R gateway pode executar essa função.A gateway can perform that function. Se estiver a utilizar uma malha de serviço, considere quais protocolos são compatíveis com a malha de serviço.If you are using a service mesh, consider which protocols are compatible with the service mesh. Por exemplo, linkerd tem suporte incorporado para HTTP, Thrift e gRPC.For example, linkerd has built-in support for HTTP, Thrift, and gRPC.

A nossa recomendação de linha de base é escolher REST através de HTTP, a menos que precise os benefícios de desempenho de um protocolo binário.Our baseline recommendation is to choose REST over HTTP unless you need the performance benefits of a binary protocol. REST através de HTTP não exige nenhum bibliotecas especiais.REST over HTTP requires no special libraries. Ele cria o acoplamento mínimo, uma vez que os chamadores não é necessário um stub de cliente para comunicar com o serviço.It creates minimal coupling, because callers don't need a client stub to communicate with the service. Existe um ecossistema avançada de ferramentas para oferecer suporte a definições de esquema, teste e monitorização de pontos de extremidade RESTful HTTP.There is rich ecosystems of tools to support schema definitions, testing, and monitoring of RESTful HTTP endpoints. Por fim, o HTTP é compatível com os clientes de browser, pelo que não tem uma camada de tradução do protocolo entre o cliente e o back-end.Finally, HTTP is compatible with browser clients, so you don't need a protocol translation layer between the client and the backend.

No entanto, se optar por REST através de HTTP, deve fazer o desempenho e teste no início do processo de desenvolvimento, para validar se ele executa bem o suficiente para o seu cenário de carga.However, if you choose REST over HTTP, you should do performance and load testing early in the development process, to validate whether it performs well enough for your scenario.

Design de API rESTfulRESTful API design

Existem muitos recursos para a criação de RESTful APIs.There are many resources for designing RESTful APIs. Aqui estão algumas que poderão ser úteis:Here are some that you might find helpful:

Aqui estão algumas considerações específicas a ter em conta.Here are some specific considerations to keep in mind.

  • Fique atento a APIs que deixar escapar detalhes da implementação interna ou simplesmente espelham um esquema de base de dados interna.Watch out for APIs that leak internal implementation details or simply mirror an internal database schema. A API deve modelar o domínio.The API should model the domain. É um contrato entre serviços e, idealmente deve apenas ser alterado quando é adicionada nova funcionalidade, não apenas porque refatorado algum código ou normalizados uma tabela de base de dados.It's a contract between services, and ideally should only change when new functionality is added, not just because you refactored some code or normalized a database table.

  • Diferentes tipos de cliente, como aplicações móveis e de navegador da web de área de trabalho, solicitar que os tamanhos de payload diferentes ou padrões de interação.Different types of client, such as mobile application and desktop web browser, may require different payload sizes or interaction patterns. Considere utilizar o back-ends para front-ends padrão para criar o back-ends separado para cada cliente, que expõem uma interface ideal para esse cliente.Consider using the Backends for Frontends pattern to create separate backends for each client, that expose an optimal interface for that client.

  • Para operações com efeitos colaterais, considere torná-los idempotent e implementá-las como métodos PUT.For operations with side effects, consider making them idempotent and implementing them as PUT methods. Que permitirá repetições seguras e pode melhorar a resiliência.That will enable safe retries and can improve resiliency. Os capítulos ingestão e fluxo de trabalho e comunicação entre serviços abordar este problema mais detalhadamente.The chapters Ingestion and workflow and Interservice communication discuss this issue in more detail.

  • Métodos HTTP podem ter semântica assíncrona, em que o método retorna uma resposta imediatamente, mas o serviço realiza a operação de forma assíncrona.HTTP methods can have asynchronous semantics, where the method returns a response immediately, but the service carries out the operation asynchronously. Nesse caso, o método deve retornar um HTTP 202 código de resposta, que indica que o pedido foi aceite para processamento, mas o processamento ainda não foi concluído.In that case, the method should return an HTTP 202 response code, which indicates the request was accepted for processing, but the processing is not yet completed.

O mapeamento de REST para padrões DDDMapping REST to DDD patterns

Padrões como o objeto de valor, de agregação e de entidades foram concebidas para colocar determinadas restrições nos objetos no seu modelo de domínio.Patterns such as entity, aggregate, and value object are designed to place certain constraints on the objects in your domain model. Em muitas discussões de DDD, os padrões são modelados usando orientada a objeto conceitos de linguagem (OO) como construtores ou getters de propriedade e setters.In many discussions of DDD, the patterns are modeled using object-oriented (OO) language concepts like constructors or property getters and setters. Por exemplo, objetos de valor devem para ser imutáveis.For example, value objects are supposed to be immutable. Numa linguagem de programação de OO, iria impor isso por atribuir os valores no construtor e tornar as propriedades só de leitura:In an OO programming language, you would enforce this by assigning the values in the constructor and making the properties read-only:

export class Location {
    readonly latitude: number;
    readonly longitude: number;

    constructor(latitude: number, longitude: number) {
        if (latitude < -90 || latitude > 90) {
            throw new RangeError('latitude must be between -90 and 90');
        }
        if (longitude < -180 || longitude > 180) {
            throw new RangeError('longitude must be between -180 and 180');
        }
        this.latitude = latitude;
        this.longitude = longitude;
    }
}

Esses tipos de práticas recomendadas de codificação são particularmente importantes ao criar uma aplicação monolítica tradicional.These sorts of coding practices are particularly important when building a traditional monolithic application. Com uma base de códigos grandes, poderão utilizar vários subsistemas o Location de objeto, pelo que é importante para o objeto para impor o comportamento correto.With a large code base, many subsystems might use the Location object, so it's important for the object to enforce correct behavior.

Outro exemplo é o padrão de repositório, o que garante que outras partes do aplicativo não faça diretas leituras ou escritas para os dados armazenar:Another example is the Repository pattern, which ensures that other parts of the application do not make direct reads or writes to the data store:

Diagrama de um repositório de Drones

Numa arquitetura de microsserviços, no entanto, os serviços não partilham a mesma base de código e não partilham arquivos de dados.In a microservices architecture, however, services don't share the same code base and don't share data stores. Em vez disso, eles comunicam através de APIs.Instead, they communicate through APIs. Considere o caso em que o serviço do agendador solicita as informações sobre um drone do serviço por Drone.Consider the case where the Scheduler service requests information about a drone from the Drone service. O serviço de Drones tem seu modelo interno de um drone, expressado por meio de código.The Drone service has its internal model of a drone, expressed through code. Mas o agendador não o ver.But the Scheduler doesn't see that. Em vez disso, ele recebe de volta uma representação da entidade por drone — talvez um objeto JSON numa resposta HTTP.Instead, it gets back a representation of the drone entity — perhaps a JSON object in an HTTP response.

Diagrama do serviço por Drone

O serviço de Scheduler não é possível modificar os modelos internos do serviço de Drones, ou escrever para o arquivo de dados do serviço por Drone.The Scheduler service can't modify the Drone service's internal models, or write to the Drone service's data store. Isso significa que o código que implementa o serviço de Drones tem uma menor exposta área de superfície, em comparação com o código num monólito tradicional.That means the code that implements the Drone service has a smaller exposed surface area, compared with code in a traditional monolith. Se o serviço de Drones define uma classe de localização, o escopo dessa classe é limitado — nenhum outro serviço consumirá diretamente a classe.If the Drone service defines a Location class, the scope of that class is limited — no other service will directly consume the class.

Por esses motivos, essa orientação não se concentre muito sobre práticas recomendadas de codificação porque estão relacionados com os padrões DDD táticos.For these reasons, this guidance doesn't focus much on coding practices as they relate to the tactical DDD patterns. Mas acontece que pode também modelar muitos dos padrões de DDD através de REST APIs.But it turns out that you can also model many of the DDD patterns through REST APIs.

Por exemplo:For example:

  • Agregações naturalmente a mapeiam recursos em REST.Aggregates map naturally to resources in REST. Por exemplo, a agregação de entrega poderia ser exposta como um recurso pela API de entrega.For example, the Delivery aggregate would be exposed as a resource by the Delivery API.

  • Os agregados são os limites de consistência.Aggregates are consistency boundaries. Operações em agregações existentes nunca devem deixar um agregado num estado inconsistente.Operations on aggregates should never leave an aggregate in an inconsistent state. Portanto, deve evitar a criação de APIs que permitem que um cliente manipular o estado interno de um agregado.Therefore, you should avoid creating APIs that allow a client to manipulate the internal state of an aggregate. Em vez disso, preferir menos elaboradas APIs que expõem agregados, como recursos.Instead, favor coarse-grained APIs that expose aggregates as resources.

  • Entidades têm identidades únicas.Entities have unique identities. No RESTANTE, recursos têm identificadores exclusivos na forma de URLs.In REST, resources have unique identifiers in the form of URLs. Crie os URLs de recursos que correspondem à identidade de domínio de uma entidade.Create resource URLs that correspond to an entity's domain identity. O mapeamento de URL para a identidade de domínio pode ser opaco para o cliente.The mapping from URL to domain identity may be opaque to client.

  • Entidades subordinadas de uma agregação podem ser alcançadas ao navegar a partir da entidade de raiz.Child entities of an aggregate can be reached by navigating from the root entity. Se seguir HATEOAS princípios, as entidades subordinadas podem ser contatadas por meio de links na representação da entidade principal.If you follow HATEOAS principles, child entities can be reached via links in the representation of the parent entity.

  • Como os objetos de valor são imutáveis, as atualizações são realizadas, substituindo o objeto de valor inteiro.Because value objects are immutable, updates are performed by replacing the entire value object. No RESTANTE, implemente atualizações através de pedidos PUT ou PATCH.In REST, implement updates through PUT or PATCH requests.

  • Um repositório permite que a consulta de clientes, adicionar ou remover objetos numa coleção, abstraindo os detalhes do arquivo de dados subjacente.A repository lets clients query, add, or remove objects in a collection, abstracting the details of the underlying data store. REST, uma coleção pode ser um recurso distinto, com métodos para consultar a coleção ou adicionar novas entidades à coleção.In REST, a collection can be a distinct resource, with methods for querying the collection or adding new entities to the collection.

Ao conceber as suas APIs, pense em como eles express que o modelo de domínio, não apenas os dados dentro do modelo, mas também as operações de negócio e as restrições nos dados.When you design your APIs, think about how they express the domain model, not just the data inside the model, but also the business operations and the constraints on the data.

Conceito DDDDDD concept Equivalente RESTREST equivalent ExemploExample
AgregarAggregate RecursoResource { "1":1234, "status":"pending"... }
IdentidadeIdentity do IdPURL https://delivery-service/deliveries/1
Entidades subordinadasChild entities LigaçõesLinks { "href": "/deliveries/1/confirmation" }
Objetos de valor de atualizaçãoUpdate value objects PUT ou PATCHPUT or PATCH PUT https://delivery-service/deliveries/1/dropoff
RepositórioRepository ColeçãoCollection https://delivery-service/deliveries?status=pending

Controlo de versões de APIAPI versioning

Uma API é um contrato entre um serviço e os clientes ou consumidores desse serviço.An API is a contract between a service and clients or consumers of that service. Se uma API for modificada, existe o risco de quebrar os clientes que dependem da API, se eles são clientes externos ou outros microsserviços.If an API changes, there is a risk of breaking clients that depend on the API, whether those are external clients or other microservices. Portanto, é uma boa idéia para minimizar o número de alterações de API que fizer.Therefore, it's a good idea to minimize the number of API changes that you make. Muitas vezes, as alterações na implementação subjacente não necessitam de quaisquer alterações à API.Often, changes in the underlying implementation don't require any changes to the API. Na realidade, no entanto, em algum momento desejará adicionar novos recursos ou novas capacidades que requerem a alteração de uma API existente.Realistically, however, at some point you will want to add new features or new capabilities that require changing an existing API.

Sempre que possível, API de fazer alterações compatíveis com versões anteriores.Whenever possible, make API changes backward compatible. Por exemplo, evite a remover um campo de um modelo, uma vez que pode quebrar os clientes que esperam o campo esteja lá.For example, avoid removing a field from a model, because that can break clients that expect the field to be there. Adicionar um campo não interromper a compatibilidade, uma vez que os clientes devem ignorar quaisquer campos não entendem numa resposta.Adding a field does not break compatibility, because clients should ignore any fields they don't understand in a response. No entanto, o serviço tem de processar o caso em que um cliente antigo omite o novo campo num pedido.However, the service must handle the case where an older client omits the new field in a request.

Suporta o controlo de versões no seu contrato de API.Support versioning in your API contract. Se introduzir uma alteração de API de última hora, introduza uma nova versão de API.If you introduce a breaking API change, introduce a new API version. Continue a suportar a versão anterior e permitir que os clientes, selecione a versão a chamar.Continue to support the previous version, and let clients select which version to call. Existem algumas maneiras de fazer isso.There are a couple of ways to do this. Uma é simplesmente a exposição de ambas as versões no mesmo serviço.One is simply to expose both versions in the same service. Outra opção é executar duas versões da serviço do lado a lado e encaminhar pedidos para um ou a outra versão, com base nas regras de encaminhamento de HTTP.Another option is to run two versions of the service side-by-side, and route requests to one or the other version, based on HTTP routing rules.

Controlo de versões

Há um custo para dar suporte a várias versões, em termos de tempo de desenvolvimento, teste e sobrecarga operacional.There's a cost to supporting multiple versions, in terms of developer time, testing, and operational overhead. Portanto, é bom preterir versões antigas mais depressa possível.Therefore, it's good to deprecate old versions as quickly as possible. Para APIs internas, a equipe que possui a API pode trabalhar com outras equipes para os ajudar a migrar para a nova versão.For internal APIs, the team that owns the API can work with other teams to help them migrate to the new version. Isso é quando ter um processo de governação entre equipas é útil.This is when having a cross-team governance process is useful. Para APIs (públicas) externas, ele pode ser mais difícil preterir uma versão de API, especialmente se as APIS são consumidas por terceiros ou por aplicações clientes nativas.For external (public) APIs, it can be harder to deprecate an API version, especially if the API is consumed by third parties or by native client applications.

Quando um alterado de implementação de serviço, é útil marcar a alteração com uma versão.When a service implementation changes, it's useful to tag the change with a version. A versão fornece informações importantes quando resolver problemas de erros.The version provides important information when troubleshooting errors. Pode ser muito útil para a análise da causa raiz saber exatamente qual versão do serviço foi chamado.It can be very helpful for root cause analysis to know exactly which version of the service was called. Considere a utilização controle de versão semântica de versões de serviço.Consider using semantic versioning for service versions. Controle de versão semântica utiliza um principais. PEQUENAS. PATCH formato.Semantic versioning uses a MAJOR.MINOR.PATCH format. No entanto, os clientes devem selecionar apenas uma API, o número de versão principal, ou, possivelmente, a versão secundária se existirem significativa (mas alterações sem interrupções) entre as versões secundárias.However, clients should only select an API by the major version number, or possibly the minor version if there are significant (but non-breaking) changes between minor versions. Em outras palavras, é razoável para os clientes para selecionar entre a versão 1 e versão 2 de uma API, mas não para selecionar versão 2.1.3.In other words, it's reasonable for clients to select between version 1 and version 2 of an API, but not to select version 2.1.3. Se permitir que esse nível de granularidade, corre o risco de ter que suportar uma proliferação de versões.If you allow that level of granularity, you risk having to support a proliferation of versions.

Para uma discussão mais de controle de versão de API, consulte controlo de versões de uma API RESTful web.For further discussion of API versioning, see Versioning a RESTful web API.