nsj-rest-lib2 0.0.36__tar.gz → 0.0.37__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. nsj_rest_lib2-0.0.37/PKG-INFO +203 -0
  2. nsj_rest_lib2-0.0.37/README.md +182 -0
  3. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/util/type_naming_util.py +64 -1
  4. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/controller/dynamic_controller.py +3 -1
  5. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/service/entity_config_writer.py +7 -56
  6. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/service/entity_loader.py +256 -106
  7. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/settings.py +10 -0
  8. nsj_rest_lib2-0.0.37/nsj_rest_lib2.egg-info/PKG-INFO +203 -0
  9. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/setup.cfg +1 -1
  10. nsj_rest_lib2-0.0.36/PKG-INFO +0 -27
  11. nsj_rest_lib2-0.0.36/README.md +0 -6
  12. nsj_rest_lib2-0.0.36/nsj_rest_lib2.egg-info/PKG-INFO +0 -27
  13. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/__init__.py +0 -0
  14. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/__init__.py +0 -0
  15. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/compiler.py +0 -0
  16. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/compiler_structures.py +0 -0
  17. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/dto_compiler.py +0 -0
  18. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/edl_model/__init__.py +0 -0
  19. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/edl_model/ai_entity_edl.py +0 -0
  20. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/edl_model/api_model.py +0 -0
  21. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/edl_model/column_meta_model.py +0 -0
  22. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/edl_model/entity_model.py +0 -0
  23. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/edl_model/entity_model_base.py +0 -0
  24. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/edl_model/entity_model_root.py +0 -0
  25. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/edl_model/index_model.py +0 -0
  26. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/edl_model/primitives.py +0 -0
  27. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/edl_model/property_meta_model.py +0 -0
  28. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/edl_model/repository_model.py +0 -0
  29. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/edl_model/trait_property_meta_model.py +0 -0
  30. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/entity_compiler.py +0 -0
  31. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/function_get_delete_compiler.py +0 -0
  32. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/function_insert_update_compiler.py +0 -0
  33. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/function_model.py +0 -0
  34. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/migration_compiler.py +0 -0
  35. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/migration_compiler_alter_table.py +0 -0
  36. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/migration_compiler_create_table.py +0 -0
  37. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/migration_compiler_util.py +0 -0
  38. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/model.py +0 -0
  39. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/property_compiler.py +0 -0
  40. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/response_dto_compiler.py +0 -0
  41. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/util/__init__.py +0 -0
  42. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/util/relation_ref.py +0 -0
  43. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/util/str_util.py +0 -0
  44. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/compiler/util/type_util.py +0 -0
  45. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/controller/__init__.py +0 -0
  46. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/dto/__init__.py +0 -0
  47. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/dto/escopo_dto.py +0 -0
  48. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/entity/__init__.py +0 -0
  49. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/entity/escopo_entity.py +0 -0
  50. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/exception.py +0 -0
  51. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/redis_config.py +0 -0
  52. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2/service/__init__.py +0 -0
  53. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2.egg-info/SOURCES.txt +0 -0
  54. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2.egg-info/dependency_links.txt +0 -0
  55. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2.egg-info/requires.txt +0 -0
  56. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/nsj_rest_lib2.egg-info/top_level.txt +0 -0
  57. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/pyproject.toml +0 -0
  58. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/tests/test_function_handler_compilation.py +0 -0
  59. {nsj_rest_lib2-0.0.36 → nsj_rest_lib2-0.0.37}/tests/test_migration_generation.py +0 -0
@@ -0,0 +1,203 @@
1
+ Metadata-Version: 2.4
2
+ Name: nsj_rest_lib2
3
+ Version: 0.0.37
4
+ Summary: Biblioteca para permitir a distribuição de rotas dinâmicas numa API, configuradas por meio de EDLs declarativos (em formato JSON).
5
+ Home-page: https://github.com/Nasajon/nsj_rest_lib2
6
+ Author: Nasajon Sistemas
7
+ Author-email: contact.dev@nasajon.com.br
8
+ Project-URL: Source, https://github.com/Nasajon/nsj_rest_lib2
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Topic :: Software Development :: Libraries
12
+ Classifier: Programming Language :: Python :: 3
13
+ Requires-Python: >=3.4
14
+ Description-Content-Type: text/markdown
15
+ Requires-Dist: nsj-rest-lib<7.0.0,>=5.1.3
16
+ Requires-Dist: redis<7.0.0,>=6.4.0
17
+ Requires-Dist: nsj-multi-database-lib<3.0.0,>=2.0.1
18
+ Requires-Dist: pydantic<3.0.0,>=2.11.9
19
+ Requires-Dist: black<26.0.0,>=25.1.0
20
+ Requires-Dist: pyyaml<7.0.0,>=6.0.3
21
+
22
+ # RestLib2
23
+
24
+ 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.
25
+
26
+ 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.
27
+
28
+ 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).
29
+
30
+ ## Links
31
+
32
+ [Guia do EDL](docs/README.md)
33
+ [ESPECIFICAÇÃO DO MODELO DE ENTIDADES](docs/especificacao.md)
34
+
35
+ ## Rota das APIs geradas
36
+
37
+ 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:
38
+
39
+ ```http
40
+ #############################
41
+ # List Prod
42
+ #############################
43
+ GET https://api.nasajon.app/dados-mestre/edl1/clientes?tenant=47&grupo_empresarial=NASAJON HTTP/1.1
44
+ Authorization: Bearer *****
45
+ Accept: application/json
46
+ ```
47
+
48
+ * Note que, na API de Dados Mestre, todas as APIs do RestLib2 ficarão debaixo da rota: ```https://api.nasajon.app/dados-mestre/edl1/```
49
+ * O endpoint em si, varia a cada JSON, e fica configurado no nó ```api.resource``` do JSON de EDL em questão.
50
+
51
+ ## Fluxo básico de uso
52
+
53
+ 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:
54
+
55
+ ### Fluxo por meio de código versionado
56
+ 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)).
57
+ 2. Fazer push das alterações.
58
+ 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).
59
+ 4. Testar as APIs compiladas.
60
+
61
+ ### Fluxo de deploy direto pela API
62
+ 1. Criar o JSON de descrição da entidade desejada.
63
+ 2. Registrá-lo diretamente, por meio da API de controle do RestLib2. segue exemplo de chamada abaixo:
64
+
65
+ ```http
66
+ ###############################
67
+ # Post dinâmico
68
+ ###############################
69
+ POST https://api.nasajon.app/restlib2/entities HTTP/1.1
70
+ Authorization: Bearer ******
71
+ Content-Type: application/json
72
+
73
+ {
74
+ "id": "{UUID}",
75
+ "escopo": "{escopo}",
76
+ "tenant": 0,
77
+ "grupo_empresarial": "00000000-0000-0000-0000-000000000000",
78
+ "codigo": "{codigo da entidade}",
79
+ "descricao": "{descrição da entidade}",
80
+ "json_schema": {
81
+ "edl_version": "1.0",
82
+ "escopo": "{escopo}",
83
+ "description": "{descrição da entidade}",
84
+ "id": "cliente",
85
+ "version": "0.0.1",
86
+ ...
87
+ }
88
+ }
89
+ ```
90
+
91
+ Observações:
92
+ * Note que, acima há placeholders a alterar.
93
+ * Note também que o JSON não está completo, e, o correto é deguir a documentação do EDL.
94
+ * 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.
95
+
96
+ 3. Essa rota irá retornar algo semelhante a:
97
+
98
+ ```http
99
+ HTTP/1.1 202 ACCEPTED
100
+ Location: https://api.nasajon.app/restlib2/entity-compilations/status/{UUID do processo de compilação}
101
+ ```
102
+
103
+ E, se você fizer uma chamada à rota retornada, poderá acompanhar o status da compilação, incluindo eventuais erros que venham a ocorrer.
104
+
105
+ 4. Testar a API compilada.
106
+
107
+ ## Como rodar a compilação de EDLs localmente?
108
+
109
+ 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.
110
+
111
+ Para isso, considere os passos a seguir:
112
+
113
+ 1. Crie um diretório, e coloque todos os seus EDLs lá (garantindo que EDLs relacionados estejam no mesmo).
114
+ 2. Instale, no seu ambiente pyhton de teste, a biblioteca `nsj-rest-lib2`:
115
+
116
+ ```sh
117
+ pip install nsj-rest-lib2
118
+ ```
119
+
120
+ 3. Rode o comando abaixo (adaptado para seu diretório):
121
+ ```sh
122
+ python3 -m nsj_rest_lib2.compiler.compiler -d $(shell pwd)/{diretorio_com_os_edls_json}
123
+ ```
124
+
125
+ O resultado da compilação será impresso no console (erros, ou código total gerado).
126
+
127
+ ## Como configurar uma aplicação para expôr rotas de acordo com o padrão do RestLib2?
128
+
129
+ Para que uma aplicação exponha as rotas no padrão do RestLib2, não são necessários muitos passos. Antes basta:
130
+
131
+ 1. Instalar, em sua aplicação, a dependência para o projeto nsj-rest-lib2
132
+
133
+ ```sh
134
+ pip install nsj-rest-lib2
135
+ ```
136
+
137
+ Não esqueça de fixar a versão usada (como sendo a última), no arquivo requirements.txt.
138
+
139
+ 2. Adicione a variável de ambiente abaixo em sua aplciação
140
+
141
+ ```env
142
+ ESCOPO_RESTLIB2: "{COLOQUE O IDENTIFICADOR DE ESCOPO QUE DESEJAR PARA SUA APLICAÇÃO (UMA SIMPLES STRING SEM ESPAÇO)}"
143
+ ```
144
+
145
+ * Esse identificador de escopo deve se único para sua aplicação.
146
+ * É importante nota que sua aplicação só irá expôr JSONs de EDL configurados para o mesmo escopo definido aqui.
147
+
148
+ 3. Instale, como dependência a biblioteca, nsj-rest-lib2:
149
+
150
+ ```sh
151
+ pip install nsj-rest-lib2
152
+ ```
153
+
154
+ Não esqueça de fixar a versão usada (como sendo a última), no arquivo requirements.txt.
155
+
156
+ 4. Adicione a linha abaixo no arquivo wsgi.py (de inicilização de sua aplicação):
157
+
158
+ ```python
159
+ from nsj_rest_lib2.controller.dynamic_controller import setup_dynamic_routes
160
+ from nasajon.injector_factory_multibanco import InjectorFactoryMultibanco
161
+
162
+ setup_dynamic_routes(application, injector_factory=InjectorFactoryMultibanco)
163
+ ```
164
+
165
+ * No exemplo acima, a rota é multibanco, mas, não é obrigatório.
166
+ * Os parâmetros de setup são:
167
+ * flask_app: Variável obrigatório, que aponte para sua aplicação Flask.
168
+ * multidb: Flag (padrão True)
169
+ * dynamic_root_path: URL padrão base de todos os endpoints do RestLib2 (padrão: "edl1")
170
+ * 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).
171
+
172
+ ## Carregando EDLs direto do disco
173
+
174
+ 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.
175
+
176
+ Exemplo:
177
+
178
+ ```python
179
+ from nsj_rest_lib2.controller.dynamic_controller import setup_dynamic_routes
180
+
181
+ setup_dynamic_routes(
182
+ application,
183
+ injector_factory=InjectorFactoryMultibanco,
184
+ edls_path="@schemas/entities",
185
+ )
186
+ ```
187
+
188
+ Observações:
189
+ * Os EDLs são carregados e compilados uma vez, ficando em cache em memória. Chamadas seguintes reutilizam o cache.
190
+ * A resolução das entidades ocorre primeiro pelo cache local; se não encontrar, o Redis é consultado (quando habilitado).
191
+
192
+ Para desabilitar o Redis e usar somente EDLs do disco, defina a variável de ambiente abaixo:
193
+
194
+ ```env
195
+ EDLS_FROM_REDIS=false
196
+ ```
197
+
198
+ O valor padrão de `EDLS_FROM_REDIS` é `true`.
199
+
200
+
201
+ **Pronto, isso deve bastar para expôr os EDLs configurados para o mesmo escopo da aplicação.**
202
+
203
+ **OBSERVAÇÃO GERAL: Isso só funciona para aplicações Flask.**
@@ -0,0 +1,182 @@
1
+ # RestLib2
2
+
3
+ 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.
4
+
5
+ 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.
6
+
7
+ 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).
8
+
9
+ ## Links
10
+
11
+ [Guia do EDL](docs/README.md)
12
+ [ESPECIFICAÇÃO DO MODELO DE ENTIDADES](docs/especificacao.md)
13
+
14
+ ## Rota das APIs geradas
15
+
16
+ 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:
17
+
18
+ ```http
19
+ #############################
20
+ # List Prod
21
+ #############################
22
+ GET https://api.nasajon.app/dados-mestre/edl1/clientes?tenant=47&grupo_empresarial=NASAJON HTTP/1.1
23
+ Authorization: Bearer *****
24
+ Accept: application/json
25
+ ```
26
+
27
+ * Note que, na API de Dados Mestre, todas as APIs do RestLib2 ficarão debaixo da rota: ```https://api.nasajon.app/dados-mestre/edl1/```
28
+ * O endpoint em si, varia a cada JSON, e fica configurado no nó ```api.resource``` do JSON de EDL em questão.
29
+
30
+ ## Fluxo básico de uso
31
+
32
+ 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:
33
+
34
+ ### Fluxo por meio de código versionado
35
+ 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)).
36
+ 2. Fazer push das alterações.
37
+ 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).
38
+ 4. Testar as APIs compiladas.
39
+
40
+ ### Fluxo de deploy direto pela API
41
+ 1. Criar o JSON de descrição da entidade desejada.
42
+ 2. Registrá-lo diretamente, por meio da API de controle do RestLib2. segue exemplo de chamada abaixo:
43
+
44
+ ```http
45
+ ###############################
46
+ # Post dinâmico
47
+ ###############################
48
+ POST https://api.nasajon.app/restlib2/entities HTTP/1.1
49
+ Authorization: Bearer ******
50
+ Content-Type: application/json
51
+
52
+ {
53
+ "id": "{UUID}",
54
+ "escopo": "{escopo}",
55
+ "tenant": 0,
56
+ "grupo_empresarial": "00000000-0000-0000-0000-000000000000",
57
+ "codigo": "{codigo da entidade}",
58
+ "descricao": "{descrição da entidade}",
59
+ "json_schema": {
60
+ "edl_version": "1.0",
61
+ "escopo": "{escopo}",
62
+ "description": "{descrição da entidade}",
63
+ "id": "cliente",
64
+ "version": "0.0.1",
65
+ ...
66
+ }
67
+ }
68
+ ```
69
+
70
+ Observações:
71
+ * Note que, acima há placeholders a alterar.
72
+ * Note também que o JSON não está completo, e, o correto é deguir a documentação do EDL.
73
+ * 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.
74
+
75
+ 3. Essa rota irá retornar algo semelhante a:
76
+
77
+ ```http
78
+ HTTP/1.1 202 ACCEPTED
79
+ Location: https://api.nasajon.app/restlib2/entity-compilations/status/{UUID do processo de compilação}
80
+ ```
81
+
82
+ E, se você fizer uma chamada à rota retornada, poderá acompanhar o status da compilação, incluindo eventuais erros que venham a ocorrer.
83
+
84
+ 4. Testar a API compilada.
85
+
86
+ ## Como rodar a compilação de EDLs localmente?
87
+
88
+ 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.
89
+
90
+ Para isso, considere os passos a seguir:
91
+
92
+ 1. Crie um diretório, e coloque todos os seus EDLs lá (garantindo que EDLs relacionados estejam no mesmo).
93
+ 2. Instale, no seu ambiente pyhton de teste, a biblioteca `nsj-rest-lib2`:
94
+
95
+ ```sh
96
+ pip install nsj-rest-lib2
97
+ ```
98
+
99
+ 3. Rode o comando abaixo (adaptado para seu diretório):
100
+ ```sh
101
+ python3 -m nsj_rest_lib2.compiler.compiler -d $(shell pwd)/{diretorio_com_os_edls_json}
102
+ ```
103
+
104
+ O resultado da compilação será impresso no console (erros, ou código total gerado).
105
+
106
+ ## Como configurar uma aplicação para expôr rotas de acordo com o padrão do RestLib2?
107
+
108
+ Para que uma aplicação exponha as rotas no padrão do RestLib2, não são necessários muitos passos. Antes basta:
109
+
110
+ 1. Instalar, em sua aplicação, a dependência para o projeto nsj-rest-lib2
111
+
112
+ ```sh
113
+ pip install nsj-rest-lib2
114
+ ```
115
+
116
+ Não esqueça de fixar a versão usada (como sendo a última), no arquivo requirements.txt.
117
+
118
+ 2. Adicione a variável de ambiente abaixo em sua aplciação
119
+
120
+ ```env
121
+ ESCOPO_RESTLIB2: "{COLOQUE O IDENTIFICADOR DE ESCOPO QUE DESEJAR PARA SUA APLICAÇÃO (UMA SIMPLES STRING SEM ESPAÇO)}"
122
+ ```
123
+
124
+ * Esse identificador de escopo deve se único para sua aplicação.
125
+ * É importante nota que sua aplicação só irá expôr JSONs de EDL configurados para o mesmo escopo definido aqui.
126
+
127
+ 3. Instale, como dependência a biblioteca, nsj-rest-lib2:
128
+
129
+ ```sh
130
+ pip install nsj-rest-lib2
131
+ ```
132
+
133
+ Não esqueça de fixar a versão usada (como sendo a última), no arquivo requirements.txt.
134
+
135
+ 4. Adicione a linha abaixo no arquivo wsgi.py (de inicilização de sua aplicação):
136
+
137
+ ```python
138
+ from nsj_rest_lib2.controller.dynamic_controller import setup_dynamic_routes
139
+ from nasajon.injector_factory_multibanco import InjectorFactoryMultibanco
140
+
141
+ setup_dynamic_routes(application, injector_factory=InjectorFactoryMultibanco)
142
+ ```
143
+
144
+ * No exemplo acima, a rota é multibanco, mas, não é obrigatório.
145
+ * Os parâmetros de setup são:
146
+ * flask_app: Variável obrigatório, que aponte para sua aplicação Flask.
147
+ * multidb: Flag (padrão True)
148
+ * dynamic_root_path: URL padrão base de todos os endpoints do RestLib2 (padrão: "edl1")
149
+ * 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).
150
+
151
+ ## Carregando EDLs direto do disco
152
+
153
+ 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.
154
+
155
+ Exemplo:
156
+
157
+ ```python
158
+ from nsj_rest_lib2.controller.dynamic_controller import setup_dynamic_routes
159
+
160
+ setup_dynamic_routes(
161
+ application,
162
+ injector_factory=InjectorFactoryMultibanco,
163
+ edls_path="@schemas/entities",
164
+ )
165
+ ```
166
+
167
+ Observações:
168
+ * Os EDLs são carregados e compilados uma vez, ficando em cache em memória. Chamadas seguintes reutilizam o cache.
169
+ * A resolução das entidades ocorre primeiro pelo cache local; se não encontrar, o Redis é consultado (quando habilitado).
170
+
171
+ Para desabilitar o Redis e usar somente EDLs do disco, defina a variável de ambiente abaixo:
172
+
173
+ ```env
174
+ EDLS_FROM_REDIS=false
175
+ ```
176
+
177
+ O valor padrão de `EDLS_FROM_REDIS` é `true`.
178
+
179
+
180
+ **Pronto, isso deve bastar para expôr os EDLs configurados para o mesmo escopo da aplicação.**
181
+
182
+ **OBSERVAÇÃO GERAL: Isso só funciona para aplicações Flask.**
@@ -1,6 +1,8 @@
1
+ import hashlib
1
2
  import uuid
2
- from typing import Iterable
3
+ from typing import Iterable, Iterator, Optional
3
4
 
5
+ from nsj_rest_lib2.compiler.model import CompilerResult
4
6
  from nsj_rest_lib2.compiler.util.str_util import CompilerStrUtil
5
7
 
6
8
 
@@ -14,6 +16,67 @@ def compile_namespace_keys(
14
16
  return (grupo_key, tenant_key, default_key)
15
17
 
16
18
 
19
+ def resolve_namespace_key(
20
+ tenant: str | int | None, grupo_empresarial: str | uuid.UUID | None
21
+ ) -> str:
22
+ grupo_key, tenant_key, default_key = compile_namespace_keys(
23
+ tenant,
24
+ grupo_empresarial,
25
+ )
26
+
27
+ if (
28
+ tenant
29
+ and tenant != 0
30
+ and grupo_empresarial
31
+ and str(grupo_empresarial) != "00000000-0000-0000-0000-000000000000"
32
+ ):
33
+ return grupo_key
34
+ if tenant and tenant != 0:
35
+ return tenant_key
36
+ return default_key
37
+
38
+
39
+ def build_entity_hash(compiler_result: CompilerResult) -> str:
40
+ hasher = hashlib.sha256()
41
+
42
+ for content in _iter_hash_chunks(
43
+ compiler_result.dto_code,
44
+ compiler_result.entity_code,
45
+ compiler_result.insert_function_name,
46
+ compiler_result.update_function_name,
47
+ compiler_result.get_function_name,
48
+ compiler_result.list_function_name,
49
+ compiler_result.delete_function_name,
50
+ compiler_result.source_insert_function,
51
+ compiler_result.source_update_function,
52
+ compiler_result.source_get_function_type,
53
+ compiler_result.source_list_function_type,
54
+ compiler_result.source_delete_function_type,
55
+ compiler_result.post_response_dto_class_name,
56
+ compiler_result.put_response_dto_class_name,
57
+ compiler_result.patch_response_dto_class_name,
58
+ str(compiler_result.retrieve_after_insert),
59
+ str(compiler_result.retrieve_after_update),
60
+ str(compiler_result.retrieve_after_partial_update),
61
+ str(compiler_result.custom_json_post_response),
62
+ str(compiler_result.custom_json_put_response),
63
+ str(compiler_result.custom_json_patch_response),
64
+ str(compiler_result.custom_json_get_response),
65
+ str(compiler_result.custom_json_list_response),
66
+ str(compiler_result.custom_json_delete_response),
67
+ compiler_result.service_account,
68
+ ):
69
+ hasher.update(content)
70
+
71
+ return hasher.hexdigest()
72
+
73
+
74
+ def _iter_hash_chunks(*chunks: Optional[str]) -> Iterator[bytes]:
75
+ for chunk in chunks:
76
+ if chunk:
77
+ yield chunk.encode("utf-8")
78
+
79
+
17
80
  def compile_dto_class_name(entity_id: str, prefx_class_name: str = "") -> str:
18
81
  return f"{CompilerStrUtil.to_pascal_case(prefx_class_name)}{CompilerStrUtil.to_pascal_case(entity_id)}DTO"
19
82
 
@@ -55,6 +55,7 @@ def setup_dynamic_routes(
55
55
  dynamic_root_path: str = "edl1",
56
56
  injector_factory: Any = None,
57
57
  escopo_in_url: bool = False,
58
+ edls_path: str | None = None,
58
59
  ) -> None:
59
60
 
60
61
  if not escopo_in_url:
@@ -68,6 +69,8 @@ def setup_dynamic_routes(
68
69
  f"/{APP_NAME}/{dynamic_root_path}/<entity_escopo>/<entity_resource>/<id>"
69
70
  )
70
71
 
72
+ entity_loader = EntityLoader(edls_path=edls_path)
73
+
71
74
  def _dynamic_route_wrapper(
72
75
  route_builder: Callable[[tuple[Any, ...]], Callable[..., Any]],
73
76
  endpoint_suffix: str | None = None,
@@ -83,7 +86,6 @@ def setup_dynamic_routes(
83
86
  tenant, grupo_empresarial, force_reload = _get_query_args()
84
87
 
85
88
  try:
86
- entity_loader = EntityLoader()
87
89
  entity_config = entity_loader.load_entity_source(
88
90
  entity_resource,
89
91
  tenant,
@@ -1,13 +1,15 @@
1
1
  from __future__ import annotations
2
2
 
3
- import hashlib
4
3
  import json
5
- from typing import Any, Dict, Iterator, Optional
4
+ from typing import Any, Dict
6
5
 
7
6
  from nsj_rest_lib2.compiler.edl_model.entity_model import EntityModel
8
7
  from nsj_rest_lib2.compiler.edl_model.entity_model_base import EntityModelBase
9
8
  from nsj_rest_lib2.compiler.model import CompilerResult
10
- from nsj_rest_lib2.compiler.util.type_naming_util import compile_namespace_keys
9
+ from nsj_rest_lib2.compiler.util.type_naming_util import (
10
+ build_entity_hash,
11
+ resolve_namespace_key,
12
+ )
11
13
  from nsj_rest_lib2.redis_config import set_redis
12
14
  from nsj_rest_lib2.settings import ESCOPO_RESTLIB2
13
15
 
@@ -113,21 +115,7 @@ class EntityConfigWriter:
113
115
  tenant = getattr(entity_model, "tenant", None)
114
116
  grupo_empresarial = getattr(entity_model, "grupo_empresarial", None)
115
117
 
116
- grupo_key, tenant_key, default_key = compile_namespace_keys(
117
- tenant,
118
- grupo_empresarial,
119
- )
120
-
121
- if (
122
- tenant
123
- and tenant != 0
124
- and grupo_empresarial
125
- and str(grupo_empresarial) != "00000000-0000-0000-0000-000000000000"
126
- ):
127
- return grupo_key
128
- if tenant and tenant != 0:
129
- return tenant_key
130
- return default_key
118
+ return resolve_namespace_key(tenant, grupo_empresarial)
131
119
 
132
120
  def _resolve_resource(self, entity_model: EntityModelBase) -> str:
133
121
  if not isinstance(entity_model, EntityModel) or not entity_model.api:
@@ -139,41 +127,4 @@ class EntityConfigWriter:
139
127
  return entity_model.api.resource
140
128
 
141
129
  def _build_entity_hash(self, compiler_result: CompilerResult) -> str:
142
- hasher = hashlib.sha256()
143
-
144
- for content in self._iter_hash_chunks(
145
- compiler_result.dto_code,
146
- compiler_result.entity_code,
147
- compiler_result.insert_function_name,
148
- compiler_result.update_function_name,
149
- compiler_result.get_function_name,
150
- compiler_result.list_function_name,
151
- compiler_result.delete_function_name,
152
- compiler_result.source_insert_function,
153
- compiler_result.source_update_function,
154
- compiler_result.source_get_function_type,
155
- compiler_result.source_list_function_type,
156
- compiler_result.source_delete_function_type,
157
- compiler_result.post_response_dto_class_name,
158
- compiler_result.put_response_dto_class_name,
159
- compiler_result.patch_response_dto_class_name,
160
- str(compiler_result.retrieve_after_insert),
161
- str(compiler_result.retrieve_after_update),
162
- str(compiler_result.retrieve_after_partial_update),
163
- str(compiler_result.custom_json_post_response),
164
- str(compiler_result.custom_json_put_response),
165
- str(compiler_result.custom_json_patch_response),
166
- str(compiler_result.custom_json_get_response),
167
- str(compiler_result.custom_json_list_response),
168
- str(compiler_result.custom_json_delete_response),
169
- compiler_result.service_account,
170
- ):
171
- hasher.update(content)
172
-
173
- return hasher.hexdigest()
174
-
175
- @staticmethod
176
- def _iter_hash_chunks(*chunks: Optional[str]) -> Iterator[bytes]:
177
- for chunk in chunks:
178
- if chunk:
179
- yield chunk.encode("utf-8")
130
+ return build_entity_hash(compiler_result)