@rcambiental/external-api
v0.0.8
Published
API de integração com o banco de dados legislativo do Portal RC Ambiental.
Downloads
130
Readme
RC Ambiental External Api
Api de integração com o banco de dados do Portal RC Ambiental.
Instalação
# Npm
npm install @rcambiental/external-api
# Yarn
yarn add @rcambiental/external-api
# PNPM
pnpm add @rcambiental/external-api
Package namespaces
@rcambiental/external-api
: Atualmente não exporta nada.@rcambiental/external-api/client
: Para uso com integrações no browser (frontend).@rcambiental/external-api/server
: Para uso com integrações no servidor (backend).@rcambiental/external-api/internal
: Uso interno da biblioteca, não deve ser utilizada diretamente.
Instanciamento do cliente server-side
import { buildRCAmbientalExternalApiServerClient } from '@rcambiental/external-api/server';
const client = buildRCAmbientalExternalApiServerClient({
apiEndpoint: 'https://www.rcambiental.com.br',
apiKey: '123-123-123-123'
});
Pingando o servidor
Utilize o resultado da operação de client.common.ping()
para saber se o servidor está online e a apiKey
informada é válida.
Obtenção dos dados de base
O cliente de servidor fornece 4 endpoints básicos para a integração com o banco de dados do Portal RC Ambiental. Estes dados são utilizados, basicamente, para construir a interface do sistema de pesquisa, embora possam também ter outros usos.
São eles:
const getAllActsAreas = await client.acts.baseData.getAllActAreas();
// ^ Retornas todas as áreas dos atos jurídicos
const getAllActOrgans = await client.acts.baseData.getAllActOrgans();
// ^ Retornas todos os órgos dos atos jurídicos
const getAllActTypes = await client.acts.baseData.getAllActTypes();
// ^ Retornas todos os tipos dos atos jurídicos
const getAllJurisdictionScopes = await client.acts.baseData.getAllJurisdictionScopes();
// ^ Retornas todos os escopos de jurisdição dos atos jurídicos (Brasil e seus Estados)
Obtenção dados dos usuários cadastrados
É possivel utilizar-se de 02 endpoints que buscam dados dos usuários. São eles:
/**
* Retorna todos os usuários cadastrados no sistema, em ordem decrescente de data de criação.
* Por questões de performance, os dados não incluem o plano atual do usuário, somente seus dados cadastrais e
* seu status de ativação.
*
* A chamada da função aceita 2 parâmetros opcionais no query:
* - `page` - Número da página, se não informado ou <= 1, o valor default é 1.
* - `maxPerPage` - Número de registros por página, se não informado ou <= 0, o valor default é 20.
* ^ Neste caso, existe um hard limit no servidor de até 20 registros por página, valores informados
* acima de 20 serão ignorados.
*/
const getAllUsers = await client.users.getAllUsers({
query: {
page: 1,
maxPerPage: 20
}
});
/**
* Retorna os mesmos dados cadastrais do usuário mas, neste caso, inclui também o
* plano atual do usuário no corpo da resposta (ou null, caso não houver).
*
* A chamada da função necessita, obrigatoriamente, dos seguintes parâmetros na query:
* - `userId` - Id do usuario cadastrado no sistema.
*
* A chamada da função pode retornar um erro 404 caso o usuário não seja encontrado.
*/
const getUser = await client.users.getUser({
query: {
userId: '123-123-123'
}
});
Pesquisa dos Atos Jurídicos
Através desse endpoint, é possível realizar pesquisas nos atos jurídicos cadastrados no sistema.
Existem, basicamente, dois tipos de pesquisa, as com texto e as sem texto (que internamente chamos de genéricas).
- Pesquisa com texto: Seus resultados são ordenados por relevância, dando ênfase sempre para os atos jurídicos mais recentes que foram inseridos no banco de dados.
- Pesquisa sem texto: Seus resultados são ordenados pela data do ato jurídico, ordenando-os sempre dos mais recentes para o mais antigos.
Todas as pesquisas precisam ser autenticadas pelo usuário que as realizar, para isso, é necessário informar o header do
x-ea-user-id
no corpo da requisição.
Além disso, os parâmetros de filtragem utilizados são aqueles obtidos pelos dados de base, como especificado anteriormente nesta documentação.
/**
* Exemplo 1: Pesquisa com texto.
*
* Os resultados são ordenados por relevância, dando ênfase sempre para os atos jurídicos
* mais recentes que foram inseridos no banco de dados.
*
* O tipo de retorno da pesquisa é `SCORED`, ou seja, cada ato retornado possui um `score` de
* relevância, sendo que no próprio corpo da resposta será informado um `maxScore`. Isso é
* util para calcular percentagem de relevância do ato e apresentar ao cliente na UI.
*
* Importante: O campo `text` é totalmente case-insensitive e accent-insensitive,
* ou seja, "ÁGUA" === "agua".
*/
const searchResultWithText = await client.acts.search({
headers: {
/**
* Este header informa qual usuário está realizando a pesquisa.
*/
'x-ea-user-id': '123-123-123-123'
},
body: {
/**
* Especifica que o tipo de pesquisa é "com texto"
*/
type: 'with-text',
/**
* Palavras-chave a serem pesquisadas, é basicamente o input do usuário.
* Aceita, também, expressões com áspas duplas (como no Google), por exemplo: "água potável"
*/
text: 'água', // ou '\"água potável\"'
/**
* Filtragem da pesquisa, alguns filtros são obrigatórios.
*/
filters: {
/**
* Filtra pela situação do ato jurídico.
* - REVOKED: Somente atos jurídicos revogados
* - IN_EFFECT: Somente atos jurídicos não-revogados
* - BOTH: Ambos os tipos (é o mesmo que desabilitar esse filtro)
*/
actSituation: 'BOTH',
/**
* Filtra pelos números dos atos jurídicos.
*/
actNumbers: [1, 2, 3],
/**
* Áreas de atuação do ato jurídico, pelo menos 01 área tem que ser especificada.
*/
actAreaIds: [
// Ids das áreas, obter através de `client.acts.baseData.getAllActAreas()`
'123-123-123-123'
],
/**
* Filtra pelo órgão do ato jurídico.
* Id órgão, obter através de `client.acts.baseData.getAllActOrgans()`
*/
actOrganId: '123-123-123-123',
/**
* Filtra pelo tipo do ato jurídico.
* Id do tipo, obter através de `client.acts.baseData.getAllActTypes()`
* Obs: Esse filtro é `exclusivo`, ou seja, AND.
*/
actTypeId: '123-123-123-123',
/**
* Filtra pela data de publicação dos atos jurídicos.
* O tipo de `value` depende do `type`, é type-safe, use type-narrowing.
*/
actPublicationDate: {
type: 'exact', // ou 'range' ou 'separated'
value: new Date('2021-01-01')
},
/**
* Filtra pela data dos atos jurídicos.
* O tipo de `value` depende do `type`, é type-safe, use type-narrowing
*/
actDate: {
type: 'range', // ou 'exact' ou 'separated'
value: {
gte: new Date('2021-01-01'),
lte: new Date('2021-12-31')
}
},
/**
* Indica em quais módulos se deseja buscar os atos jurídicos, pelo menos 01 field é obrigatório.
*/
actLocalization: {
/**
* Indica que deve ser incluído a Legislação Federal.
* Se não informado, o valor default é `false`.
*/
includeFederal: true,
/**
* Indica que deve ser incluído as legislações estaduais.
* Se não informado, o valor default é `[]`, ou seja, nenhum Estado.
*/
includeStateIds: [
// Id do Estado, obter através de `client.acts.baseData.getAllJurisdictionScopes()`
'123-123-123-123'
]
}
},
/**
* Filtro de paginação.
*/
paging: {
// Página atual, se não informado ou <= 1, o valor default é 1.
page: 1,
}
}
});
/**
* Exemplo 2: Pesquisa sem texto (genérica).
* Os resultados serão servidos em ordem decrescente de data de inserção, do mais recente para o mais antigo.
* O tipo de retorno da pesquisa é `NON_SCORED`.
*/
const searchResultNonText = await client.acts.search({
headers: {
'x-ea-user-id': '123-123-123-123'
},
body: {
/**
* Especifica que o tipo de pesquisa é "sem texto"
*/
type: 'without-text',
filters: {
actSituation: 'REVOKED',
actAreaIds: [
'123-123-123-123'
],
/**
* Exemplo com type `separated`.
*/
actDate: {
type: 'separated',
/**
* Pelo menos 1 campo tem que ser informado:
* - `day` - dia do mês
* - `month` - mês do ano (1-12)
* - `year` - ano
*/
value: {
day: 1,
month: 1
}
},
actLocalization: {
includeFederal: true,
includeStateIds: [
'123-123-123-123'
]
}
},
paging: {
page: 1,
}
}
});
Requisitando os metadados de um Ato Jurídico
Os metadados de um ato jurídico específico podem ser requisitados sem gerar, necessariamente, um acesso. Este endpoint é útil para situações onde, por exemplo:
- Se deseje atualizar seus dados caso alguma atualização/alteração tenha sido realizada.
- Verificar se o ato jurídico existe ou não no banco de dados (em casos de exclusão ou não encontrado, será retornado status 404).
- Entre outros.
Utilize o endpoint client.acts.getActMetadata()
para requisitar os metadados de um ato jurídico, exemplo:
/**
* Obs: É necessário informar o usuário que está requisitando
* os metadados do ato jurídico.
*/
const actMetadata = await client.acts.getActMetadata({
query: {
actId: '123-123-123-123'
},
headers: {
'x-ea-user-id': '123-123-123-123'
}
});
Realizando um acesso a um Ato Jurídico
O acesso a um ato jurídico é feito de forma encadeada, ou seja, é necessário realizar, sequencialmente, algumas operações:
Primeiramente, é necessário obter o
id
do ato jurídico ao qual se deseja acessar, isso é feito, por exemplo, utilizando-se do resultado do endpoint de pesquisa (client.acts.search()
).Com o
id
do ato jurídico em mãos, é necessário gerar um id de acesso, isto é possível através do endpointclient.acts.generateActAccess()
, exemplo:
/**
* Obs: É necessário informar o usuário que está requisitando
* o acesso do ato jurídico.
*/
const actAccess = await client.acts.generateActAccess({
query: {
actId: '123-321-123-321'
},
headers: {
'x-ea-user-id': '123-123-123-123'
}
});
O retorno da chamada do endpoint acima devolve uma resposta com uma estrutura semelhante a esta:
{
/**
* Id único, por recorrência de um plano de um usuário, que identifica o acesso
* a um ato jurídico.
* Este id é utilizado para:
* 1. Requisição da decriptação do texto legislativo do ato jurídico (caso
* ele esteja em estado `ENCRYPTED`).
*/
"actAccessId": "12346-abcde",
/**
* Token de acesso instantâneo de acesso ao ato (atrelado ao `actAccessId`).
* Este id é utilizado para:
* 1. Realizar a validação do acesso por parte do
* usuário (no browser), através da ferramenta do FingerprintJS.
* 2. Realizar a requisição do texto legislativo (só pode ser utilizado uma
* única vez e possui data de expiração).
*/
"actAccessEntryId": "12346-abcde-123456",
/**
* Data de expiração do token de acesso para busca do texto do ato jurídico (actAccessEntryId).
*/
"actAccessEntryValidUntil": "2021-12-31T23:59:59.999Z",
"text": {
/**
* Indica o status da encryptação do texto do
* ato jurídico.
*/
"encryptionStatus": {
/**
* Importante: Todo primeiro acesso a um ato jurídico, numa recorrência, começa
* como `ENCRYPTED`.
*/
"value": "ENCRYPTED",
/**
* Indica se o usuário pode requisitar a decriptação do
* ato jurídico. Este valor leva em consideração a quantidade
* de requisições de decriptação restantes e se o usuário
* possui o módulo que contempla a acesso a este ato (incluindo
* o status do plano atual).
*/
"canRequestDecryption": true
},
/**
* Número restante de requisições de descriptografia de
* texto na recorrência atual do plano do usuário.
*/
"remainingDecryptionRequests": 30,
/**
* Número máximo de requisições de descriptografia de
* texto na recorrência atual do plano do usuário.
*/
"maxDecryptionRequests": 30
},
// Metadados do Ato Jurídico
"act": {}
}
- Agora, com o acesso gerado e com o
actAccessId
em mãos, é possível requisitar o texto do ato jurídico, exemplo:
/**
* O retorno da função abaixo devolve um objeto com 2 valores distintos de `status`:
*
* 1. `ENCRYPTED` - Indica que o texto do ato jurídico está criptografado.
* 2. `NOT_ENCRYPTED` - Indica que o código fonte do ato jurídico está em forma decriptada.
*
* O texto (html) do ato jurídico será retornado no field `html`, sendo que algumas
* considerações são importantes:
*
* - Recomenda-se o uso da fonte 'Arial' para o tipo de `status`:`NOT_ENCRYPTED` pois a
* encriptação do html utiliza, exclusiva e unicamente esta fonte, isto mantém a consistência no
* display pro usuário caso uma request para decriptação seja feita e o ato seja recarregado.
* Tentar forçar o uso de outa fontFamily no container onde o texto do ato jurídico que está encriptado
* foi injetado irá quebrar o display da encriptação e os caracteres serão exibidos de forma incorreta.
*
* - Em quaisquer dos casos do field `status`, recomenda-se a injeção direta do HTML
* num container, por exemplo, uma `div`, usando `div.innerHTML = actText.html`;
*
* Obs: É necessário informar o usuário que está requisitando
* o texto do ato jurídico.
*/
const actText = await client.acts.getActText({
query: {
/**
* Este token só poderá ser utilizado uma única vez e
* é de uso exclusivo para cada usuário que requisitou o acesso
* ao ato jurídico (e seu texto).
*/
actAccessEntryId: '123-123-123-123'
},
body: {
/**
* Configuração dos links dos anexos no texto do ato jurídico.
*/
attachmentLinks?: {
/**
* - `NEW_TAB` - Abre o link em uma nova aba (target="_blank").
* - `SAME_TAB` - Abre o link na mesma aba (target="_self").
*/
clickBehavior?: 'NEW_TAB' // ou 'SAME_TAB'
},
/**
* Configuração dos links para outros atos jurídicos
* no texto do ato jurídico atual.
*/
actLinks: {
/**
* - `NEW_TAB` - Abre o link em uma nova aba (target="_blank").
* - `SAME_TAB` - Abre o link na mesma aba (target="_self").
*/
clickBehavior?: 'NEW_TAB', // ou 'SAME_TAB'
/**
* Configura como os links para outros atos jurídicos
* serão parseados.
*/
parsing: {
/**
* Neste método de parsing os links são
* renderizados da seguinte forma:
*
* `<a href="actId://123-123/" data-link-to-act-id="123-123">Link para um ato</a>`
*
* O field `data-link-to-act-id` possui o id do ato jurídico alvo, desta forma
* você, desenvolvedor, fica responsável por
* parsear o texto do ato jurídico, buscar esses links como e transformá-los ou
* aplicar event handlers (click) da forma que achar mais conveniente, exemplo: *
* ```js
* const allActLinks = actTextContainer.querySelectorAll('a[data-link-to-act-id]');
*
* allActLinks.forEach((link) => {
* link.addEventListener('click', (e) => {
* e.preventDefault();
* const actId = link.getAttribute('data-link-to-act-id');
* // Agora você pode fazer o que quiser com o id do ato jurídico
* });
* });
* ```
*/
method: 'ACT_ID_INLINE_WITH_DATA_ATTR'
}
/**
* Outra configuração de parsing também é possível, veja:
*/
parsing: {
/**
* Indica que os links serão renderizados com uma url fixa,
* especificada no momento da requisição.
*/
method: 'TO_FIXED_URL',
/**
* Indica o placeholder que será substituído pela id do ato jurídico
* na montagem da url (href).
*/
placeholder?: '{{ actId }}',
/**
* Agora é só informar a URL que deve ser montada, incluindo,
* obrigatoriamente, o placeholder especificado acima (default é '{{ actId }}'),
* caso não especificado.
*/
url: `https://www.example.com/some-path/?actId={{ actId }}`
// ^ <a href="https://www.example.com/some-path/?actId=123-123">Link para um ato</a>
}
}
},
headers: {
'x-ea-user-id': '123-123-123-123'
}
});
A chamada a função acima pode retornar os seguintes erros:
- Http 404 - Caso o
actAccessEntryId
informado não seja encontrado. - Http 403 - Nos casos:
- O
actAccessEntryId
informado não pertença ao usuário informado no headerx-ea-user-id
. - O
actAccessEntryId
informado já tenha sido utilizado. - O
actAccessEntryId
informado esteja expirado, neste caso, é necessário gerar um novoactAccessEntryId
através do endpointclient.acts.generateActAccess()
.
- O
Em todos os casos acima, uma mensagem descritiva do erro será retornada no corpo da resposta.
Requisitando a decriptação do texto de um Ato Jurídico
A decriptação do texto de um ato jurídico é o que permite o usuário a realizar cópias do conteúdo do mesmo. Toda vez que o usuário quiser realizar uma cópia, seja por seleção de texto (entre outros), é necessário chamar pelo endpoint responsável por requisitar a decriptação do texto.
Uma vez que a decriptação do texto seja aceita pelo sistema, novas requisições pelo texto do ato jurídico serão automaticamente retornadas com o conteúdo (html) do texto de forma decriptada e assim se manterão até o final da recorrência atual do plano do usuário.
Com o actAccessId
em mãos, realize a seguinte chamada ao endpoint client.acts.requestActTextDecryption()
, exemplo:
/**
* O resultado desta função retorna um objeto com um field `result`
* que indica o resultado a operação.
*
* Caso o valor de `result` seja `ACCEPTED`, significa que a requisição foi aceita,
* neste caso, para obter o texto decriptado, é necessário gerar um novo `actAccessEntryId`
* através do endpoint `client.acts.generateActAccess()` e logo depois realizar, novamente, a requisição
* do texto do ato jurídico com o novo `actAccessEntryId` com o endpoint `client.acts.getActText()`.
*
* Obs: É necessário informar o usuário que está
* requisitando esta decriptação de texto.
*/
const requestActTextDecryption = await client.acts.requestActTextDecryption({
query: {
actAccessId: '123-123-123-123'
},
headers: {
'x-ea-user-id': '123-123-123-123'
}
});
Após a chamada acima, considerando o retorno como ACCEPTED
, uma nova chamada
a client.acts.generateActAccess()
com o mesmo actAccessId
retornará um objeto
com o status de DECRYPTED
no field text.encryptionStatus.value
, exemplo:
{
...omitido
/**
* Um novo valor para esse field será gerado, o qual deve ser
* utilizado para requisitar a versão do texto do ato jurídico
* em forma decriptada.
* Lembrando que toda chamada a `client.acts.generateActAccess()`
* deve ser validada com o FingerprintJS utilizando-se desse token.
*/
"actAccessEntryId": "123456-new-value",
"text": {
"encryptionStatus": {
"value": "DECRYPTED",
"decryptedAt": "2024-02-22T14:38:02.309Z"
},
"remainingDecryptionRequests": 29,
"maxDecryptionRequests": 30
}
...omitido
}
Observações
1. Requisições que envolvem o userId (que identifica o usuário)
Todas as requisições que envolvem o usuário podem retornar os seguintes erros na requisição:
EXTAPI_USER_NOT_FOUND_OR_INVALID
- OuserId
informado é inválido ou o usuário não existe (não foi encontrado).EXTAPI_USER_DEACTIVATED
- O usuário informado está desativado, que pode ser causado pelo contratante ou pela própria administração do Portal RC Ambiental.EXTAPI_USER_HAS_NO_PLAN_CONFIGURED_OR_STARTED
- Indica que o usuário não possui um plano configurado ou iniciado, é necessário que o mesmo possua pelo menos um plano configurado e iniciado para começar a usar o sistema.EXTAPI_USER_CURRENT_PLAN_IS_PAUSED
- Indica que o plano do usuário está pausado, isso é causado, exclusivamente, por uma medida administrativa por parte do Portal RC Ambiental.
2. Tratamento de erros
Essa bibliotca exporta funções utilitárias para identificação de erros nas chamadas de API, são eles:
/**
* Contém todos os códigos de erros específicos que podem ocorrer na API,
* ao inspecionar o código fonte desse tipo, é explicado o motivo de cada erro.
*/
import { RCAmbientalExternalApiErrorCode } from '@rcambiental/external-api/server';
/**
* Função do tipo "type-guard" que testa se o objeto do erro retornado é
* do tipo `RCAmbientalExternalApiError`.
*/
import { isRCAmbientalExternalApiServerError } from '@rcambiental/external-api/server';
/**
* Exemplo: imagine que você fez uma chamada de api usando o client e ele retornou um erro e
* o erro retornado é similar ao abaixo:
*/
import { isRCAmbientalExternalApiServerError, RCAmbientalExternalApiError } from '@rcambiental/external-api/server';
const errorFromApi: RCAmbientalExternalApiError = {
type: 'rcambiental-api-error',
statusCode: 404,
code: 'EXT_API_RESOURCE_ID_INVALID',
message: 'Uma mensagem de erro será retornada pelo sistema aqui.'
};
if (isRCAmbientalExternalApiServerError(errorFromApi)) {
// O erro retornado é um erro específico
} else {
// O erro retornado não é um erro especifico
}