# Problemas APIs Sienge
###### tags: `Sienge` `APIs` `Acompanhamentos`
### APIs
- Municípios: GET /cities
- Profissões: GET /professions
- Estados Civis: GET /civil-status
### O Problema
As APIs não permitem busca textual, ou seja a API de cidades não permite uma busca "LIKE nomeCidade", ou a API de Profissões não permite uma busca "LIKE nomeProfissão, e isso causa um problema no produto da API em si, no Sienge e nos consumidores das APIs.
Imaginemos o seginte cenário:
Uma construtora realiza as operações de venda em um CRM de mercado, este CRM parceiro precisa enviar um contrato de venda para o Sienge.
- Passo 1: Cadastrar o cliente para qual a venda foi realizada
- Passo 2: Cadastrar o contrato de venda vinculando o cliente cadastrado a este novo contrato.
Dentro dos dados enviados para cadastrar este cliente está os dados do "Endereço do Cliente", "Endereço de Cobrança", "Endereço Comercial", "Endereço do Conjugê", "Profissão", "Profissão do Conjugê"....
Acontece para que seja possível cadastrar esses dados no Sienge é necessário enviar os "ids" das já pré-cadastradas informaçoes: Para cadastrar o endereço do cliente é necessário enviar o "id" de uma cidade (\profissão\estado civil) que já exista nos cadastros do Sienge.
O CRM não possuí a mesma forma de trabalho e também não possúi uma sincronização de cadastros básicos entre sistemas, por esse motivo o CRM não é capaz de enviar um "id" desses cadastros sem antes fazer um trabalho de crawler na base do Sienge.
---
Para ser capaz de realizar esse cadastro de cliente, o CRM (e qualquer um que tente fazer o mesmo), deverá uma busca de todas as cidades\profissões\estado civil cadastradas no Sienge, ou seja, realizar o GET páginado, e buscar todas as páginas possíveis trazendo para si todo o cadastro de cidades\profissões\estado civil, para só depois com tudo isso em memória realizar uma busca textual pelo nome afim de encontrar qual "id" deve ser vinculado.
Então toda vez que um contrato de venda é enviado para o Sienge, a integração do CRM deve buscar toda a base de cidades\profissões\estado civil.
---
Além de trabalhoso e não inteligente, temos outros problemas:
- Os clientes pagam os pacotes de APIs por número de requisições, então um trabalho que poderia ser realizado com apenas 5 requisições (GET cidade, GET profissão, GET estado-civil, POST cliente, POST contrato ), agora é feito com dezenas: (25 requisições para pegar todas as páginas de cidades, 25 requisições para pegar todas as pagina de profissões, etc...)
- Outro problemas é que, ao dar o loop na paginação o Sienge leva um problema para si mesmo por não aguentar receber essa carga (mesmo que pequena), elevando o load da máquina na infra-estrutura e sofrendo problemas de concorrência, como exemplo abaixo:
O Sienge não aguentou suportar 25 chamadas, com o loop da páginação da API de cidades:
> O problema de concorrência das APIs -> Acreditamos que esse seja um problema crónico no Sienge, pois outras APIs já sofreram casos assim (Caso das APIs de cobranças\boletos)
>
```javascript=
[
{
status: 422,
statusText: 'Unprocessable Entity',
headers: {
server: 'nginx',
date: 'Thu, 27 Aug 2020 21:04:34 GMT',
'content-type': 'application/json;charset=UTF-8',
'transfer-encoding': 'chunked',
connection: 'close',
'x-ratelimit-limit-minute': '3000',
'x-ratelimit-remaining-minute': '2983',
'x-xss-protection': '1; mode=block, 1; mode=block',
'x-frame-options': 'SAMEORIGIN, SAMEORIGIN',
'strict-transport-security': 'max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains',
'x-frame-option': 'DENY, DENY',
'x-kong-upstream-latency': '221',
'x-kong-proxy-latency': '0',
via: 'kong/0.14.1'
},
body: {
status: 422,
developerMessage: 'Result set is already closed.',
clientMessage: ''
}
},
{
status: 422,
statusText: 'Unprocessable Entity',
headers: {
server: 'nginx',
date: 'Thu, 27 Aug 2020 21:04:34 GMT',
'content-type': 'application/json;charset=UTF-8',
'transfer-encoding': 'chunked',
connection: 'close',
'x-ratelimit-limit-minute': '3000',
'x-ratelimit-remaining-minute': '2982',
'x-xss-protection': '1; mode=block, 1; mode=block',
'x-frame-options': 'SAMEORIGIN, SAMEORIGIN',
'strict-transport-security': 'max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains',
'x-frame-option': 'DENY, DENY',
'x-kong-upstream-latency': '216',
'x-kong-proxy-latency': '1',
via: 'kong/0.14.1'
},
body: {
status: 422,
developerMessage: 'Result set is already closed.',
clientMessage: ''
}
},
{
status: 422,
statusText: 'Unprocessable Entity',
headers: {
server: 'nginx',
date: 'Thu, 27 Aug 2020 21:04:34 GMT',
'content-type': 'application/json;charset=UTF-8',
'transfer-encoding': 'chunked',
connection: 'close',
'x-ratelimit-limit-minute': '3000',
'x-ratelimit-remaining-minute': '2981',
'x-xss-protection': '1; mode=block, 1; mode=block',
'x-frame-options': 'SAMEORIGIN, SAMEORIGIN',
'strict-transport-security': 'max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains',
'x-frame-option': 'DENY, DENY',
'x-kong-upstream-latency': '201',
'x-kong-proxy-latency': '1',
via: 'kong/0.14.1'
},
body: {
status: 422,
developerMessage: 'Result set is already closed.',
clientMessage: ''
}
},
{
status: 422,
statusText: 'Unprocessable Entity',
headers: {
server: 'nginx',
date: 'Thu, 27 Aug 2020 21:04:34 GMT',
'content-type': 'application/json;charset=UTF-8',
'transfer-encoding': 'chunked',
connection: 'close',
'x-ratelimit-limit-minute': '3000',
'x-ratelimit-remaining-minute': '2980',
'x-xss-protection': '1; mode=block, 1; mode=block',
'x-frame-options': 'SAMEORIGIN, SAMEORIGIN',
'strict-transport-security': 'max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains',
'x-frame-option': 'DENY, DENY',
'x-kong-upstream-latency': '184',
'x-kong-proxy-latency': '0',
via: 'kong/0.14.1'
},
body: {
status: 422,
developerMessage: 'Result set is already closed.',
clientMessage: ''
}
},
{
status: 422,
statusText: 'Unprocessable Entity',
headers: {
server: 'nginx',
date: 'Thu, 27 Aug 2020 21:04:34 GMT',
'content-type': 'application/json;charset=UTF-8',
'transfer-encoding': 'chunked',
connection: 'close',
'x-ratelimit-limit-minute': '3000',
'x-ratelimit-remaining-minute': '2979',
'x-xss-protection': '1; mode=block, 1; mode=block',
'x-frame-options': 'SAMEORIGIN, SAMEORIGIN',
'strict-transport-security': 'max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains',
'x-frame-option': 'DENY, DENY',
'x-kong-upstream-latency': '171',
'x-kong-proxy-latency': '1',
via: 'kong/0.14.1'
},
body: {
status: 422,
developerMessage: 'Result set is already closed.',
clientMessage: ''
}
},
{
status: 200,
statusText: 'OK',
headers: {
server: 'nginx',
date: 'Thu, 27 Aug 2020 21:04:35 GMT',
'content-type': 'application/json;charset=UTF-8',
'transfer-encoding': 'chunked',
connection: 'close',
vary: 'Accept-Encoding, Accept-Encoding',
'x-ratelimit-limit-minute': '3000',
'x-ratelimit-remaining-minute': '2971',
'x-xss-protection': '1; mode=block, 1; mode=block',
'x-frame-options': 'SAMEORIGIN, SAMEORIGIN',
'strict-transport-security': 'max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains',
'x-frame-option': 'DENY, DENY',
'x-kong-upstream-latency': '191',
'x-kong-proxy-latency': '0',
via: 'kong/0.14.1'
},
body: { resultSetMetadata: [Object], results: [Array] }
},
{
status: 422,
statusText: 'Unprocessable Entity',
headers: {
server: 'nginx',
date: 'Thu, 27 Aug 2020 21:04:34 GMT',
'content-type': 'application/json;charset=UTF-8',
'transfer-encoding': 'chunked',
connection: 'close',
'x-ratelimit-limit-minute': '3000',
'x-ratelimit-remaining-minute': '2977',
'x-xss-protection': '1; mode=block, 1; mode=block',
'x-frame-options': 'SAMEORIGIN, SAMEORIGIN',
'strict-transport-security': 'max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains',
'x-frame-option': 'DENY, DENY',
'x-kong-upstream-latency': '127',
'x-kong-proxy-latency': '0',
via: 'kong/0.14.1'
},
body: {
status: 422,
developerMessage: 'Result set is already closed.',
clientMessage: ''
}
},
{
status: 500,
statusText: 'Internal Server Error',
headers: {
server: 'nginx',
date: 'Thu, 27 Aug 2020 21:04:34 GMT',
'content-type': 'application/json;charset=UTF-8',
'transfer-encoding': 'chunked',
connection: 'close',
'x-ratelimit-limit-minute': '3000',
'x-ratelimit-remaining-minute': '2978',
'x-xss-protection': '1; mode=block, 1; mode=block',
'x-frame-options': 'SAMEORIGIN, SAMEORIGIN',
'strict-transport-security': 'max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains',
'x-frame-option': 'DENY, DENY',
'x-kong-upstream-latency': '130',
'x-kong-proxy-latency': '1',
via: 'kong/0.14.1'
},
body: { status: 500, developerMessage: null, clientMessage: null }
},
{
status: 422,
statusText: 'Unprocessable Entity',
headers: {
server: 'nginx',
date: 'Thu, 27 Aug 2020 21:04:34 GMT',
'content-type': 'application/json;charset=UTF-8',
'transfer-encoding': 'chunked',
connection: 'close',
'x-ratelimit-limit-minute': '3000',
'x-ratelimit-remaining-minute': '2976',
'x-xss-protection': '1; mode=block, 1; mode=block',
'x-frame-options': 'SAMEORIGIN, SAMEORIGIN',
'strict-transport-security': 'max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains',
'x-frame-option': 'DENY, DENY',
'x-kong-upstream-latency': '102',
'x-kong-proxy-latency': '1',
via: 'kong/0.14.1'
},
body: {
status: 422,
developerMessage: 'Connection handle has been closed and is unusable',
clientMessage: ''
}
},
{
status: 422,
statusText: 'Unprocessable Entity',
headers: {
server: 'nginx',
date: 'Thu, 27 Aug 2020 21:04:34 GMT',
'content-type': 'application/json;charset=UTF-8',
'transfer-encoding': 'chunked',
connection: 'close',
'x-ratelimit-limit-minute': '3000',
'x-ratelimit-remaining-minute': '2975',
'x-xss-protection': '1; mode=block, 1; mode=block',
'x-frame-options': 'SAMEORIGIN, SAMEORIGIN',
'strict-transport-security': 'max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains, max-age=31536000; includeSubDomains',
'x-frame-option': 'DENY, DENY',
'x-kong-upstream-latency': '74',
'x-kong-proxy-latency': '0',
via: 'kong/0.14.1'
},
body: {
status: 422,
developerMessage: 'Connection handle has been closed and is unusable',
clientMessage: ''
}
}
]
```
### Solução
Existem dois problemas a serem resolvidos:
- **1 -** Pensar e Implementar filtros por texto nas APIs:
- Municípios: GET /cities
- Profissões: GET /professions
- Estados Civis: GET /civil-status
Dado que os cadastros do Sienge são abertos e editavéis, uma busca textal usando a ideia de "LIKE" seria mais apropriada, afim de produzir resultados quando a palavra consta no texto ou não. Seria interessante também produzir resultados quando a palavra tem acentuação e foi pesquisada sem, por exemplo: "Joacaba" e "Joaçaba", "Florianópolis" e "Florianopolis", "Cacador", "Caçador". Outro ponto seria ser case-insensitive.
- **2 -** Escalar o problema de concorrência, conforme exemplos acima com o Team Rocket, afim de mitigar falhas deste tipo.