ApiLogicServer 15.0.0__py3-none-any.whl → 15.0.10__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 (37) hide show
  1. api_logic_server_cli/add_cust/add_cust.py +8 -2
  2. api_logic_server_cli/api_logic_server.py +2 -2
  3. api_logic_server_cli/api_logic_server_info.yaml +3 -3
  4. api_logic_server_cli/create_from_model/__pycache__/dbml.cpython-312.pyc +0 -0
  5. api_logic_server_cli/create_from_model/dbml.py +1 -0
  6. api_logic_server_cli/genai/genai_svcs.py +5 -2
  7. api_logic_server_cli/manager.py +1 -0
  8. api_logic_server_cli/prototypes/base/api/api_discovery/mcp_discovery.py +63 -24
  9. api_logic_server_cli/prototypes/base/config/logging.yml +5 -0
  10. api_logic_server_cli/prototypes/base/config/server_setup.py +73 -0
  11. api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_discovery_response.json +150 -0
  12. api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_request.prompt +46 -0
  13. api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_tool_context_response.json +34 -0
  14. api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_tool_context_response_get.json +18 -0
  15. api_logic_server_cli/prototypes/base/integration/mcp/mcp_client_executor.py +395 -203
  16. api_logic_server_cli/prototypes/basic_demo/customizations/logic/logic_discovery/mcp_client_executor_request.py +11 -282
  17. api_logic_server_cli/prototypes/basic_demo/customizations/ui/admin/admin.yaml +3 -3
  18. api_logic_server_cli/prototypes/basic_demo/customizations/ui/admin/home.js +48 -0
  19. api_logic_server_cli/prototypes/manager/system/genai/mcp_learning/mcp.prompt +12 -0
  20. {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.10.dist-info}/METADATA +1 -1
  21. {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.10.dist-info}/RECORD +26 -32
  22. api_logic_server_cli/prototypes/base/integration/mcp/README_mcp.md +0 -15
  23. api_logic_server_cli/prototypes/base/integration/mcp/test_notes.txt +0 -37
  24. api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/mcp_discovery.py +0 -96
  25. api_logic_server_cli/prototypes/basic_demo/customizations/config/server_setup.py +0 -388
  26. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/.DS_Store +0 -0
  27. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/README_mcp.md +0 -15
  28. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/Zmcp_client_executor.py +0 -294
  29. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_schema.txt +0 -47
  30. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_server_discovery.json +0 -9
  31. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_tool_context.json +0 -25
  32. api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/test_notes.txt +0 -37
  33. /api_logic_server_cli/prototypes/base/integration/mcp/{mcp_schema.txt → examples/mcp_schema.txt} +0 -0
  34. {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.10.dist-info}/WHEEL +0 -0
  35. {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.10.dist-info}/entry_points.txt +0 -0
  36. {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.10.dist-info}/licenses/LICENSE +0 -0
  37. {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.10.dist-info}/top_level.txt +0 -0
@@ -148,9 +148,15 @@ def add_basic_demo_customizations(project: Project, do_show_messages: bool = Tru
148
148
 
149
149
  if do_show_messages:
150
150
  log.info("\nExplore key customization files:")
151
- log.info(f'..logic/declare_logic.py')
151
+ log.info('\033[94m\033[1m..logic/declare_logic.py\033[0m')
152
152
  log.info(f'..security/declare_security.py\n')
153
- log.info(f'Explore MCP (Model Context Protocol): https://apilogicserver.github.io/Docs/Integration-MCP/\n')
153
+ # Make the message blue, bold, and add an attention-getting icon
154
+ log.info('\033[94m\033[1m🔷 Explore MCP (Model Context Protocol): https://apilogicserver.github.io/Docs/Integration-MCP/\033[0m\n')
155
+ log.info('.. restart the server')
156
+ log.info('python integration/mcp/mcp_client_executor.py mcp')
157
+ # log.info(".. Copy/paste this into your terminal (Mac/Linux):")
158
+ # log.info(".. curl -X 'POST' 'http://localhost:5656/api/SysMcp/' -H 'accept: application/vnd.api+json' -H 'Content-Type: application/json' -d '{ \"data\": { \"attributes\": {\"request\": \"List the orders date_shipped is null and CreatedOn before 2023-07-14, and send a discount email (subject: '\\''Discount Offer'\\'') to the customer for each one.\"}, \"type\": \"SysMcp\"}}'")
159
+ log.info('')
154
160
  log.info(f'Next Steps: activate security')
155
161
  log.info(f'..ApiLogicServer add-auth --db_url=auth')
156
162
  if project.is_tutorial == False:
@@ -12,10 +12,10 @@ ApiLogicServer CLI: given a database url, create [and run] customizable ApiLogic
12
12
  Called from api_logic_server_cli.py, by instantiating the ProjectRun object.
13
13
  '''
14
14
 
15
- __version__ = "15.00.00" # last public release: 15.00.00 (14.05.04)
15
+ __version__ = "15.00.10" # last public release: 15.00.10 (15.00.00)
16
16
  recent_changes = \
17
17
  f'\n\nRecent Changes:\n' +\
18
- "\t05/28/2024 - 15.00.00: MCP \n"\
18
+ "\t06/08/2024 - 15.00.10: MCP, optional shortening of stacktrace lines, bugfix[92] \n"\
19
19
  "\t05/16/2024 - 14.05.00: safrs 3.1.7, running mcp preview \n"\
20
20
  "\t04/27/2024 - 14.04.00: Graphics preview, Vibe install fix, Improved IDE Chat Logic, MCP Exploration \n"\
21
21
  "\t03/30/2024 - 14.03.25: WebGenAI fixes for Kafka and Keycloak \n"\
@@ -1,3 +1,3 @@
1
- last_created_date: May 28, 2025 12:08:45
2
- last_created_project_name: /Users/val/dev/ApiLogicServer/ApiLogicServer-dev/servers/basic_demo
3
- last_created_version: 14.05.16
1
+ last_created_date: June 08, 2025 16:06:20
2
+ last_created_project_name: samples/nw_sample_nocust
3
+ last_created_version: 15.00.09
@@ -207,6 +207,7 @@ class DBMLCreator(object):
207
207
  '''
208
208
  """
209
209
 
210
+ # copy mcp learning from manager (to enable user to extend)
210
211
  docs_path = Path(self.mod_gen.project_directory).joinpath('docs')
211
212
  docs_path.mkdir(parents=True, exist_ok=True)
212
213
  mcp_learning_src = genai_svcs.get_manager_path(use_env=True).joinpath('system/genai/mcp_learning')
@@ -152,8 +152,11 @@ def get_code_update_logic_file(rule_list: List[DotMap], logic_file_path: Path =
152
152
  project (Project): a Project object (unless creating a logic file)
153
153
  imports (set): the set of imported classes
154
154
  """
155
- insert_logic = "\n # Logic from GenAI: (or, use your IDE w/ code completion)\n"
156
- insert_logic += translated_logic
155
+ insert_logic = "\n # Logic from GenAI: (or, use your IDE with code completion)\n"
156
+ insert_import = translated_logic
157
+ if 'import \n' in translated_logic:
158
+ insert_import = " # no rules"
159
+ insert_logic += insert_import
157
160
  insert_logic += "\n # End Logic from GenAI\n\n"
158
161
 
159
162
  insert_point = 'discover_logic()' # default for als`
@@ -19,6 +19,7 @@ def create_manager(clean: bool, open_with: str, api_logic_server_path: Path,
19
19
  1. .vscode, readme
20
20
  2. System folder (GenAI sample prompts / responses, others TBD)
21
21
  3. pre-created samples (optional)
22
+ 4. readme (from docs: Sample-Basic-Tour.md)
22
23
 
23
24
  Example, from CLI in directory containing a `venv` (see https://apilogicserver.github.io/Docs/Manager/):
24
25
  als start
@@ -1,9 +1,8 @@
1
1
  from flask import request, jsonify
2
- from flask import Flask, redirect, send_from_directory, send_file
3
2
  import logging
4
3
  import os
5
4
  import json
6
- import io
5
+ from pathlib import Path
7
6
 
8
7
  import requests
9
8
  from config.config import Args # circular import error if at top
@@ -23,36 +22,76 @@ def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_deco
23
22
  return result # + '/api'
24
23
 
25
24
 
25
+ @app.before_request
26
+ def before_any_request():
27
+ # print(f"[DEBUG] Incoming request: {request.method} {request.url}")
28
+ if activate_openapi_logging := False:
29
+ if request.content_type == 'application/json' and request.method in ['POST', 'PUT', 'PATCH']:
30
+ # openapi: Incoming request: PATCH http://localhost:5656/api/Customer/1/ {'data': {'attributes': {'credit_limit': 5555}, 'type': 'Customer', 'id': '1'}}
31
+ # openapi: Incoming request: PATCH http://6f6f-2601-644-4900-d6f0-ecc9-6df3-8863-c5b2.ngrok-free.app/api/Customer/1 {'credit_limit': 5555}
32
+
33
+ app_logger.info(f"openapi: Incoming request: {request.method} {request.url} {str(request.json)}")
34
+ else:
35
+ app_logger.info(f"openapi: Incoming request: {request.method} {request.url}")
36
+ # app_logger.info(f"openapi: Incoming request headers: {request.headers}")
37
+
38
+ chatgpt_request_json = {
39
+ "credit_limit": 25000,
40
+ }
41
+ standard_request_json = {
42
+ "data": {
43
+ "type": "Customer",
44
+ "id": "ALFKI",
45
+ "attributes": {
46
+ "name": "Alice",
47
+ "credit_limit": 25000,
48
+ "balance": 12345
49
+ }
50
+ }
51
+ }
52
+ swagger_request_json = {
53
+ 'data': {
54
+ 'attributes': {
55
+ 'credit_limit': 5555
56
+ },
57
+ 'type': 'Customer',
58
+ 'id': '1'
59
+ }
60
+ }
61
+ pass
62
+
26
63
 
27
64
  @app.route('/.well-known/mcp.json', methods=['GET'])
28
65
  def mcp_discovery(path=None):
29
- ''' called by mcp_client_executor for discovery, eg:
30
- ```
31
- {
32
- "tool_type": "json-api",
33
- "schema_version": "1.0",
34
- "base_url": "https://crm.company.com",
35
- "resources": [
36
- {
37
- "name": "Customer",
38
- "path": "/Customer",
39
- "methods": ["GET", "PATCH"],
40
- "fields": ["id", "name", "balance", "credit_limit"],
41
- "filterable": ["name", "credit_limit"],
42
- "example": "List customers with credit over 5000"
43
- }
44
- ]
45
- }
46
- ```
47
- test: curl -X GET "http://localhost:5656/.well-known/mcp.json"
66
+ ''' called by mcp_client_executor for discovery; read docs/mcp_learning/ for:
67
+ 1. learning, including fan-out & response format, and email requests.
68
+ 2. schema
69
+
70
+ see: https://apilogicserver.github.io/Docs/Integration-MCP/#1-discovery
71
+
72
+ test: curl -X GET "http://localhost:5656/.well-known/mcp.json"
48
73
  '''
49
74
  # return docs/mcp_schema.json
50
- schema_path = os.path.join(project_dir, "docs/mcp_learning/mcp_schema.json")
75
+ mcp_learning_path = Path(project_dir + "/docs/mcp_learning")
51
76
  try:
77
+ schema_path = mcp_learning_path.joinpath('mcp_schema.json')
78
+ if not schema_path.exists():
79
+ return jsonify({"error": "System Error - /docs/mcp_learning/mcp_schema.json not found"}), 404
52
80
  with open(schema_path, "r") as schema_file:
53
81
  schema = json.load(schema_file)
54
- return jsonify(schema), 200
55
82
  except Exception as e:
56
83
  app_logger.error(f"Error loading MCP schema: {e}")
57
84
  return jsonify({"error": "MCP schema not found"}), 404
58
- pass
85
+
86
+ try:
87
+ learnings_path = mcp_learning_path.joinpath('mcp.prompt')
88
+ if not learnings_path.exists():
89
+ return jsonify({"error": "System Error - /docs/mcp_learning/mcp,prompt not found"}), 404
90
+ with open(learnings_path, "r") as learnings_file:
91
+ learnings = learnings_file.read()
92
+ except Exception as e:
93
+ app_logger.error(f"Error loading MCP learnings: {e}")
94
+ return jsonify({"error": "MCP learnings not found"}), 404
95
+ schema['learning'] = learnings
96
+
97
+ return jsonify(schema), 200
@@ -87,6 +87,11 @@ loggers:
87
87
  handlers: [console]
88
88
  propagate: no
89
89
 
90
+ integration.mcp:
91
+ level: DEBUG
92
+ handlers: [console]
93
+ propagate: no
94
+
90
95
  integration.n8n:
91
96
  level: DEBUG
92
97
  handlers: [console]
@@ -174,6 +174,75 @@ def get_args(flask_app: Flask) -> Args:
174
174
  # LOGGING SETUP
175
175
  # ==================================
176
176
 
177
+ import site
178
+
179
+ # Auto-detect venv site-packages path
180
+ import logging
181
+ import site
182
+
183
+ venv_path = site.getsitepackages()[0]
184
+ venv_alias = "$venv"
185
+ app_path = str(Path(__file__).parent.parent)
186
+ app_alias = ""
187
+ max_len = 100 # max length of a line in stacktrace
188
+
189
+ # Patch stacktrace formatters to replace venv path with alias
190
+ def patch_stacktrace_formatters():
191
+ """
192
+ Patch only the formatException method of each formatter,
193
+ so only stacktraces are affected, not normal log lines.
194
+ """
195
+ import logging
196
+
197
+ def short_format_exception(self, exc_info):
198
+ result = logging.Formatter.formatException(self, exc_info)
199
+ lines = result.splitlines('\n')
200
+ line_num = 0
201
+ for each_line in lines:
202
+ follow_link = ""
203
+ if '1906' in each_line:
204
+ pass # good breakpoint
205
+ if venv_path in each_line:
206
+ # get the string inside the double quotes
207
+ if '"' in each_line:
208
+ follow_link = '\tFollow link: ' + each_line.split('"')[1] + ']'
209
+ # Replace the venv_path with venv_alias in the stacktrace line
210
+ each_line = each_line.replace('"' + venv_path, venv_alias)
211
+ each_line = each_line.replace('File ', '') # replace project path with name
212
+ each_line = each_line.replace('", line ', ' @ ')
213
+ each_line = each_line.replace('^', '')
214
+ each_line = each_line.replace('\n', '')
215
+ lines[line_num] = each_line
216
+ elif app_path in each_line:
217
+ if '"' in each_line:
218
+ follow_link = '\tFollow link: ' + each_line.split('"')[1] + ']'
219
+ each_line = each_line.replace('"' + app_path, app_alias)
220
+ each_line = each_line.replace('File ', '')
221
+ each_line = each_line.replace('", line ', ' @ ')
222
+ each_line = each_line.replace('\n', '')
223
+ lines[line_num] = each_line
224
+ elif '^^' in each_line:
225
+ lines[line_num] = ""
226
+ elif 'File "<string>", line' in each_line:
227
+ lines[line_num] = ""
228
+ # add spaces for 90 characters
229
+ if len(lines[line_num]) < max_len and lines[line_num] != "" and follow_link != "":
230
+ lines[line_num] = lines[line_num] + ' ' * (max_len - len(lines[line_num]))
231
+ lines[line_num] += follow_link
232
+ line_num += 1
233
+ result = ''.join(lines)
234
+ return result
235
+
236
+ # Patch the formatException method of all formatters in the root logger
237
+
238
+ root_logger = logging.getLogger()
239
+ for handler in root_logger.handlers:
240
+ fmt = handler.formatter
241
+ if fmt and not hasattr(fmt, "_stacktrace_patched"):
242
+ fmt.formatException = short_format_exception.__get__(fmt)
243
+ fmt._stacktrace_patched = True
244
+
245
+
177
246
  def logging_setup() -> logging.Logger:
178
247
  """
179
248
  Setup Logging
@@ -187,6 +256,10 @@ def logging_setup() -> logging.Logger:
187
256
  f.close()
188
257
  logging.config.dictConfig(config) # log levels: notset 0, debug 10, info 20, warn 30, error 40, critical 50
189
258
  app_logger = logging.getLogger("api_logic_server_app")
259
+
260
+ if do_truncate_venv_path := True: # use False for standard Python logging in stacktrace
261
+ patch_stacktrace_formatters()
262
+
190
263
  debug_value = os.getenv('APILOGICPROJECT_DEBUG')
191
264
  if debug_value is not None: # > export APILOGICPROJECT_DEBUG=True
192
265
  debug_value = debug_value.upper()
@@ -0,0 +1,150 @@
1
+ {
2
+ "http://localhost:5656/.well-known/mcp.json": {
3
+ "base_url": "http://localhost:5656/api",
4
+ "description": "API Logic Project: basic_demo",
5
+ "learning": [
6
+ "To issue one request per row from a prior step (fan-out), use the syntax:",
7
+ "",
8
+ "\"$<stepIndex>[*].<fieldName>\"",
9
+ "",
10
+ "For example, if step 0 returns orders, and you want to send a POST per customer:",
11
+ "",
12
+ "Before (incorrect):",
13
+ " \"customer_id\": \"{customer_id}\"",
14
+ "",
15
+ "After (correct):",
16
+ " \"customer_id\": \"$0[*].customer_id\"",
17
+ "",
18
+ "Only if 'email' is in the Natural language query, send email by issing a POST request to the SysEmail endpoint, setting the subject, message and customer_id in the body. DO NOT include a POST unless the word ‘email’ appears in the user query.",
19
+ "",
20
+ "Format response as mcp_responseFormat.",
21
+ "",
22
+ "<mcp_responseFormat>",
23
+ "class QueryParam(BaseModel):",
24
+ " name: str # attribute name",
25
+ " op: str # eq, lt, gt",
26
+ " val: str",
27
+ "",
28
+ "class JsonValues(BaseModel):",
29
+ " name: str # name of attribute",
30
+ " value: str # value of attribute",
31
+ "",
32
+ "class Resource(BaseModel):",
33
+ " tool_type: str",
34
+ " base_url: str",
35
+ " path: str # specified use case or requirement name (use 'General' if missing)",
36
+ " method: str # GET, PATCH, POST or DELETE",
37
+ " body: json # data for PATCH or POST",
38
+ " query_params: List(QueryParam) # filter for GET",
39
+ "",
40
+ "class MCPResult(BaseModel): # must match system/genai/prompt_inserts/response_format.prompt",
41
+ " schema_version: str",
42
+ " resources : List[Resource] # list resources",
43
+ "",
44
+ "<mcp_responseFormat/>",
45
+ ""
46
+ ],
47
+ "resources": [
48
+ {
49
+ "fields": [
50
+ "id",
51
+ "name",
52
+ "balance",
53
+ "credit_limit",
54
+ "email",
55
+ "email_opt_out"
56
+ ],
57
+ "filterable": [
58
+ "id",
59
+ "name",
60
+ "balance",
61
+ "credit_limit",
62
+ "email",
63
+ "email_opt_out"
64
+ ],
65
+ "methods": [
66
+ "GET",
67
+ "PATCH",
68
+ "POST",
69
+ "DELETE"
70
+ ],
71
+ "name": "Customer",
72
+ "path": "/Customer"
73
+ },
74
+ {
75
+ "fields": [
76
+ "id",
77
+ "order_id",
78
+ "product_id",
79
+ "quantity",
80
+ "amount",
81
+ "unit_price"
82
+ ],
83
+ "filterable": [
84
+ "id",
85
+ "order_id",
86
+ "product_id",
87
+ "quantity",
88
+ "amount",
89
+ "unit_price"
90
+ ],
91
+ "methods": [
92
+ "GET",
93
+ "PATCH",
94
+ "POST",
95
+ "DELETE"
96
+ ],
97
+ "name": "Item",
98
+ "path": "/Item"
99
+ },
100
+ {
101
+ "fields": [
102
+ "id",
103
+ "notes",
104
+ "customer_id",
105
+ "CreatedOn",
106
+ "date_shipped",
107
+ "amount_total"
108
+ ],
109
+ "filterable": [
110
+ "id",
111
+ "notes",
112
+ "customer_id",
113
+ "CreatedOn",
114
+ "date_shipped",
115
+ "amount_total"
116
+ ],
117
+ "methods": [
118
+ "GET",
119
+ "PATCH",
120
+ "POST",
121
+ "DELETE"
122
+ ],
123
+ "name": "Order",
124
+ "path": "/Order"
125
+ },
126
+ {
127
+ "fields": [
128
+ "id",
129
+ "name",
130
+ "unit_price"
131
+ ],
132
+ "filterable": [
133
+ "id",
134
+ "name",
135
+ "unit_price"
136
+ ],
137
+ "methods": [
138
+ "GET",
139
+ "PATCH",
140
+ "POST",
141
+ "DELETE"
142
+ ],
143
+ "name": "Product",
144
+ "path": "/Product"
145
+ }
146
+ ],
147
+ "schema_version": "1.0",
148
+ "tool_type": "json-api"
149
+ }
150
+ }
@@ -0,0 +1,46 @@
1
+ Natural language query:
2
+ List the orders date_shipped is null and CreatedOn before 2023-07-14, and send a discount email (subject: 'Discount Offer') to the customer for each one.
3
+
4
+ Learnings_and_Schema:
5
+ {"base_url": "http://localhost:5656/api",
6
+ "description": "API Logic Project: basic_demo",
7
+ "learning": "To issue one request per row from a prior step (fan-out), use the syntax:
8
+
9
+ "$<stepIndex>[*].<fieldName>"
10
+
11
+ For example, if step 0 returns orders, and you want to send a POST per customer:
12
+
13
+ Before (incorrect):
14
+ "customer_id": "{customer_id}"
15
+
16
+ After (correct):
17
+ "customer_id": "$0[*].customer_id"
18
+
19
+ Only if 'email' is in the Natural language query, send email by issing a POST request to the SysEmail endpoint, setting the subject, message and customer_id in the body. DO NOT include a POST unless the word u2018emailu2019 appears in the user query.
20
+
21
+ Format response as mcp_responseFormat.
22
+
23
+ <mcp_responseFormat>
24
+ class QueryParam(BaseModel):
25
+ name: str # attribute name
26
+ op: str # eq, lt, gt
27
+ val: str
28
+
29
+ class JsonValues(BaseMopdel):
30
+ name: str # name of attribute
31
+ value: str # value of attribute
32
+
33
+ class Resource(BaseModel):
34
+ tool_type: str
35
+ base_url: str
36
+ path: str # specified use case or requirement name (use 'General' if missing)
37
+ method: str # GET, PATCH, POST or DELETE
38
+ body: json # data for PATCH or POST
39
+ query_params: List(QueryParam) # filter for GET
40
+
41
+ class MCPResult(BaseModel): # must match system/genai/prompt_inserts/response_format.prompt
42
+ schema_version: str
43
+ resources : List[Resource] # list resources
44
+
45
+ <mcp_responseFormat/>
46
+ ", "resources": [{"fields": ["id", "name", "balance", "credit_limit", "email", "email_opt_out"], "filterable": ["id", "name", "balance", "credit_limit", "email", "email_opt_out"], "methods": ["GET", "PATCH", "POST", "DELETE"], "name": "Customer", "path": "/Customer"}, {"fields": ["id", "order_id", "product_id", "quantity", "amount", "unit_price"], "filterable": ["id", "order_id", "product_id", "quantity", "amount", "unit_price"], "methods": ["GET", "PATCH", "POST", "DELETE"], "name": "Item", "path": "/Item"}, {"fields": ["id", "notes", "customer_id", "CreatedOn", "date_shipped", "amount_total"], "filterable": ["id", "notes", "customer_id", "CreatedOn", "date_shipped", "amount_total"], "methods": ["GET", "PATCH", "POST", "DELETE"], "name": "Order", "path": "/Order"}, {"fields": ["id", "name", "unit_price"], "filterable": ["id", "name", "unit_price"], "methods": ["GET", "PATCH", "POST", "DELETE"], "name": "Product", "path": "/Product"}], "schema_version": "1.0", "tool_type": "json-api"}
@@ -0,0 +1,34 @@
1
+ {
2
+ "schema_version": "1.0",
3
+ "resources": [
4
+ {
5
+ "tool_type": "json-api",
6
+ "base_url": "http://localhost:5656/api",
7
+ "path": "/Order",
8
+ "method": "GET",
9
+ "query_params": [
10
+ {
11
+ "name": "date_shipped",
12
+ "op": "eq",
13
+ "val": "null"
14
+ },
15
+ {
16
+ "name": "CreatedOn",
17
+ "op": "lt",
18
+ "val": "2023-07-14"
19
+ }
20
+ ]
21
+ },
22
+ {
23
+ "tool_type": "json-api",
24
+ "base_url": "http://localhost:5656/api",
25
+ "path": "/SysEmail",
26
+ "method": "POST",
27
+ "body": {
28
+ "subject": "Discount Offer",
29
+ "message": "Dear customer, we are offering a discount on your next purchase. Please check your account for more details.",
30
+ "customer_id": "$0[*].customer_id"
31
+ }
32
+ }
33
+ ]
34
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "schema_version": "1.0",
3
+ "resources": [
4
+ {
5
+ "tool_type": "json-api",
6
+ "base_url": "http://localhost:5656/api",
7
+ "path": "/Customer",
8
+ "method": "GET",
9
+ "query_params": [
10
+ {
11
+ "name": "credit_limit",
12
+ "op": "gt",
13
+ "val": "1000"
14
+ }
15
+ ]
16
+ }
17
+ ]
18
+ }