ApiLogicServer 14.3.25__py3-none-any.whl → 14.5.0__py3-none-any.whl

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 (167) hide show
  1. api_logic_server_cli/add_cust/add_cust.py +283 -0
  2. api_logic_server_cli/api_logic_server.py +18 -250
  3. api_logic_server_cli/api_logic_server_info.yaml +3 -3
  4. api_logic_server_cli/cli.py +54 -35
  5. api_logic_server_cli/create_from_model/__pycache__/api_logic_server_utils.cpython-312.pyc +0 -0
  6. api_logic_server_cli/create_from_model/__pycache__/create_db_from_model.cpython-312.pyc +0 -0
  7. api_logic_server_cli/create_from_model/__pycache__/dbml.cpython-312.pyc +0 -0
  8. api_logic_server_cli/create_from_model/__pycache__/ont_build.cpython-312.pyc +0 -0
  9. api_logic_server_cli/create_from_model/__pycache__/ont_create.cpython-312.pyc +0 -0
  10. api_logic_server_cli/create_from_model/api_logic_server_utils.py +47 -0
  11. api_logic_server_cli/create_from_model/create_db_from_model.py +2 -0
  12. api_logic_server_cli/create_from_model/dbml.py +113 -58
  13. api_logic_server_cli/create_from_model/ont_build.py +102 -74
  14. api_logic_server_cli/create_from_model/ont_create.py +7 -6
  15. api_logic_server_cli/create_from_model/safrs-react-admin-npm-build/static/.DS_Store +0 -0
  16. api_logic_server_cli/database/basic_demo.sqlite +0 -0
  17. api_logic_server_cli/database/basic_demo.txt +1 -0
  18. api_logic_server_cli/database/basic_demo_wg.sqlite +0 -0
  19. api_logic_server_cli/database/nw-gold-fix.sql +62 -0
  20. api_logic_server_cli/database/nw-gold.sqlite +0 -0
  21. api_logic_server_cli/{prototypes/manager/webgenai → fragments}/docker-compose.yml +1 -1
  22. api_logic_server_cli/genai/genai.py +42 -11
  23. api_logic_server_cli/genai/genai_graphics.py +252 -38
  24. api_logic_server_cli/genai/genai_svcs.py +20 -12
  25. api_logic_server_cli/manager.py +22 -12
  26. api_logic_server_cli/prototypes/.DS_Store +0 -0
  27. api_logic_server_cli/prototypes/base/.DS_Store +0 -0
  28. api_logic_server_cli/prototypes/base/.vscode/launch.json +22 -2
  29. api_logic_server_cli/prototypes/base/api/expose_api_models.py +3 -1
  30. api_logic_server_cli/prototypes/base/api_logic_server_run.py +5 -2
  31. api_logic_server_cli/prototypes/base/config/activate_logicbank.py +1 -0
  32. api_logic_server_cli/prototypes/base/config/config.py +123 -25
  33. api_logic_server_cli/prototypes/base/config/default.env +7 -1
  34. api_logic_server_cli/prototypes/base/config/logging.yml +1 -0
  35. api_logic_server_cli/prototypes/base/config/server_setup.py +33 -1
  36. api_logic_server_cli/prototypes/base/database/test_data/readme.md +5 -2
  37. api_logic_server_cli/prototypes/base/devops/docker-standard-image/docker-compose-standard-image.yml +7 -2
  38. api_logic_server_cli/prototypes/base/docs/training/logic_bank_api.prompt +314 -0
  39. api_logic_server_cli/prototypes/base/docs/training/logic_example.py +41 -0
  40. api_logic_server_cli/prototypes/base/integration/kafka/kafka_producer.py +12 -5
  41. api_logic_server_cli/prototypes/base/integration/n8n/n8n_producer.py +68 -21
  42. api_logic_server_cli/prototypes/base/integration/n8n/n8n_readme.md +19 -0
  43. api_logic_server_cli/prototypes/base/integration/system/FlaskKafka.py +5 -1
  44. api_logic_server_cli/prototypes/base/test/basic/server_test.py +1 -1
  45. api_logic_server_cli/prototypes/base/ui/templates/bar_chart.jinja +64 -0
  46. api_logic_server_cli/prototypes/basic_demo/README.md +29 -52
  47. api_logic_server_cli/prototypes/basic_demo/customizations/api/.DS_Store +0 -0
  48. api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/mcp_server_executor.py +138 -0
  49. api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/openapi.py +92 -0
  50. api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/proper_update_def.json +71 -0
  51. api_logic_server_cli/prototypes/basic_demo/customizations/config/default.env +13 -0
  52. api_logic_server_cli/prototypes/basic_demo/customizations/database/db.sqlite +0 -0
  53. api_logic_server_cli/prototypes/basic_demo/customizations/database/models.py +131 -0
  54. api_logic_server_cli/prototypes/basic_demo/customizations/integration/.DS_Store +0 -0
  55. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/.DS_Store +0 -0
  56. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/1_langchain_loader.py +71 -0
  57. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/2_gpt_mcp_prompt.txt +19 -0
  58. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/README_mcp.md +13 -0
  59. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_client_executor.py +295 -0
  60. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_schema.txt +47 -0
  61. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_server_discovery.json +9 -0
  62. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/multi_mcp_flow/multi_mcp_flow.png +0 -0
  63. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/multi_mcp_flow/multi_mcp_orchestration.yaml +49 -0
  64. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/multi_mcp_flow/wny mcp flows.png +0 -0
  65. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/natlang_to_api.py +73 -0
  66. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/curl.txt +5 -0
  67. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/images/MCP Overview.png +0 -0
  68. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/images/MCP_Arch.png +0 -0
  69. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/images/MCP_Overview_Executor.png +0 -0
  70. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/invoke_llm/1 - prompt_messages_array.json +10 -0
  71. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/invoke_llm/2 - completion_tool_context.json +12 -0
  72. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/llm_schema.txt +38 -0
  73. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/nw_swagger_2.yaml +17393 -0
  74. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/nw_swagger_3.yaml +16660 -0
  75. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/nw_swagger_3_relaxed.yaml +109 -0
  76. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/proxy_server.py +51 -0
  77. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/proxy_serverZ.py +72 -0
  78. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/resources/validate_jsonapi.py +64 -0
  79. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/run_executor.py +23 -0
  80. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/swagger_converter.py +65 -0
  81. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/z_old/3_executor_test_agent.py +52 -0
  82. api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/3_executor_test_agent.py +52 -0
  83. api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/README_functon.md +201 -0
  84. api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/ai_plugin.json +17 -0
  85. api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/nw-swagger_3.json +1731 -0
  86. api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/snippets.txt +5 -0
  87. api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/swagger_3 genai_demo_with_get.json +1731 -0
  88. api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/swagger_3.json +1782 -0
  89. api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/swagger_3_genai_demo.json +264 -0
  90. api_logic_server_cli/prototypes/basic_demo/customizations/integration/openai_function/swagger_3_genai_demo_with_update.json +1782 -0
  91. api_logic_server_cli/prototypes/basic_demo/customizations/logic/declare_logic.py +62 -44
  92. api_logic_server_cli/prototypes/basic_demo/customizations/security/declare_security.py +11 -12
  93. api_logic_server_cli/prototypes/basic_demo/customizations/ui/admin/admin.yaml +166 -0
  94. api_logic_server_cli/prototypes/basic_demo/iteration/api/{customize_api.py → api_discovery/order_b2b.py} +17 -23
  95. api_logic_server_cli/prototypes/basic_demo/iteration/database/db.sqlite +0 -0
  96. api_logic_server_cli/prototypes/basic_demo/iteration/integration/row_dict_maps/OrderB2B.py +6 -5
  97. api_logic_server_cli/prototypes/basic_demo/iteration/integration/row_dict_maps/OrderShipping.py +4 -4
  98. api_logic_server_cli/prototypes/basic_demo/iteration/logic/declare_logic.py +69 -43
  99. api_logic_server_cli/prototypes/basic_demo/iteration/ui/admin/admin.yaml +125 -50
  100. api_logic_server_cli/prototypes/genai_demo/ui/admin/admin.yaml +1 -1
  101. api_logic_server_cli/prototypes/manager/README.md +30 -4
  102. api_logic_server_cli/prototypes/manager/README_X.md +663 -0
  103. api_logic_server_cli/prototypes/manager/system/genai/.DS_Store +0 -0
  104. api_logic_server_cli/prototypes/manager/system/genai/examples/.DS_Store +0 -0
  105. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/.DS_Store +0 -0
  106. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.prompt +0 -10
  107. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo.response_example +32 -10
  108. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/docs/002_create_db_models.prompt +4 -4
  109. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_docs_logic/docs/003_create_db_models.response +77 -47
  110. api_logic_server_cli/prototypes/manager/system/genai/examples/genai_demo/genai_demo_informal.prompt +1 -1
  111. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/dashboard_services.jinja +83 -0
  112. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_dashboard_WIP.py +34 -0
  113. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/{graphics_services.py → graphics_services_api_xxx.py} +0 -9
  114. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_services_db.jinja +46 -0
  115. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/graphics_services_db_each_method.jinja +36 -0
  116. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/graphics.prompt +7 -3
  117. api_logic_server_cli/prototypes/manager/system/genai/prompt_inserts/response_format.prompt +8 -1
  118. api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/install-ApiLogicServer-dev.ps1 +100 -0
  119. api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/install-ApiLogicServer-dev.sh +116 -0
  120. api_logic_server_cli/prototypes/manager/system/install-ApiLogicServer-dev/readme.md +7 -0
  121. api_logic_server_cli/prototypes/manager/system/style-guide.yaml +2 -2
  122. api_logic_server_cli/prototypes/manager/webgenai/README.md +6 -0
  123. api_logic_server_cli/prototypes/nw/docs/graphics/count_orders_by_category.prompt +1 -0
  124. api_logic_server_cli/prototypes/nw/docs/graphics/order_count_by_month.prompt +1 -0
  125. api_logic_server_cli/prototypes/nw/docs/graphics/request copy.json +892 -0
  126. api_logic_server_cli/prototypes/nw/docs/graphics/request.json +6 -0
  127. api_logic_server_cli/prototypes/nw/docs/graphics/response.json +17 -0
  128. api_logic_server_cli/prototypes/nw/docs/graphics/response.yaml +59 -0
  129. api_logic_server_cli/prototypes/nw/docs/graphics/sales_by_category.prompt +1 -0
  130. api_logic_server_cli/prototypes/nw/ui/admin/home.js +5 -4
  131. api_logic_server_cli/prototypes/nw/ui/app_model_custom.yaml +851 -1082
  132. api_logic_server_cli/prototypes/nw_no_cust/Tutorial.md +45 -26
  133. api_logic_server_cli/prototypes/nw_no_cust/api/api_discovery/openapi.py +130 -0
  134. api_logic_server_cli/prototypes/nw_no_cust/api/api_discovery/proper_update_def.json +71 -0
  135. api_logic_server_cli/prototypes/nw_no_cust/config/default.env +13 -0
  136. api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/count_orders_by_category.prompt +1 -0
  137. api_logic_server_cli/prototypes/nw_no_cust/docs/graphics/sales_by_employee.prompt +1 -0
  138. api_logic_server_cli/prototypes/ont_app/ontimize_seed/nginx/nginx.conf +2 -2
  139. api_logic_server_cli/prototypes/ont_app/ontimize_seed/package-lock.json +9725 -1180
  140. api_logic_server_cli/prototypes/ont_app/ontimize_seed/package.json +6 -9
  141. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/app/app.config.ts +2 -1
  142. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/app/shared/app.services.config.ts +1 -1
  143. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/assets/css/app.scss +4 -0
  144. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/assets/i18n/en.json +1 -1
  145. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/assets/i18n/es.json +14 -12
  146. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/environments/environment.prod.ts +5 -5
  147. api_logic_server_cli/prototypes/ont_app/ontimize_seed/src/environments/environment.ts +5 -5
  148. api_logic_server_cli/prototypes/ont_app/templates/app_config.jinja +1 -1
  149. api_logic_server_cli/prototypes/ont_app/templates/date_template.html +1 -1
  150. api_logic_server_cli/prototypes/ont_app/templates/detail_template.html +1 -1
  151. api_logic_server_cli/prototypes/ont_app/templates/new_template.html +16 -16
  152. api_logic_server_cli/prototypes/ont_app/templates/textarea_template.html +1 -1
  153. api_logic_server_cli/prototypes/ont_app/templates/timestamp_template.html +1 -1
  154. api_logic_server_cli/prototypes/sample_ai/logic/declare_logic.py +30 -13
  155. apilogicserver-14.5.0.dist-info/METADATA +76 -0
  156. {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/RECORD +160 -88
  157. {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/WHEEL +1 -1
  158. api_logic_server_cli/prototypes/basic_demo/apply_customizations.ps1 +0 -17
  159. api_logic_server_cli/prototypes/basic_demo/apply_customizations.sh +0 -14
  160. api_logic_server_cli/prototypes/basic_demo/apply_iteration.ps1 +0 -20
  161. api_logic_server_cli/prototypes/basic_demo/apply_iteration.sh +0 -15
  162. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/service_template_jsonapi_rpc.jinja +0 -37
  163. api_logic_server_cli/prototypes/manager/system/genai/graphics_templates/service_template_unused.jinja +0 -38
  164. apilogicserver-14.3.25.dist-info/METADATA +0 -167
  165. {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/entry_points.txt +0 -0
  166. {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/licenses/LICENSE +0 -0
  167. {apilogicserver-14.3.25.dist-info → apilogicserver-14.5.0.dist-info}/top_level.txt +0 -0
@@ -12,21 +12,19 @@ See how to build a complete database system -- in minutes instead of weeks or mo
12
12
 
13
13
  We'll use API Logic Server (open source), providing:
14
14
 
15
- | Key Feature | Providing | Why It Matters|
16
- | :--- |:---|:---|
17
- | **Automation** | Instant Project Creation:<br>An API and an Admin web app | Unblock UI App Dev<br>Instant Agile Collaboration |
18
- | **Customization** | Declarative logic and security <br> 5 rules vs. 200 lines of Python | 40X less backend code |
19
- | **Iteration** | Revising the data model, and <br>Adding rules plus Python | Iterative development <br> Extensiblity with Python |
15
+ | Key Feature | Providing | Why It Matters |
16
+ | :---------------- | :------------------------------------------------------------------ | :-------------------------------------------------- |
17
+ | **Automation** | Instant Project Creation:<br>An API and an Admin web app | Unblock UI App Dev<br>Instant Agile Collaboration |
18
+ | **Customization** | Declarative logic and security <br> 5 rules vs. 200 lines of Python | 40X less backend code |
19
+ | **Iteration** | Revising the data model, and <br>Adding rules plus Python | Iterative development <br> Extensiblity with Python |
20
20
 
21
21
  The entire process takes 10 minutes, instead of several weeks using traditional development.
22
22
 
23
23
  You can use this article in several ways:
24
24
 
25
- * Conceptual Overview - focus on the basic process. Operational details are moved to the Appendix to retain focus on the concepts.
26
-
27
- * Self-demo - you can create this system yourself.
28
-
29
- * Self-demo with video - you can also use [this video](https://www.youtube.com/watch?v=sD6RFp8S6Fg) (it's the same system, but the database is created with ChatGPT).
25
+ - Conceptual Overview - focus on the basic process. Operational details are moved to the Appendix to retain focus on the concepts.
26
+ - Self-demo - you can create this system yourself.
27
+ - Self-demo with video - you can also use [this video](https://www.youtube.com/watch?v=sD6RFp8S6Fg) (it's the same system, but the database is created with ChatGPT).
30
28
 
31
29
  &nbsp;
32
30
 
@@ -45,9 +43,7 @@ This creates a project by reading your schema. The database is Customer, Orders
45
43
  You can open with VSCode, and run it as follows:
46
44
 
47
45
  1. **Create Virtual Environment:** as shown in the Appendix.
48
-
49
46
  2. **Start the Server:** F5 (also described in the Appendix).
50
-
51
47
  3. **Start the Admin App:** either use the links provided in the IDE console, or click [http://localhost:5656/](http://localhost:5656/). The screen shown below should appear in your Browser.
52
48
 
53
49
  The sections below explore the system that has been created (which would be similar for your own database).
@@ -58,7 +54,7 @@ The sections below explore the system that has been created (which would be simi
58
54
 
59
55
  The system creates an API with end points for each table, with filtering, sorting, pagination, optimistic locking and related data access -- **[self-serve](https://apilogicserver.github.io/Docs/API-Self-Serve/), ready for custom app dev.**
60
56
 
61
- <img src="https://github.com/ApiLogicServer/Docs/blob/main/docs/images/basic_demo/api-swagger.jpeg?raw=true">
57
+ ![api-swagger](https://github.com/ApiLogicServer/Docs/blob/main/docs/images/basic_demo/api-swagger.jpeg?raw=true)
62
58
 
63
59
  ### Admin App
64
60
 
@@ -66,32 +62,29 @@ It also creates an Admin App: multi-page, multi-table apps -- ready for **[busin
66
62
 
67
63
  You can click Customer 2, see their Orders, and Items.
68
64
 
69
- <img src="https://github.com/ApiLogicServer/Docs/blob/main/docs/images/basic_demo/admin-app-initial.jpeg?raw=true">
65
+ ![admin-app-initial](https://github.com/ApiLogicServer/Docs/blob/main/docs/images/basic_demo/api-swagger.jpeg?raw=true)
70
66
 
71
67
  ## 2. Customize in your IDE
72
68
 
73
69
  While API/UI automation is a great start, it's critical to enforce logic and security. Here's how.
74
70
 
75
- The follwing `apply_customizations` process simulates adding security to your project, and using your IDE to declare logic and security in `logic/declare_logic.sh` and `security/declare_security.py`. You can diff these files to their created versions, and/or examine the declared logic.
71
+ The follwing *add customizations* process simulates adding security to your project, and using your IDE to declare logic and security in `logic/declare_logic.sh` and `security/declare_security.py`. You can diff these files to their created versions, and/or examine the declared logic.
76
72
 
77
73
  In a terminal window for your project:
78
74
 
79
75
  **1. Stop the Server** (Red Stop button, or Shift-F5 -- see Appendix)
80
76
 
81
- **2. Apply Customizations**
77
+ **2. Add Customizations**
82
78
 
83
79
  ```bash
84
- # mac, linux
85
- sh apply_customizations.sh
86
-
87
- #windows
88
- ./apply_customizations.ps1
80
+ als add-cust
89
81
  ```
82
+
90
83
  &nbsp;
91
84
 
92
85
  ### Declare Security
93
86
 
94
- The `apply_customizations` process above has simulated the `ApiLogicServer add-auth` command, and using your IDE to declare security in `logic/declare_logic.sh`.
87
+ The *add customizations* process above has simulated the `ApiLogicServer add-auth` command, and using your IDE to declare security in `logic/declare_logic.sh`.
95
88
 
96
89
  To see security in action:
97
90
 
@@ -115,7 +108,7 @@ Logic (multi-table derivations and constraints) is a significant portion of a sy
115
108
 
116
109
  Rules are declared in Python, simplified with IDE code completion. The screen below shows the 5 rules for **Check Credit Logic.**
117
110
 
118
- The `apply_customizations` process above has simulated the process of using your IDE to declare logic in `logic/declare_logic.sh`.
111
+ The *add customizations* process above has simulated the process of using your IDE to declare logic in `logic/declare_logic.sh`.
119
112
 
120
113
  To see logic in action:
121
114
 
@@ -169,11 +162,9 @@ Not only are spreadsheet-like rules 40X more concise, they meaningfully simplify
169
162
 
170
163
  The follwing `apply_iteration` process simulates an iteration:
171
164
 
172
- * acquires a new database with `Product.CarbonNeutral`
173
-
174
- * and a revised `ui/admin/admin.yaml` that shows this new column
175
-
176
- * revised logic - in `logic/declare_logic.py`, we replace the 2 lines for the `models.Item.Amount` formula with this (next screenshot shows revised logic executing with breakpoint):
165
+ - acquires a new database with `Product.CarbonNeutral`
166
+ - and a revised `ui/admin/admin.yaml` that shows this new column
167
+ - revised logic - in `logic/declare_logic.py`, we replace the 2 lines for the `models.Item.Amount` formula with this (next screenshot shows revised logic executing with breakpoint):
177
168
 
178
169
  ```python
179
170
  def derive_amount(row: models.Item, old_row: models.Item, logic_row: LogicRow):
@@ -185,8 +176,6 @@ The follwing `apply_iteration` process simulates an iteration:
185
176
  Rule.formula(derive=models.Item.Amount, calling=derive_amount)
186
177
  ```
187
178
 
188
- * issues the `ApiLogicServer rebuild-from-database` command that rebuilds your project (the database models, the api), while preserving the customizations we made above.
189
-
190
179
  In a terminal window for your project:
191
180
 
192
181
  **1. Stop the Server** (Red Stop button, or Shift-F5 -- see Appendix)
@@ -194,12 +183,10 @@ In a terminal window for your project:
194
183
  **2. Apply Iteration**
195
184
 
196
185
  ```bash
197
- # mac, linux
198
- sh apply_iteration.sh
199
-
200
- #windows
201
- ./apply_iteration.ps1
186
+ als add-cust
187
+ als rebuild-from-database
202
188
  ```
189
+
203
190
  &nbsp;
204
191
 
205
192
  **3. Set the breakpoint as shown**
@@ -210,7 +197,7 @@ sh apply_iteration.sh
210
197
 
211
198
  At the breakpoint, note you can use standard debugger services to debug your logic (examine `Item` attributes, step, etc).
212
199
 
213
- <img src="https://github.com/ApiLogicServer/Docs/blob/main/docs/images/basic_demo/logic-debugging.jpeg?raw=true">
200
+ ![logic-debugging](https://github.com/ApiLogicServer/Docs/blob/main/docs/images/basic_demo/logic-debugging.jpeg?raw=true)!
214
201
 
215
202
  &nbsp;
216
203
 
@@ -250,11 +237,9 @@ Note we rebuilt the project from our altered database, illustrating we can **ite
250
237
 
251
238
  Of course, we all know that all businesses the world over depend on the `hello world` app. This is provided in `api/customize_api`. Observe that it's:
252
239
 
253
- * standard Python
254
-
255
- * using Flask
256
-
257
- * and, for database access, SQLAlchemy. Note all updates from custom APIs also enforce your logic.
240
+ - standard Python
241
+ - using Flask
242
+ - and, for database access, SQLAlchemy. Note all updates from custom APIs also enforce your logic.
258
243
 
259
244
  &nbsp;
260
245
 
@@ -270,7 +255,7 @@ API Logic Server also creates scripts for deployment. While these are ***not re
270
255
 
271
256
  ## Summary
272
257
 
273
- <img src="https://github.com/ApiLogicServer/Docs/blob/main/docs/images/basic_demo/summary.jpeg?raw=true">
258
+ ![summary](https://github.com/ApiLogicServer/Docs/blob/main/docs/images/basic_demo/summary.jpeg?raw=true)
274
259
 
275
260
  In minutes - not days or weeks - you've used API Logic Server to convert an idea into **working software,** added **logic and security,** and **iterated** to meet new requirements.
276
261
 
@@ -282,8 +267,9 @@ To dive deeper, you can install [API Logic Server](https://apilogicserver.github
282
267
 
283
268
  ## Appendix: Database Schema
284
269
 
285
- <img src="https://github.com/ApiLogicServer/Docs/blob/main/docs/images/basic_demo/basic_demo_data_model.jpeg?raw=true" width="500">
286
270
 
271
+
272
+ ![basic_demo_data_model](https://github.com/ApiLogicServer/Docs/blob/main/docs/images/basic_demo/basic_demo_data_model.jpeg?raw=true" width="500")
287
273
  &nbsp;
288
274
 
289
275
  ## Appendix: Procedures
@@ -321,28 +307,19 @@ For PyCharm, start the server with CTL-D, Stop with red stop button.
321
307
  To enter a new Order:
322
308
 
323
309
  1. Click `Customer 1``
324
-
325
310
  2. Click `+ ADD NEW ORDER`
326
-
327
311
  3. Set `Notes` to "hurry", and press `SAVE AND SHOW`
328
-
329
312
  4. Click `+ ADD NEW ITEM`
330
-
331
313
  5. Enter Quantity 1, lookup "Product 1", and click `SAVE AND ADD ANOTHER`
332
-
333
314
  6. Enter Quantity 2000, lookup "Product 2", and click `SAVE`
334
-
335
315
  7. Observe the constraint error, triggered by rollups from the `Item` to the `Order` and `Customer`
336
-
337
316
  8. Correct the quantity to 2, and click `Save`
338
317
 
339
-
340
318
  **4. Update the Order**
341
319
 
342
320
  To explore our new logic for green products:
343
321
 
344
322
  1. Access the previous order, and `ADD NEW ITEM`
345
-
346
323
  2. Enter quantity 11, lookup product `Green`, and click `Save`.
347
324
 
348
325
  &nbsp;
@@ -0,0 +1,138 @@
1
+ from flask import request, jsonify
2
+ from flask import Flask, redirect, send_from_directory, send_file
3
+ import logging
4
+ import os
5
+ import json
6
+ import io
7
+
8
+ import requests
9
+ from config.config import Args # circular import error if at top
10
+
11
+ app_logger = logging.getLogger("api_logic_server_app")
12
+
13
+ def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_decorators = []):
14
+ pass
15
+
16
+ def get_server_url():
17
+ """ return the server URL for the OpenAPI spec """
18
+ result = f'http://{Args.instance.swagger_host}:{Args.instance.swagger_port}'
19
+ # get env variable API_LOGIC_SERVER_TUNNEL (or None)
20
+ if tunnel_url := os.getenv("API_LOGIC_SERVER_TUNNEL", None):
21
+ app_logger.info(f".. tunnel URL: {tunnel_url}")
22
+ result = tunnel_url
23
+ return result # + '/api'
24
+
25
+
26
+ @app.before_request
27
+ def before_any_request():
28
+ # print(f"[DEBUG] Incoming request: {request.method} {request.url}")
29
+ if activate_openapi_logging := True:
30
+ if request.content_type == 'application/json' and request.method in ['POST', 'PUT', 'PATCH']:
31
+ # openapi: Incoming request: PATCH http://localhost:5656/api/Customer/1/ {'data': {'attributes': {'credit_limit': 5555}, 'type': 'Customer', 'id': '1'}}
32
+ # openapi: Incoming request: PATCH http://6f6f-2601-644-4900-d6f0-ecc9-6df3-8863-c5b2.ngrok-free.app/api/Customer/1 {'credit_limit': 5555}
33
+
34
+ app_logger.info(f"openapi: Incoming request: {request.method} {request.url} {str(request.json)}")
35
+ else:
36
+ app_logger.info(f"openapi: Incoming request: {request.method} {request.url}")
37
+ # app_logger.info(f"openapi: Incoming request headers: {request.headers}")
38
+
39
+ chatgpt_request_json = {
40
+ "credit_limit": 25000,
41
+ }
42
+ standard_request_json = {
43
+ "data": {
44
+ "type": "Customer",
45
+ "id": "ALFKI",
46
+ "attributes": {
47
+ "name": "Alice",
48
+ "credit_limit": 25000,
49
+ "balance": 12345
50
+ }
51
+ }
52
+ }
53
+ swagger_request_json = {
54
+ 'data': {
55
+ 'attributes': {
56
+ 'credit_limit': 5555
57
+ },
58
+ 'type': 'Customer',
59
+ 'id': '1'
60
+ }
61
+ }
62
+ pass
63
+
64
+
65
+ @app.route('/mcp_server_executor', methods=['GET'])
66
+ def mcp_server_executor(path=None):
67
+ ''' sample response printed in mcp_client_executor.py:
68
+ FIXME - incorrect.
69
+ But do provide: https://localhost:5656/.well-known/mcp.json
70
+ ```
71
+ MCP MCP Response (simulated):
72
+ {
73
+ "get_json": {
74
+ "filter": {
75
+ "filter": {
76
+ "credit_limit": {
77
+ "gt": 4000
78
+ }
79
+ },
80
+ "headers": {
81
+ "Accept": "application/vnd.api+json",
82
+ "Authorization": "Bearer your_token"
83
+ },
84
+ "type": "Customer",
85
+ "url": "http://localhost:5656/api/Customer"
86
+ }
87
+ },
88
+ "name": "mcp_server_executor",
89
+ "openapiUrl": "TUNNEL_URL/api/openapi.json",
90
+ "serverUrl": "TUNNEL_URL/api"
91
+ }
92
+ ```
93
+ '''
94
+ get_json = request.get_json()
95
+ app_logger.info(f"mcp_server_executor sees mcp request: \n{json.dumps(get_json, indent=4)}")
96
+
97
+ # process verb, filter here (stub for now)
98
+ filter_json = get_json['filter'] # {"credit_limit": {"gt": 4000}} # todo: bunch'o parsing here
99
+
100
+ filter_json = {"name": "credit_limit", "op": "gt", "val":4000} # https://github.com/thomaxxl/safrs/wiki/JsonApi-filtering
101
+ filter = json.dumps(filter_json) # {"name": "credit_limit", "op": "gt", "val": 4000}
102
+ get_uri = get_json['url'] + '?filter=' + filter # get_uri = "http://localhost:5656/api/Customer?filter[credit_limit]=1000"
103
+ response = requests.get(url=get_uri, headers= request.headers)
104
+
105
+ return response.json(), 200, {'Content-Type': 'application/json; charset=utf-8'}
106
+
107
+
108
+ @app.route('/.well-known/mcp.json', methods=['GET'])
109
+ def mcp_discovery(path=None):
110
+ ''' called by mcp_client_executor for discovery, eg:
111
+ ```
112
+ {
113
+ "tool_type": "json-api",
114
+ "base_url": "https://crm.company.com",
115
+ "resources": [
116
+ {
117
+ "name": "Customer",
118
+ "path": "/Customer",
119
+ "methods": ["GET", "PATCH"],
120
+ "fields": ["id", "name", "balance", "credit_limit"],
121
+ "filterable": ["name", "credit_limit"],
122
+ "example": "List customers with credit over 5000"
123
+ }
124
+ ]
125
+ }
126
+ ```
127
+ test: curl -X GET "http://localhost:5656/.well-known/mcp.json"
128
+ '''
129
+ # return docs/mcp_schema.json
130
+ schema_path = os.path.join(project_dir, "docs", "mcp_schema.json")
131
+ try:
132
+ with open(schema_path, "r") as schema_file:
133
+ schema = json.load(schema_file)
134
+ return jsonify(schema), 200
135
+ except Exception as e:
136
+ app_logger.error(f"Error loading MCP schema: {e}")
137
+ return jsonify({"error": "MCP schema not found"}), 404
138
+ pass
@@ -0,0 +1,92 @@
1
+ from flask import request, jsonify
2
+ from flask import Flask, redirect, send_from_directory, send_file
3
+ import logging
4
+ import os
5
+ import json
6
+ import io
7
+ from config.config import Args # circular import error if at top
8
+
9
+ app_logger = logging.getLogger("api_logic_server_app")
10
+
11
+
12
+
13
+ def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_decorators = []):
14
+ pass
15
+
16
+ def get_server_url():
17
+ """ return the server URL for the OpenAPI spec """
18
+ result = f'http://{Args.instance.swagger_host}:{Args.instance.swagger_port}'
19
+ # get env variable API_LOGIC_SERVER_TUNNEL (or None)
20
+ if tunnel_url := os.getenv("API_LOGIC_SERVER_TUNNEL", None):
21
+ app_logger.info(f".. tunnel URL: {tunnel_url}")
22
+ result = tunnel_url
23
+ return result # + '/api'
24
+
25
+ @app.route('/mcp.json')
26
+ def mcp(path=None):
27
+ '''
28
+ test: curl -X GET http://localhost:5656/mcp.json
29
+ '''
30
+
31
+ mcp_json = {
32
+ "name": "MCP genai_demo test",
33
+ "description": "You are an AI Planner + Executor for a live JSON:API server.",
34
+ "instructions": [
35
+ "When a user gives you a natural language goal (e.g., 'list customers from Germany'), you:",
36
+ "Identify the resource (Customer, Order, Product).",
37
+ "Map filters (e.g., Country=Germany).",
38
+ "Construct a JSON:API call to the live endpoint (through a function called fetch_resource).",
39
+ "Execute the live API call through the function.",
40
+ "Format and display the results neatly."
41
+ ],
42
+ "serverUrl": "http://localhost:5656/api",
43
+ "openapiUrl": "http://localhost:5656/api/openapi.json",
44
+ "apiStandard": "JSON:API (application/vnd.api+json)"
45
+ }
46
+ mcp_json["serverUrl"] = get_server_url() + '/api'
47
+ mcp_json["openapiUrl"] = get_server_url() + '/api/openapi.json'
48
+ # return jsonify(mcp), 200, {'Content-Type': 'text/plain; charset=utf-8'}
49
+ return jsonify(mcp_json), 200, {'Content-Type': 'application/json; charset=utf-8'}
50
+
51
+
52
+ @app.route('/api/openapi.json')
53
+ def openapi(path=None):
54
+ """ return integration/openai_plugin/swagger_3.json
55
+ * with updated tunnel URL if API_LOGIC_SERVER_TUNNEL is set
56
+
57
+ test: curl -X GET http://localhost:5656/api/openapi.json
58
+ like: curl -X GET http://localhost:5656/api/swagger.json
59
+ """
60
+
61
+ # read dict from json file integration/openai_plugin/swagger_3.json
62
+ with open("integration/openai_function/swagger_3.json", "r") as json_file:
63
+ swagger_dict = json.load(json_file)
64
+ app_logger.info(f"openapi: Swagger JSON loaded: {swagger_dict}")
65
+
66
+ server_url = get_server_url()
67
+ swagger_dict["servers"][0]["url"] = server_url + '/api'
68
+
69
+ # convert dict to buffered stream
70
+ swagger_dict_mem = io.BytesIO(json.dumps(swagger_dict).encode('utf-8'))
71
+ return send_file(swagger_dict_mem, mimetype='text/json')
72
+
73
+
74
+ @app.route('/api/ai_plugin')
75
+ def ai_plugin(path=None):
76
+ """ return integration/openai_plugin/ai_plugin.json (disparaged)
77
+ * with updated tunnel URL if API_LOGIC_SERVER_TUNNEL is set
78
+
79
+ test: curl -X GET http://localhost:5656/api/ai_plugin
80
+ """
81
+
82
+ # read dict from json file integration/openai_plugin/swagger_3.json
83
+ with open("integration/openai_plugin/ai_plugin.json", "r") as json_file:
84
+ swagger_dict = json.load(json_file)
85
+ app_logger.info(f"openapi: ai_plugin JSON loaded: {swagger_dict}")
86
+
87
+ server_url = get_server_url()
88
+ swagger_dict["servers"][0]["url"] = server_url
89
+
90
+ # convert dict to buffered stream
91
+ swagger_dict_mem = io.BytesIO(json.dumps(swagger_dict).encode('utf-8'))
92
+ return send_file(swagger_dict_mem, mimetype='text/json')
@@ -0,0 +1,71 @@
1
+ {
2
+ "/Customer/{id}": {
3
+ "patch": {
4
+ "summary": "Update Customer by ID",
5
+ "operationId": "updateCustomer",
6
+ "parameters": [
7
+ {
8
+ "name": "id",
9
+ "in": "path",
10
+ "required": true,
11
+ "schema": {
12
+ "type": "string"
13
+ }
14
+ }
15
+ ],
16
+ "requestBody": {
17
+ "required": true,
18
+ "content": {
19
+ "application/vnd.api+json": {
20
+ "schema": {
21
+ "type": "object",
22
+ "required": ["data"],
23
+ "properties": {
24
+ "data": {
25
+ "type": "object",
26
+ "required": ["type", "id", "attributes"],
27
+ "properties": {
28
+ "type": {
29
+ "type": "string",
30
+ "enum": ["Customer"]
31
+ },
32
+ "id": {
33
+ "type": "string"
34
+ },
35
+ "attributes": {
36
+ "type": "object",
37
+ "properties": {
38
+ "name": {
39
+ "type": "string"
40
+ },
41
+ "credit_limit": {
42
+ "type": "number"
43
+ },
44
+ "balance": {
45
+ "type": "number"
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ },
56
+ "responses": {
57
+ "200": {
58
+ "description": "Customer updated",
59
+ "content": {
60
+ "application/vnd.api+json": {
61
+ "schema": {
62
+ "type": "object"
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+ }
71
+
@@ -0,0 +1,13 @@
1
+ SECRET_KEY = "whatnothow"
2
+ SQLALCHEMY_TRACK_MODIFICATIONS = False
3
+ SQLAlCHEMY_ECHO = False
4
+ # AGGREGATE_DEFAULTS = True
5
+ # ALL_DEFAULTS = True
6
+ # APILOGICPROJECT_KAFKA_PRODUCER = "{\"bootstrap.servers\": \"localhost:9092\"}"
7
+ # SQLALCHEMY_DATABASE_URI=db.sqlite
8
+
9
+ SECURITY_ENABLED = false
10
+
11
+ # if using tunnel for mcp, function, or ai_plugin
12
+ # eg, https://tunnel_url.ngrok-free.app
13
+ API_LOGIC_SERVER_TUNNEL = "TUNNEL_URL"
@@ -0,0 +1,131 @@
1
+ # coding: utf-8
2
+ from sqlalchemy import DECIMAL, DateTime # API Logic Server GenAI assist
3
+ from sqlalchemy import Boolean, Column, DECIMAL, Date, ForeignKey, Integer, String
4
+ from sqlalchemy.orm import relationship
5
+ from sqlalchemy.ext.declarative import declarative_base
6
+
7
+ ########################################################################################################################
8
+ # Classes describing database for SqlAlchemy ORM, initially created by schema introspection.
9
+ #
10
+ # Alter this file per your database maintenance policy
11
+ # See https://apilogicserver.github.io/Docs/Project-Rebuild/#rebuilding
12
+ #
13
+ # Created: May 14, 2025 10:47:47
14
+ # Database: sqlite:////Users/val/dev/ApiLogicServer/ApiLogicServer-dev/servers/basic_demo/database/db.sqlite
15
+ # Dialect: sqlite
16
+ #
17
+ # mypy: ignore-errors
18
+ ########################################################################################################################
19
+
20
+ from database.system.SAFRSBaseX import SAFRSBaseX, TestBase
21
+ from flask_login import UserMixin
22
+ import safrs, flask_sqlalchemy, os
23
+ from safrs import jsonapi_attr
24
+ from flask_sqlalchemy import SQLAlchemy
25
+ from sqlalchemy.orm import relationship
26
+ from sqlalchemy.orm import Mapped
27
+ from sqlalchemy.sql.sqltypes import NullType
28
+ from typing import List
29
+
30
+ db = SQLAlchemy()
31
+ Base = declarative_base() # type: flask_sqlalchemy.model.DefaultMeta
32
+ metadata = Base.metadata
33
+
34
+ #NullType = db.String # datatype fixup
35
+ #TIMESTAMP= db.TIMESTAMP
36
+
37
+ from sqlalchemy.dialects.sqlite import *
38
+
39
+ if os.getenv('APILOGICPROJECT_NO_FLASK') is None or os.getenv('APILOGICPROJECT_NO_FLASK') == 'None':
40
+ Base = SAFRSBaseX # enables rules to be used outside of Flask, e.g., test data loading
41
+ else:
42
+ Base = TestBase # ensure proper types, so rules work for data loading
43
+ print('*** Models.py Using TestBase ***')
44
+
45
+
46
+
47
+ class Customer(Base): # type: ignore
48
+ __tablename__ = 'customer'
49
+ _s_collection_name = 'Customer' # type: ignore
50
+
51
+ id = Column(Integer, primary_key=True)
52
+ name = Column(String)
53
+ balance : DECIMAL = Column(DECIMAL)
54
+ credit_limit : DECIMAL = Column(DECIMAL)
55
+ email = Column(String)
56
+ email_opt_out = Column(Boolean)
57
+
58
+ # parent relationships (access parent)
59
+
60
+ # child relationships (access children)
61
+ EmailList : Mapped[List["Email"]] = relationship(back_populates="customer")
62
+ OrderList : Mapped[List["Order"]] = relationship(back_populates="customer")
63
+
64
+
65
+
66
+ class Product(Base): # type: ignore
67
+ __tablename__ = 'product'
68
+ _s_collection_name = 'Product' # type: ignore
69
+
70
+ id = Column(Integer, primary_key=True)
71
+ name = Column(String)
72
+ unit_price : DECIMAL = Column(DECIMAL)
73
+
74
+ # parent relationships (access parent)
75
+
76
+ # child relationships (access children)
77
+ ItemList : Mapped[List["Item"]] = relationship(back_populates="product")
78
+
79
+
80
+
81
+ class Email(Base): # type: ignore
82
+ __tablename__ = 'email'
83
+ _s_collection_name = 'Email' # type: ignore
84
+
85
+ id = Column(Integer, primary_key=True)
86
+ message = Column(String)
87
+ customer_id = Column(ForeignKey('customer.id'), nullable=False)
88
+ CreatedOn = Column(Date)
89
+
90
+ # parent relationships (access parent)
91
+ customer : Mapped["Customer"] = relationship(back_populates=("EmailList"))
92
+
93
+ # child relationships (access children)
94
+
95
+
96
+
97
+ class Order(Base): # type: ignore
98
+ __tablename__ = 'order'
99
+ _s_collection_name = 'Order' # type: ignore
100
+
101
+ id = Column(Integer, primary_key=True)
102
+ notes = Column(String)
103
+ customer_id = Column(ForeignKey('customer.id'), nullable=False)
104
+ CreatedOn = Column(Date)
105
+ date_shipped = Column(Date)
106
+ amount_total : DECIMAL = Column(DECIMAL)
107
+
108
+ # parent relationships (access parent)
109
+ customer : Mapped["Customer"] = relationship(back_populates=("OrderList"))
110
+
111
+ # child relationships (access children)
112
+ ItemList : Mapped[List["Item"]] = relationship(back_populates="order")
113
+
114
+
115
+
116
+ class Item(Base): # type: ignore
117
+ __tablename__ = 'item'
118
+ _s_collection_name = 'Item' # type: ignore
119
+
120
+ id = Column(Integer, primary_key=True)
121
+ order_id = Column(ForeignKey('order.id'))
122
+ product_id = Column(ForeignKey('product.id'), nullable=False)
123
+ quantity = Column(Integer, nullable=False)
124
+ amount : DECIMAL = Column(DECIMAL)
125
+ unit_price : DECIMAL = Column(DECIMAL)
126
+
127
+ # parent relationships (access parent)
128
+ order : Mapped["Order"] = relationship(back_populates=("ItemList"))
129
+ product : Mapped["Product"] = relationship(back_populates=("ItemList"))
130
+
131
+ # child relationships (access children)