Documentar a estrutura, funcionamento e práticas relacionadas à mensagem padronizada TOTVS utilizando REST como padrão de comunicação e JSON como formato de mensagem.
IMPORTANTE
Este documento leva em consideração que o leitor tenha um conhecimento prévio da mensagem padronizada TOTVS utilizando XML e SOAP. Caso algum termo não esteja suficientemente descrito aqui, recomenda-se consultar o documento relacionado a elaboração de mensagem padronizada em SOAP/XML, disponível aqui.
Semelhante ao que se tem na mensagem padronizada, baseada em SOAP e XML, a estrutura é composta dos seguintes elementos:
Graficamente, a estrutura pode ser descrita conforme abaixo:
A dinâmica envolvendo o envio e recebimento de mensagens não se altera com a nova proposta. O que muda, de fato, são o formato da mensagem e a interface.
Os modos de operação continuam os mesmos: síncrono e assíncrono, sendo que neste último continuamos a ter a necessidade de uma fila e de um agente que se responsabilize por sua gestão (processador de fila).
A geração das mensagens continua a cargo dos adapters, que entregam para a Engine do EAI a estrutura de dados necessária para gerar a mensagem no padrão TOTVS. Da mesma, forma o recebimento das mensagens continua sendo intermediado pelo Engine de EAI, que determinará qual o adapter responsável por processar a mensagem recebida.
Considerando a crescente implementação de APIs nos produtos TOTVS e visando a definição de um glossário único na troca de dados entre os participantes de uma integração, estabeleceu-se a obrigatoriedade da mensagem padronizada nos seguintes contextos:
Em função do exposto acima, a definição e uso de InternalId nas transações deve seguir esta orientação:
A mensagem padronizada, utilizando JSON como formato, será composta dos elementos Header e Content.
Header: contem informações sobre a mensagem sendo trafegada, como seu identificador único, data em que foi gerada, transação ao qual se refere, entre outras. São dados equivalentes a tag MessageInformation, do formato XML. Os atributos JSON correspondentes seguem as mesmas convenções de obrigatoriedade do padrão original. As tags que não estão descritas aqui, a principio, não serão utilizadas.
Content: contem informações equivalentes a tag BusinessContent, para mensagens de negócio, ou a tag ReturnContent, para mensagens de resposta. Devido a isso, os atributos podem variar de acordo com a definição da transação. Entretanto, os atributos modelados para preencher o atributo Content, que corresponde ao contexto de uso server-to-server, devem ser os mesmos no contexto de uso client-to-server.
Quando a mensagem for de resposta, o atributo Content terá ainda os seguintes atributos:
Tag Identification
A tag Identification, subordinada à tag BusinessEvent, não será contemplada no formato REST/JSON. Essa tag foi sendo substituída ao longo do tempo pelos InternalIDs do corpo das mensagens. Ao migrar um adapter para utilizar o novo formato, qualquer processamento baseado na tag Identification deve ser revisto.
Uma mensagem da transação CostCenter, na versão 2.000, no contexto de uso server-to-server, seria expressa da seguinte forma, usando o formato JSON:
{ "Header" : { "UUID" : "d6bbfa63-ca27-e2ac-0b14-101970f59a5b", "Type" : "BusinessMessage", "SubType" : "event", "Event" : "upsert", "Transaction" : "CostCenter", "Version" : "2.000", "SourceApplication": "P1299", "ProductName" : "PROTHEUS", "ProductVersion" : "12.1.17", "CompanyId" : "99", "BranchId" : "01", "GeneratedOn" : "2017-11-14T11:47:00-03:00", "DeliveryType" : "async", }, "Content" : { "CompanyId" : "99", "BranchId" : "01", "CompanyInternalId" : "99", "Code" : "ABC001", "InternalId" : "99|ABC001", "RegisterSituation" : "Active", "Name" : "Centro de Custo ABC001", "ShortCode" : "ABC001", "SPED" : true, "Class" : 2 } }
A mensagem de resposta correspondente seria semelhante ao exemplo abaixo:
{ "Header" : { "UUID" : "a1b2c3d4-e5f6-g7h8-i9j0-k1l2m3n4o5p6", "Type" : "Response", "SubType" : "event", "Transaction" : "CostCenter", "Version" : "2.000", "SourceApplication" : "LGX12", "ProductName" : "LOGIX", "ProductVersion" : "12.1.15", "GeneratedOn" : "2017-11-14T11:47:15-03:00", "DeliveryType": "async" }, "Content" : { "ReceivedMessage" : { "UUID" : "d6bbfa63-ca27-e2ac-0b14-101970f59a5b", "SentBy" : "P1299", "Event" : "upsert" }, "ProcessingInformation" : { "ProcessedOn" : "2017-11-14T11:47:15-03:00", "Status" : "Ok" }, "ReturnContent" : { "ListOfInternalID" : [ { "Name" : "CostCenter", "Origin" : "99|ABC001", "Destination" : "10|1000" }, { "Name" : "Company", "Origin" : "99", "Destination" : "10" } ] } } }
Para mensagem de Resposta Assíncronas o método do envio deve ser POST, pois esta sendo trafegada a resposta, independente da operação original. Para obter o processo da mensagem original pode se acessar a propriedade Content.ReceivedMessage.Event.
O padrão REST/JSON fornece também um modelo para lote de mensagens, onde as mensagens são agrupadas em um array JSON, de nome items.
{ "Items" : [ { "Header" : { "UUID" : "", "Type" : "", "SubType" : "", "Event" : "", "Transaction" : "customerVendor", "Version" : "2.001", "SourceApplication": "", "ProductName" : "", "ProductVersion" : "", "GeneratedOn" : "", "DeliveryType" : "async", }, "Content" : { "Atributo1" : "", "Atributo2" : "", ... "AtributoN" : "" } },{ "Header" : { "UUID" : "", ... "Transaction" : "item", "Version" : "3.001", ... "DeliveryType" : "async" }, "Content" : { "Atributo1" : "", "Atributo2" : "", ... "AtributoN" : "" } } ] }
O uso do formato de lote de mensagens tem algumas considerações importantes:
A transação CostCenter, versão 2.000, no contexto de uso client-to-server, seria representada em JSON conforme segue:
{ "CompanyId" : "99", "BranchId" : "01", "Code" : "ABC001", "RegisterSituation" : "Active", "Name" : "Centro de Custo ABC001", "ShortCode" : "ABC001", "SPED" : true, "Class" : 2 }
Observe que os campos relativos a InternalId não estão presentes, por serem opcionais neste contexto de uso.
As mensagens padronizadas em formato JSON serão recebidas por um endpoint padrão, conforme descrito abaixo:
/totvseai/standardmessage/v1/{resource}
No endpoint, v1 corresponde à versão do padrão de mensagem, que pode evoluir. A versão será alterada, quando necessário, conforme o Guia de Implementação de APIs.
Em resource, pode-se informar as seguintes opções:
Salvo quando explicitamente indicado no documento, deve-se considerar que os endpoints disponibilizam os recursos previstos no Guia de Implementação de APIs para paginação, ordenação e filtro de dados.
Onde:
Os métodos HTTP previstos são:
Requests usando método DELETE
Por definição, não serão aceitas mensagens com subtipo request no método DELETE. Apenas mensagens com subtipo event serão permitidas. Quando tal situação ocorre, será retornado, no mínimo, o código HTTP 405 (Method not allowed).
Método HTTP x atributo Event
Diante do descrito até o momento, há duas formas de se indicar a operação de uma mensagem do tipo BusinessMessage: via métodos HTTP (POST e DELETE) e via atributo Event.
Sempre que for possível determinar a operação pelos atributos do canal, esta será a informação prevalente, como é o caso do canal REST, onde os métodos HTTP provêm essa indicação. Neste caso, pode ocorrer sobre posição da informação no atributo Event da mensagem, se ele não for compatível com a indicação do canal.
O atributo Event, dentro da mensagem, será considerado apenas nos casos onde o canal não fornecer a indicação da operação, como é o caso do canal AMQP.
Exemplos de utilização deste predicado podem ser encontrados nos links a seguir:
No período de migração das implementações em XML para JSON, será necessário que os formatos convivam simultaneamente e sejam interoperáveis.Isso implica que a modelagem de uma transação usando o padrão REST/JSON seja compatível com a modelagem usando o padrão SOAP/XML (orientações no tópico seguinte).
Assim que todos os ERPs forem capazes de trabalhar com a nova proposta, o formato XML e os endpoints SOAP poderão ser desativados.
Para permitir a utilização dos adapters atuais, sem que seja necessário convertê-los de imediato para o formato JSON, está disponível um conversor de XML para JSON e vice-versa, implementado no formato de DLL. Para mais informações, consulte a documentação correspondente.
Para apoiar na migração de adapters do formato XML para o formato JSON, foi desenvolvido o documento Equivalência entre formatos, o qual possui orientações importantes para este processo.
O desenho de uma transação, no formato REST/JSON, deve utilizar o formato Json Schema, Draft 4 ou superior, em substituição ao formato XML Schema (XSD) utilizado na implementação SOAP/XML. Para mais informações sobre como implementar um documento no formato Json Schema consulte a especificação própria do padrão.
Em nome da consistência entre os formatos, é necessário ter em mente o seguinte procedimento: ao desenvolver, por exemplo, um documento Json Schema (padrão REST/JSON) para a transação CostCenter, versão 2.000, deve-se verificar se já existe um documento XSD da referida transação (padrão SOAP/XML). Existindo o documento, todos os atributos que definem a tag BusinessContent devem estar presentes no tipo equivalente no documento Json Schema, para que o modelo seja considerado como sendo da transação CostCenter, versão 2.000.
Por outro lado, é possível que um documento Json Schema seja implementado sem que haja o correspondente em XSD. Neste caso, a modelagem deve ser elaborada considerando que a transação também pode vir a ser usada no futuro para integração server-to-server, e por isso, deve conter atributos que permitam o uso em tal contexto, mesmo que inicialmente a utilização seja no contexto client-to-server. Se isso for levado em consideração, não será necessário criar um documento XSD equivalente para a mesma transação e versão.
Para a documentação da transação no arquivo de definição Json Schema, há regras para a mensagem e para os campos, conforme abaixo:
Conforme descrito no item Funcionamento deste documento, os atributos relativos ao InternalId devem ser modelados, independentemente do contexto de uso.
O exemplo a seguir mostra a modelagem da transação Branch, versão 2.001, usando o padrão Json Schema, considerando a obrigatoriedade da definição de InternalIds, mas não o seu uso. Ou seja, os campos de InternalId não são marcados como requeridos.
{ "$schema": "https://raw.githubusercontent.com/totvs/ttalk-standard-message/master/jsonschema/schemas/events/branch_2_001.json#", "info": { "description": "Contrato de Mensagem Padronizada para a entidade filial (Branch) para produtos TOTVS", "version": "2.001", "title": "Branch", "contact": { "name": "T-Talk", "url": "API.Totvs.com.br", "email": "[email protected]" }, "x-totvs": { "transactionMessageDocumentation": { "subType": "event", "businessContentType": { "type": "object", "$ref": "#/definitions/BranchType" }, "returnContentType": { "type": "object", "$ref": "https://raw.githubusercontent.com/totvs/ttalk-standard-message/master/jsonschema/schemas/ListOfInternalId_1_000.json#/definitions/ReturnContentWithModelType" } }, "messageDocumentation": { "name": "Branch", "description": "Filial", "segment": "FrameWork" }, "productInformation": [ { "product" : "protheus", "contact": "[email protected]", "description": "Cadastro de Filial", "adapter": "apcfg230i.prw", "helpUrl": "link aqui" } ] } }, "definitions": { "BranchType": { "type": "object", "properties": { "CompanyCode": { "type": "string", "example": "D", "description": "Código da Empresa", "x-totvs": [ { "product": "protheus", "Field": "XX8.XX8_CODIGO", "Required": false, "Type": "Char", "length": "12", "avialable": true, "canUpdate": false } ] }, "internalId": { "description": "InternalId da entidade", "type": "string", "example": "01", "x-totvs": [ { "product": "protheus", "Field": "XX8.XX8_CODIGO", "Required": false, "Type": "Char", "length": "100", "avialable": true, "canUpdate": false } ] }, "Description": { "type": "string", "example": "Filial São Paulo 1", "description": "Descrição", "x-totvs": [ { "product": "protheus", "Field": "XX8.XX8_NOME", "Required": false, "Type": "Char", "length": "100", "avialable": true, "canUpdate": false } ] }, "Code": { "type": "string", "example": "D SP 01", "description": "Filial/Codigo Unidade" }, (...) }, "required":["CompanyCode"] } } }