# RestLib2

O RestLib2 é uma plataforma que tem por objetivo o fornecimento de APIs para os clientes, a partir da descrição da entidades envolvidas, e sem a necessidade de programação imperativa tradicional.

Em resumo, a partir da declaração em JSON das entidades que compõe um negócio, bem como dos relacionamentos entre estas, as APIs já estarão disponíveis em produção.

O objetivo final é permitir que o desenvolvimento de APIs se torne rápido e simples, acessível àqueles que tratam diretamente com o negócio (incluindo implantadores, e, no limite, o próprio cliente).

## Links

[Guia do EDL](docs/README.md)
[ESPECIFICAÇÃO DO MODELO DE ENTIDADES](docs/especificacao.md)

## Rota das APIs geradas

A rota para acesso a uma API gerada por variar de acordo com o modo de configuração escolhido pela aplicação que usar o RestLib2. Mas, via de regra, sugere-se o padrão aplicado na API de DadosMestre:

```http
#############################
# List Prod
#############################
GET https://api.nasajon.app/dados-mestre/edl1/clientes?tenant=47&grupo_empresarial=NASAJON HTTP/1.1
Authorization: Bearer *****
Accept: application/json
```

* Note que, na API de Dados Mestre, todas as APIs do RestLib2 ficarão debaixo da rota: ```https://api.nasajon.app/dados-mestre/edl1/```
* O endpoint em si, varia a cada JSON, e fica configurado no nó ```api.resource``` do JSON de EDL em questão.

## Fluxo básico de uso

Há dois modos básicos de publicar novas APIs a partir de um JSON gerado, para uma aplicação previamente configurada para uso da plataforma:

### Fluxo por meio de código versionado
1. Criar o JSON de descrição da entidade desejada, gravando-o no diretório "@schemas/entities" da aplicação em questão (tome [como exemplo o "dados-mestre"](https://github.com/Nasajon/dados-mestre-api/tree/production/%40schemas)).
2. Fazer push das alterações.
3. Aguardar o build da aplicação (pode ser útil conferir os logs do job de atualização dos JSON, na aplicação em questão, e também os logs do [worker de compilação](https://ci.nasajon.in/applications/restlib2?view=pods&conditions=false), no Argo).
4. Testar as APIs compiladas.
   
### Fluxo de deploy direto pela API
1. Criar o JSON de descrição da entidade desejada.
2. Registrá-lo diretamente, por meio da API de controle do RestLib2. segue exemplo de chamada abaixo:

```http
###############################
# Post dinâmico
###############################
POST https://api.nasajon.app/restlib2/entities HTTP/1.1
Authorization: Bearer ******
Content-Type: application/json

{
  "id": "{UUID}",
  "escopo": "{escopo}",
  "tenant": 0,
  "grupo_empresarial": "00000000-0000-0000-0000-000000000000",
  "codigo": "{codigo da entidade}",
  "descricao": "{descrição da entidade}",
  "json_schema": {
    "edl_version": "1.0",
    "escopo": "{escopo}",
    "description": "{descrição da entidade}",
    "id": "cliente",
    "version": "0.0.1",
    ...
  }
}
```

Observações:
* Note que, acima há placeholders a alterar.
* Note também que o JSON não está completo, e, o correto é deguir a documentação do EDL.
* Os valores tenant=0 e grupo_empresarial=00000000-0000-0000-0000-000000000000, indicam que a entidade é padrão, e serve para todos os tenants e grupos.

3. Essa rota irá retornar algo semelhante a:

```http
HTTP/1.1 202 ACCEPTED
Location: https://api.nasajon.app/restlib2/entity-compilations/status/{UUID do processo de compilação}
```

E, se você fizer uma chamada à rota retornada, poderá acompanhar o status da compilação, incluindo eventuais erros que venham a ocorrer.

4. Testar a API compilada.

## Como rodar a compilação de EDLs localmente?

Você pode testar a compilação de seus EDLs localmente, incluindo a execução de diversas validações sobre os mesmos, desde que todos estejam dispostos num mesmo diertório.

Para isso, considere os passos a seguir:

1. Crie um diretório, e coloque todos os seus EDLs lá (garantindo que EDLs relacionados estejam no mesmo).
2. Instale, no seu ambiente pyhton de teste, a biblioteca `nsj-rest-lib2`:
   
```sh
pip install nsj-rest-lib2
```

3. Rode o comando abaixo (adaptado para seu diretório):
```sh
python3 -m nsj_rest_lib2.compiler.compiler -d $(shell pwd)/{diretorio_com_os_edls_json}
```

O resultado da compilação será impresso no console (erros, ou código total gerado).

## Como configurar uma aplicação para expôr rotas de acordo com o padrão do RestLib2?

Para que uma aplicação exponha as rotas no padrão do RestLib2, não são necessários muitos passos. Antes basta:

1. Instalar, em sua aplicação, a dependência para o projeto nsj-rest-lib2

```sh
pip install nsj-rest-lib2
```

Não esqueça de fixar a versão usada (como sendo a última), no arquivo requirements.txt.

2. Adicione a variável de ambiente abaixo em sua aplciação

```env
ESCOPO_RESTLIB2: "{COLOQUE O IDENTIFICADOR DE ESCOPO QUE DESEJAR PARA SUA APLICAÇÃO (UMA SIMPLES STRING SEM ESPAÇO)}"
```

* Esse identificador de escopo deve se único para sua aplicação.
* É importante nota que sua aplicação só irá expôr JSONs de EDL configurados para o mesmo escopo definido aqui.

3. Instale, como dependência a biblioteca, nsj-rest-lib2:

```sh
pip install nsj-rest-lib2
```

Não esqueça de fixar a versão usada (como sendo a última), no arquivo requirements.txt.

4. Adicione a linha abaixo no arquivo wsgi.py (de inicilização de sua aplicação):

```python
from nsj_rest_lib2.controller.dynamic_controller import setup_dynamic_routes
from nasajon.injector_factory_multibanco import InjectorFactoryMultibanco

setup_dynamic_routes(application, injector_factory=InjectorFactoryMultibanco)
```

* No exemplo acima, a rota é multibanco, mas, não é obrigatório.
* Os parâmetros de setup são:
  * flask_app: Variável obrigatório, que aponte para sua aplicação Flask.
  * multidb: Flag (padrão True)
  * dynamic_root_path: URL padrão base de todos os endpoints do RestLib2 (padrão: "edl1")
  * injector_factory: Classe de injeção de depndência usada (normalmente necessária para aplicações multibanco; o principal uso é justamente manipular a criação da conexão com o BD).

## Carregando EDLs direto do disco

Também é possível carregar EDLs diretamente do disco, sem depender exclusivamente do Redis. Para isso, use o parâmetro opcional `edls_path` em `setup_dynamic_routes`, apontando para um caminho relativo ao workdir da aplicação (ou absoluto), contendo arquivos `.json`, `.yml` ou `.yaml` com os EDLs.

Exemplo:

```python
from nsj_rest_lib2.controller.dynamic_controller import setup_dynamic_routes

setup_dynamic_routes(
    application,
    injector_factory=InjectorFactoryMultibanco,
    edls_path="@schemas/entities",
)
```

Observações:
* Os EDLs são carregados e compilados uma vez, ficando em cache em memória. Chamadas seguintes reutilizam o cache.
* A resolução das entidades ocorre primeiro pelo cache local; se não encontrar, o Redis é consultado (quando habilitado).

Para desabilitar o Redis e usar somente EDLs do disco, defina a variável de ambiente abaixo:

```env
EDLS_FROM_REDIS=false
```

O valor padrão de `EDLS_FROM_REDIS` é `true`.


**Pronto, isso deve bastar para expôr os EDLs configurados para o mesmo escopo da aplicação.**

**OBSERVAÇÃO GERAL: Isso só funciona para aplicações Flask.**
