Este documento define os padrões que devem ser adotados durante a implementação de novas APIs publicas ou privadas na plataforma do fluig incluido:
Criamos um comitê interno, formado com um integrante de cada squad, para discutir e garantir a execução dos padrões definidos neste documento.
Cada um dos membros deve obrigatoriamente ser incluído no pull request de novas APIs publicas e cadas um deles é responsável por garantir a correta disseminação e implementação dentro de seu próprio time das APIs privadas.
Squad | Membro |
---|---|
SDK | Marcelo De Aguiar |
Identity / Portal | Paulo Roberto Francisco Junior |
LMS | Diego Lopes |
BPM | Gustavo Martins De Souza |
PAAS / Fundação | Vanei Anderson Heidemann |
ECM | Andre Felipe Joriatti |
Integração | Danilo Pacheco Martins |
Cliente: Qualquer aplicativo que faça uma requisição para um endpoint do fluig.
Mensagem: Conteúdo enviado no corpo de uma requisição ou resposta do servidor.
Endpoint: Representa um método ou entidade que pode ser acessado através de uma requisição ao servidor do fluig.
Verbo: Tipo de requisição usada para acessar um endpoint (GET, POST, PUT, HEAD, etc).
API: Grupo de endpoints
APIs Privadas são todas as APIs acessíveis apenas pelos times do fluig
APIs Publicas são todas as APIs que podem ser acessadas por clientes externos aos times de desenvolvimento do fluig.
Os caminhos definidos para cada endpoint devem ser de fácil leitura e significativos para o cliente para facilitar a sua descoberta e adoção. Os pontos abaixo DEVEM ser considerados ao criar uma URL:
Exemplo de URLs amigáveis:
Colocar exemplo de filtro e expansíveis
Exemplo de URLS NÃO amigaveis e que deve ser evitadas:
Apesar de o padrão definido no documento RFC 7230 da especificação do HTTP 1.1 não definir um tamanho maximo para a url nenhum endpoint do fluig deve ser identificado com uma url maior que 2000 caracteres para garantir que todos os navegares modernos sejam suportados
Mais informações sobre a escolha do valor máximo de caracteres pode ser consultada em: https://blogs.msdn.microsoft.com/ieinternals/2014/08/13/url-length-limits/ |
Endpoints devem usar os métodos HTTP adequados e devem respeitar a idempotência da operação.
Na tabela abaixo serão listados os métodos que DEVEM ser suportados. Nem todos os endpoints devem suportar todos os métodos, mas os que usarem DEVEM respeitar a utilização conforme descrita.
Método | Descrição | Idempotente | ||
---|---|---|---|---|
GET | Retorna o valor corrente do objeto. | Sim | ||
PUT | Sobrescreve o objeto quando aplicável. Por exemplo: O cliente gostaria de sobrescrever o usuário com novos valores:
| Sim | ||
DELETE | Exclui o objeto. | Sim | ||
POST | Cria um novo objeto ou submete um comando ao objeto. | Não | ||
HEAD | Retorna os metadados da requisição em casos em que o cliente não precisa do corpo das requisições do tipo GET. | Sim | ||
PATCH | PATH foi padronizado pelo IETF como o método usado para atualizar um objeto de forma incremental (ver RFC 5789), ou seja, apenas as propriedades informadas pelo cliente serão atualizadas. Por exemplo: O cliente gostaria de atualizar o nome do usuário e para isso vai usar o endpoint de atualização de usuários
O servidor deverá implementar o serviço de modo que apenas o nome do usuário seja atualizado e todas as outras propriedades mantidas. | Não | ||
OPTIONS | Retorna informações sobre um endpoint e sobre as operações suportadas por ele; ver abaixo para mais detalhes. | Sim |
Deve-se atentar aos códigos de retorno para os tipos de operações definidos para usar estes métodos principalmente nos casos definidos abaixo:
Verbo | Usado para | Tipo de operação | Código de sucesso | Detalhes | ||
---|---|---|---|---|---|---|
POST | Criar uma entidade | Síncrona | 201 | Além do código de sucesso deve retorna a nova entidade criada. | ||
PATCH ou PUT | Atualizar uma entidade | Síncrona | 200 | Além do código de sucesso deve retorna a nova entidade atualizada. | ||
POST, PATCH, PUT | Criar ou atualizar entidade | Assíncrona | 202 | O código 202 informa ao cliente que o serviço aceitou a requisição para processamento e que isso pode levar um tempo para concluir. Nesse caso o endpoint DEVE retornar o campo Location no cabeçalho da resposta apontando para onde a nova entidade poderá ser encontrada. Por exemplo, considere o endpoint de cadastro assíncrono de usuários:
DEVE retornar como responta:
|
A utilização destes cabeçalhos não é obrigatória para todos os endpoints mas os que os usarem DEVEM obedecer as regras descritas aqui.
Header | Tipo | Descrição |
---|---|---|
Authorization | literal | Cabeçalho usado para autorização das requisições |
Date | data | Data e hora da requisição com base no calendário do cliente no formato estipulado em RFC 5322 |
Accept | enumerador de tipo de conteúdo | O tipo de conteúdo esperado para a resposta como por exemplo:
De acordo com os padrões HTTP, este valor é apenas uma dica para o servidor e as respostas PODEM retornar valores em formatos diferentes dos informados. |
Accept-Encoding | Gzip, deflate | Endpoints DEVEM suportar codificação GZIP e DEFLATE por padrão exceto em casos em que isso implique na performance. |
Accept-Language | "en", "es", "pt" | Especifica o idioma preferencial da resposta. Endpoints DEVEM suportar e respeitar estes valores em casos em que uma mensagem é retornada ao usuário. Caso o idioma informado não seja suportado deve retornar no idioma padrão (pt). |
Content-Type | tipo de conteúdo | Tipo do conteúdo sendo passado na requisição. O endpoint DEVE respeitar esta informação na hora de interpretar a informação passada pelo cliente ou retornar um erro apropriado caso o valor não for suportado. |
Endpoints DEVEM retornar estes cabeçalhos em todas as reposta a menos que explicitamente citado o contrário na coluna obrigatório
Cabeçalho | Obrigatório | Descrição |
---|---|---|
Date | Em todas as respostas | Hora em que a resposta foi processada baseada no calendário do servidor no formato estipulado em RFC 5322. Ex: Wed, 24 Aug 2016 18:41:30 GMT . |
Content-Type | Em todas as respostas | O tipo de conteúdo enviado do endpoint para o servidor. |
Content-Encoding | Em todas as respostas | GZIP ou DEFLATE como for apropriado. |
Cabeçalhos customizados NÃO DEVEM ser utilizados para representar qualquer estado, valor ou ação sobre a entidade representada pela url. Isso quer dizer que cabeçalhos NÃO DEVE ter relação com o cliente do endpoint (mobile, desktop, etc), url, corpo da mensagem, corpo da resposta ou parâmetros da url. O protocolo HTTP oferece uma séria de cabeçalhos para quase todas as situações e estas sempre tem precedência a um cabeçalho customizado.
Nos casos extremos onde não houver outra maneira de representar a informação, pode-se optar por criar um cabeçalho que DEVE estar descrito na documentação do endpoint e este DEVE seguir o padrão X-fluig-[Nome do cabeçalho]
Precisamos decidir se vamos suportar XML E Json ou apenas um deles.
JSON DEVE ser o formato padrão para mensagens e as propriedades destas mensagens DEVEM ser escritas usando camelCase.
Todos os endpoints DEVEM suportar este tipo de conteúdo.
Para todas as mensagens que representam um erro (códigos HTTP 4xx e 5xx) deve-se retornar obrigatoriamente os campos a seguir:
{ code: "Código identificador do erro", helpUrl: "link para a documentação do error", message: "Literal no idioma da requisição descrevendo o erro para o cliente", detailedMessage: "Mensagem técnica e mais detalhada do erro" } |
O campo code deve identificar unicamente o erro na documentação da API;
Todos os códigos de error DEVEM estar mapeados e listados na documentação da API. |
Em alguns casos se faz necessário retornar mais campos do que os estipulados acima. Nestes casos a informação deve ser considerada opcional do ponto de vista do cliente, ou seja, o cliente não deve depender dela para o tratamento do erro. |
Dividimos os erros em duas categorias: Erros de negócio ou requisição e Erros não esperados.
Erros de negócio ou requisição são aqueles causados por dados inválidos na requisiçõe ou intencionalmente lançados do endpoint para o cliente. Todos os erros deste tipo devem obrigatoriamente retornar um código HTTP 4xx. Ex:
Erros não esperados são os erros não tratados ou não intencionais. Esse tipo de erro deve sempre retornar códigos HTTP 5xx. Ex:
{ } |
Todos os endpoints DEVEM respeitar e suportar os campos expansíveis. E DEVEM retornar os campos retraídos a menos que especificado na requisição atráves do parâmetro de url expand.
As entidades de retorne DEVEM obedecer as regras:
Ao retornar uma entidade todas as suas propriedades que representam um objeto OU coleção DEVEM vir retraídas e a entidade DEVE conter um campo adicional com o nome _expandables. Esse campo é uma lista com o nome de cada uma das propriedades que podem ser passadas na url para que o endpoint inclua na responta.
Por exemplo, a entidade usuário possui propriedades que apontam para suas permissões, comunidades e detalhes e portanto estas dem estar retraídas:
POST https://fluig.totvs.com/api/users/10 { _expandables: ["permissions", "communities", "detailedInformation"], id: 10, name: "Usuário", age: 25, permissions: [], communities: [], detailedInformation: {}, ... } |
Caso o cliente queira expandir as propriedades ele DEVE então fazer uma requisição informando o parâmetro expand na url e passando como valor uma lista separada por , (virgula) dos campos exatamente como descritos no campo _expandables.
Apenas o primeiro nível das propriedades deve ser expandido, ou seja, se o objeto expandido tiver propriedades expansíveis elas devem vir retraídas. |
Por exemplo, no cenário em que o cliente gostaria de expandir as comunidades da entidade usuário:
POST https://fluig.totvs.com/api/users/10?expand=communities { _expandables: ["permissions", "detailedInformation"], id: 10, name: "Usuário", age: 25, permissions: [], communities: [{ name: "Vendas", photoUrl: "https://fluig.totvs.com/communities/1/photo", permissions: {} }, { name: "Outra comunidade", photoUrl: "https://fluig.totvs.com/communities/2/photo", permissions: {} }], detailedInformation: {}, ... } |
Note que as propriedades do objeto expandido DEVEM vir retraídas por padrão. O cliente PODE solicitar que as propriedades dos objetos sejam expandidas separando as sub-propriedades com ponto (.). Usando o exemplo acima, o usuário gostaria de expandir as permissões das comunidades da entidade usuário:
POST https://fluig.totvs.com/api/users/10?expand=communities.permissions { _expandables: ["permissions", "detailedInformation"], id: 10, name: "Usuário", age: 25, permissions: [], communities: [{ name: "Vendas", photoUrl: "https://fluig.totvs.com/communities/1/photo", permissions: { isAdmin: true, canView: true } }, { name: "Outra comunidade", photoUrl: "https://fluig.totvs.com/communities/2/photo", permissions: { isAdmin: true, canView: true } }], detailedInformation: {}, ... } |
Dicas de como implementar os métodos para tentar manter um padrão de implementação.