api-foundry-query-engine 0.8.30__tar.gz → 0.8.31__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.
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/PKG-INFO +2 -1
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/adapters/adapter.py +1 -1
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/adapters/case_change_adapter.py +1 -1
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/adapters/gateway_adapter.py +23 -35
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/adapters/security_adapter.py +2 -2
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/connectors/connection_factory.py +6 -6
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/connectors/oracle_connector.py +1 -1
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/connectors/postgres_connection.py +1 -1
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/dao/sql_custom_query_handler.py +1 -1
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/dao/sql_delete_query_handler.py +1 -1
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/dao/sql_insert_query_handler.py +1 -1
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/dao/sql_query_handler.py +9 -4
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/lambda_handler.py +7 -6
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/operation.py +31 -14
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/services/service.py +12 -6
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/services/transactional_service.py +2 -2
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/utils/api_model.py +2 -2
- api_foundry_query_engine-0.8.31/api_foundry_query_engine/utils/claims_check.py +471 -0
- api_foundry_query_engine-0.8.31/api_foundry_query_engine/utils/gateway_operation.py +279 -0
- api_foundry_query_engine-0.8.31/api_foundry_query_engine/utils/token_decoder.py +415 -0
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/pyproject.toml +38 -2
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/.gitignore +0 -0
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/LICENSE +0 -0
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/.pre-commit-config.yaml +0 -0
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/__init__.py +0 -0
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/connectors/connection.py +0 -0
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/dao/dao.py +0 -0
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/dao/operation_dao.py +0 -0
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/dao/sql_select_query_handler.py +0 -0
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/dao/sql_subselect_query_handler.py +0 -0
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/dao/sql_update_query_handler.py +0 -0
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/utils/app_exception.py +0 -0
- {api_foundry_query_engine-0.8.30 → api_foundry_query_engine-0.8.31}/api_foundry_query_engine/utils/logger.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: api-foundry-query-engine
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.31
|
|
4
4
|
Summary: The AWS lambda service handler use by the `api_foundry` project is a powerful tool designed to automate the deployment of REST APIs on AWS using Lambda services to access and interact with relational databases (RDBMS). This project leverages the OpenAPI specification to define and manage the APIs
|
|
5
5
|
Project-URL: Documentation, https://github.com/DanRepik/api-foundry
|
|
6
6
|
Project-URL: Source, https://github.com/DanRepik/api-foundry
|
|
@@ -18,3 +18,4 @@ Requires-Dist: fixture-foundry>=0.1.0; extra == 'dev'
|
|
|
18
18
|
Requires-Dist: isort>=5.12.0; extra == 'dev'
|
|
19
19
|
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
20
20
|
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
21
|
+
Requires-Dist: simple-oauth-server; extra == 'dev'
|
|
@@ -30,7 +30,7 @@ class CaseChangeAdapter(Adapter):
|
|
|
30
30
|
or self.__check_camel_case(operation.store_params)
|
|
31
31
|
or self.__check_camel_case(operation.query_params)
|
|
32
32
|
)
|
|
33
|
-
log.info(
|
|
33
|
+
log.info("camel_case: %s", self.camel_case)
|
|
34
34
|
|
|
35
35
|
if self.camel_case:
|
|
36
36
|
return Operation(
|
|
@@ -65,38 +65,30 @@ class GatewayAdapter(Adapter):
|
|
|
65
65
|
if body is not None and len(body) > 0:
|
|
66
66
|
store_params = json.loads(body)
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
claims =
|
|
70
|
-
|
|
71
|
-
#
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
permissions_raw = claims.get("permissions", [])
|
|
91
|
-
if isinstance(permissions_raw, str):
|
|
92
|
-
try:
|
|
93
|
-
permissions = json.loads(permissions_raw)
|
|
94
|
-
except (json.JSONDecodeError, TypeError):
|
|
95
|
-
permissions = []
|
|
68
|
+
# Extract JWT claims from API Gateway event
|
|
69
|
+
claims = event.get("requestContext", {}).get("authorizer", {})
|
|
70
|
+
|
|
71
|
+
# Handle different authorizer types
|
|
72
|
+
if isinstance(claims, dict):
|
|
73
|
+
# TOKEN authorizer puts claims directly in authorizer object
|
|
74
|
+
if "sub" in claims or "iss" in claims:
|
|
75
|
+
# Already have JWT claims at top level
|
|
76
|
+
pass
|
|
77
|
+
elif "claims" in claims:
|
|
78
|
+
# Some configurations nest claims
|
|
79
|
+
claims = claims["claims"]
|
|
80
|
+
elif "iam" in claims:
|
|
81
|
+
# IAM authorizer fallback
|
|
82
|
+
claims = claims["iam"]
|
|
83
|
+
elif "lambda" in claims:
|
|
84
|
+
# Lambda authorizer fallback
|
|
85
|
+
claims = claims["lambda"]
|
|
86
|
+
else:
|
|
87
|
+
# Empty or unknown format
|
|
88
|
+
claims = {}
|
|
96
89
|
else:
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
subject = claims.get("sub")
|
|
90
|
+
# Non-dict authorizer context
|
|
91
|
+
claims = {}
|
|
100
92
|
scope_str = claims.get("scope")
|
|
101
93
|
|
|
102
94
|
# Enforce OAuth scopes (simulating API Gateway authorizer behavior)
|
|
@@ -132,10 +124,6 @@ class GatewayAdapter(Adapter):
|
|
|
132
124
|
store_params=store_params,
|
|
133
125
|
query_params=query_params,
|
|
134
126
|
metadata_params=metadata_params,
|
|
135
|
-
roles=roles,
|
|
136
|
-
groups=groups,
|
|
137
|
-
subject=subject,
|
|
138
|
-
permissions=permissions,
|
|
139
127
|
claims=claims,
|
|
140
128
|
)
|
|
141
129
|
|
|
@@ -99,8 +99,8 @@ class SecurityAdapter(Adapter):
|
|
|
99
99
|
try:
|
|
100
100
|
operation = self.unmarshal(event)
|
|
101
101
|
result = self.service.execute(operation)
|
|
102
|
-
log.debug(
|
|
102
|
+
log.debug("adapter result: %s", result)
|
|
103
103
|
return self.marshal(result)
|
|
104
104
|
except PermissionError as e:
|
|
105
|
-
log.error(
|
|
105
|
+
log.error("Permission error: %s", e)
|
|
106
106
|
return {"error": str(e), "status": "permission_denied"}
|
|
@@ -32,7 +32,7 @@ class ConnectionFactory:
|
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
34
|
# Get the secret name based on the engine and database from the secrets map
|
|
35
|
-
log.info(
|
|
35
|
+
log.info("database: %s", database)
|
|
36
36
|
db_config = self.db_config_map.get(database)
|
|
37
37
|
if not db_config:
|
|
38
38
|
# Use config dict for secrets
|
|
@@ -40,7 +40,7 @@ class ConnectionFactory:
|
|
|
40
40
|
if isinstance(secrets_map, str):
|
|
41
41
|
secrets_map = json.loads(secrets_map)
|
|
42
42
|
secret_name = secrets_map.get(database)
|
|
43
|
-
log.debug(
|
|
43
|
+
log.debug("secret_name: %s", secret_name)
|
|
44
44
|
|
|
45
45
|
if secret_name:
|
|
46
46
|
db_config = self.__get_secret(secret_name)
|
|
@@ -79,7 +79,7 @@ class ConnectionFactory:
|
|
|
79
79
|
sts_client = boto3.client("sts", endpoint_url=endpoint_url)
|
|
80
80
|
|
|
81
81
|
secret_account_id = self.config.get("SECRET_ACCOUNT_ID", None)
|
|
82
|
-
log.debug(
|
|
82
|
+
log.debug("secret_account_id: %s", secret_account_id)
|
|
83
83
|
|
|
84
84
|
if secret_account_id:
|
|
85
85
|
# If a secret account ID is provided, assume a role in that account
|
|
@@ -100,16 +100,16 @@ class ConnectionFactory:
|
|
|
100
100
|
)
|
|
101
101
|
else:
|
|
102
102
|
# If no secret account ID is provided, use the default account
|
|
103
|
-
log.info(
|
|
103
|
+
log.info("endpoint_url: %s", endpoint_url)
|
|
104
104
|
secretsmanager = boto3.client(
|
|
105
105
|
"secretsmanager",
|
|
106
106
|
endpoint_url=endpoint_url,
|
|
107
107
|
)
|
|
108
108
|
|
|
109
109
|
# Get the secret value from AWS Secrets Manager
|
|
110
|
-
log.info(
|
|
110
|
+
log.info("db_secret_name: %s", db_secret_name)
|
|
111
111
|
db_secret = secretsmanager.get_secret_value(SecretId=db_secret_name)
|
|
112
|
-
log.debug(
|
|
112
|
+
log.debug("loading secret name: %s", db_secret)
|
|
113
113
|
|
|
114
114
|
# Return the parsed JSON secret string
|
|
115
115
|
return json.loads(db_secret.get("SecretString"))
|
|
@@ -15,7 +15,7 @@ class OracleConnnector(Connector):
|
|
|
15
15
|
def execute(self, cursor, sql: str, parameters: dict):
|
|
16
16
|
from oracledb import Error, IntegrityError, ProgrammingError
|
|
17
17
|
|
|
18
|
-
log.debug(
|
|
18
|
+
log.debug("sql: %s, parameters: %s", sql, parameters)
|
|
19
19
|
try:
|
|
20
20
|
cursor.execute(sql, parameters)
|
|
21
21
|
except IntegrityError as err:
|
|
@@ -39,7 +39,7 @@ class SQLCustomQueryHandler(SQLQueryHandler):
|
|
|
39
39
|
self._selection_results = self.check_permissions(
|
|
40
40
|
"read", self.path_operation.permissions, self.path_operation.outputs
|
|
41
41
|
)
|
|
42
|
-
log.debug(
|
|
42
|
+
log.debug("selection_results: %s", self._selection_results)
|
|
43
43
|
return self._selection_results
|
|
44
44
|
|
|
45
45
|
def _compile(self):
|
|
@@ -31,7 +31,7 @@ class SQLDeleteSchemaQueryHandler(SQLSchemaQueryHandler):
|
|
|
31
31
|
|
|
32
32
|
for role in self.operation.roles:
|
|
33
33
|
role_permissions = self.schema_object.permissions.get(role, {})
|
|
34
|
-
log.info(
|
|
34
|
+
log.info("role: %s, role_permissions: %s", role, role_permissions)
|
|
35
35
|
if len(role_permissions) == 0:
|
|
36
36
|
continue
|
|
37
37
|
allowed = role_permissions.get("delete", False)
|
|
@@ -78,7 +78,7 @@ class SQLInsertSchemaQueryHandler(SQLSchemaQueryHandler):
|
|
|
78
78
|
for k, v in self.schema_object.properties.items()
|
|
79
79
|
if k in allowed_property_names
|
|
80
80
|
}
|
|
81
|
-
log.info(
|
|
81
|
+
log.info("allowed properties: %s", allowed_properties)
|
|
82
82
|
|
|
83
83
|
import json
|
|
84
84
|
|
|
@@ -187,10 +187,15 @@ class SQLQueryHandler:
|
|
|
187
187
|
return properties
|
|
188
188
|
|
|
189
189
|
allowed_properties = {}
|
|
190
|
+
log.info(
|
|
191
|
+
"Input properties keys: %s",
|
|
192
|
+
list(properties.keys()) if properties else "None",
|
|
193
|
+
)
|
|
194
|
+
log.info("Operation roles: %s", self.operation.roles)
|
|
190
195
|
|
|
191
196
|
for role in self.operation.roles:
|
|
192
197
|
role_permissions = permissions.get(role, {})
|
|
193
|
-
log.info(
|
|
198
|
+
log.info("role: %s, role_permissions: %s", role, role_permissions)
|
|
194
199
|
if len(role_permissions) == 0:
|
|
195
200
|
continue
|
|
196
201
|
|
|
@@ -201,13 +206,13 @@ class SQLQueryHandler:
|
|
|
201
206
|
write_pattern = self._extract_permission_pattern(write_perm)
|
|
202
207
|
|
|
203
208
|
for prop_name, property in properties.items():
|
|
204
|
-
log.info(
|
|
209
|
+
log.info("prop_name: %s, property: %s", prop_name, property)
|
|
205
210
|
if permission_type == "read" and re.match(read_pattern, prop_name):
|
|
206
211
|
allowed_properties[prop_name] = property
|
|
207
212
|
if permission_type == "write" and re.match(write_pattern, prop_name):
|
|
208
213
|
allowed_properties[prop_name] = property
|
|
209
214
|
|
|
210
|
-
log.info(
|
|
215
|
+
log.info("allowed_properties: %s", allowed_properties)
|
|
211
216
|
return allowed_properties
|
|
212
217
|
|
|
213
218
|
def _extract_permission_pattern(self, permission_rule) -> str:
|
|
@@ -381,7 +386,7 @@ class SQLSchemaQueryHandler(SQLQueryHandler):
|
|
|
381
386
|
"""
|
|
382
387
|
log.info("selection_result")
|
|
383
388
|
if not hasattr(self, "__selection_results"):
|
|
384
|
-
log.info(
|
|
389
|
+
log.info("prefix_map: %s", self.prefix_map)
|
|
385
390
|
filters = self.operation.metadata_params.get("_properties", ".*").split()
|
|
386
391
|
allowed_properties = self.check_permissions(
|
|
387
392
|
"read", self.schema_object.permissions, self.schema_object.properties
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import Mapping, Any
|
|
5
5
|
|
|
6
6
|
from api_foundry_query_engine.utils.api_model import set_api_model
|
|
7
7
|
from api_foundry_query_engine.utils.app_exception import ApplicationException
|
|
8
8
|
from api_foundry_query_engine.adapters.gateway_adapter import GatewayAdapter
|
|
9
|
+
from api_foundry_query_engine.utils.token_decoder import token_decoder
|
|
10
|
+
from api_foundry_query_engine.utils.claims_check import claims_check
|
|
9
11
|
|
|
12
|
+
logging.basicConfig(level=os.getenv("LOG_LEVEL", "INFO"))
|
|
10
13
|
log = logging.getLogger(__name__)
|
|
11
14
|
|
|
12
15
|
|
|
@@ -44,15 +47,13 @@ class QueryEngine:
|
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
@token_decoder()
|
|
51
|
+
@claims_check()
|
|
51
52
|
def handler(event, _):
|
|
52
53
|
if not hasattr(handler, "engine_config"):
|
|
53
54
|
log.info("Loading engine config from environment variables")
|
|
54
55
|
handler.engine_config = os.environ
|
|
55
|
-
log.info(
|
|
56
|
+
log.info("engine_config: %s", handler.engine_config)
|
|
56
57
|
|
|
57
58
|
if not hasattr(handler, "query_engine"):
|
|
58
59
|
set_api_model(handler.engine_config)
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
from typing import Any, Dict, List, Optional
|
|
2
2
|
|
|
3
|
+
from api_foundry_query_engine.utils.logger import logger
|
|
4
|
+
|
|
5
|
+
logger = logger(__name__)
|
|
6
|
+
|
|
3
7
|
|
|
4
8
|
class Operation:
|
|
5
9
|
"""
|
|
@@ -35,11 +39,6 @@ class Operation:
|
|
|
35
39
|
query_params: Optional[Dict[str, Any]] = None,
|
|
36
40
|
store_params: Optional[Dict[str, Any]] = None,
|
|
37
41
|
metadata_params: Optional[Dict[str, Any]] = None,
|
|
38
|
-
roles: Optional[List[str]] = None,
|
|
39
|
-
scope: Optional[Dict[str, Any]] = None,
|
|
40
|
-
groups: Optional[List[str]] = None,
|
|
41
|
-
permissions: Optional[List[str]] = None,
|
|
42
|
-
subject: Optional[str] = None,
|
|
43
42
|
claims: Optional[Dict[str, Any]] = None,
|
|
44
43
|
):
|
|
45
44
|
"""
|
|
@@ -76,12 +75,30 @@ class Operation:
|
|
|
76
75
|
self.metadata_params = metadata_params or {}
|
|
77
76
|
|
|
78
77
|
# Roles defining the context in which the operation is allowed.
|
|
79
|
-
self.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
self.claims = claims or {}
|
|
79
|
+
|
|
80
|
+
# Log the operation for debugging and audit purposes
|
|
81
|
+
logger.info(
|
|
82
|
+
"Operation created: entity=%s, action=%s, "
|
|
83
|
+
"query_params=%s, store_params=%s, "
|
|
84
|
+
"metadata_params=%s, claims=%s",
|
|
85
|
+
self.entity,
|
|
86
|
+
self.action,
|
|
87
|
+
self.query_params,
|
|
88
|
+
self.store_params,
|
|
89
|
+
self.metadata_params,
|
|
90
|
+
self.claims,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def roles(self) -> List[str]:
|
|
95
|
+
"""Get the roles from claims."""
|
|
96
|
+
return self.claims.get("roles", []) if self.claims else []
|
|
97
|
+
|
|
98
|
+
def subject(self) -> Optional[str]:
|
|
99
|
+
"""Get the subject from claims."""
|
|
100
|
+
return self.claims.get("sub") if self.claims else None
|
|
101
|
+
|
|
102
|
+
def groups(self) -> List[str]:
|
|
103
|
+
"""Get the groups from claims."""
|
|
104
|
+
return self.claims.get("groups", []) if self.claims else []
|
|
@@ -8,7 +8,9 @@ log = logger(__name__)
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class Service:
|
|
11
|
-
def __init__(self, config: dict =
|
|
11
|
+
def __init__(self, config: dict = None):
|
|
12
|
+
if not config:
|
|
13
|
+
config = {}
|
|
12
14
|
self.config = config
|
|
13
15
|
|
|
14
16
|
def execute(self, operation: Operation) -> list[dict]:
|
|
@@ -16,7 +18,9 @@ class Service:
|
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
class ServiceAdapter(Service):
|
|
19
|
-
def __init__(self, config: dict =
|
|
21
|
+
def __init__(self, config: dict = None):
|
|
22
|
+
if not config:
|
|
23
|
+
config = {}
|
|
20
24
|
super().__init__(config)
|
|
21
25
|
|
|
22
26
|
def execute(self, operation: Operation) -> list[dict]:
|
|
@@ -24,7 +28,9 @@ class ServiceAdapter(Service):
|
|
|
24
28
|
|
|
25
29
|
|
|
26
30
|
class MutationPublisher(ServiceAdapter):
|
|
27
|
-
def __init__(self, config: dict =
|
|
31
|
+
def __init__(self, config: dict = None):
|
|
32
|
+
if not config:
|
|
33
|
+
config = {}
|
|
28
34
|
super().__init__(config)
|
|
29
35
|
|
|
30
36
|
def execute(self, operation):
|
|
@@ -34,7 +40,7 @@ class MutationPublisher(ServiceAdapter):
|
|
|
34
40
|
|
|
35
41
|
def publish_notification(self, operation):
|
|
36
42
|
topic_arn = self.config.get("BROADCAST_TOPIC", None)
|
|
37
|
-
log.debug(
|
|
43
|
+
log.debug("Topic ARN: %s", topic_arn)
|
|
38
44
|
|
|
39
45
|
if topic_arn is not None:
|
|
40
46
|
log.debug("Sending message")
|
|
@@ -46,7 +52,7 @@ class MutationPublisher(ServiceAdapter):
|
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
message_str = json.dumps({"default": json.dumps(message)})
|
|
49
|
-
log.debug(
|
|
55
|
+
log.debug("message_str: %s", message_str)
|
|
50
56
|
hash_object = hashlib.sha256(message_str.encode("utf-8"))
|
|
51
57
|
hex_dig = hash_object.hexdigest()
|
|
52
58
|
|
|
@@ -57,7 +63,7 @@ class MutationPublisher(ServiceAdapter):
|
|
|
57
63
|
MessageGroupId=operation.api_name,
|
|
58
64
|
Message=message_str,
|
|
59
65
|
)
|
|
60
|
-
log.info(
|
|
66
|
+
log.info("publish msg id %s", msg_id)
|
|
61
67
|
|
|
62
68
|
def __client(self, client_type):
|
|
63
69
|
import boto3
|
|
@@ -45,8 +45,8 @@ class TransactionalService(ServiceAdapter):
|
|
|
45
45
|
return [result]
|
|
46
46
|
return result
|
|
47
47
|
except Exception as error:
|
|
48
|
-
log.error(
|
|
49
|
-
log.error(
|
|
48
|
+
log.error("transaction exception: %s", error)
|
|
49
|
+
log.error("traceback: %s", traceback.format_exc())
|
|
50
50
|
raise error
|
|
51
51
|
finally:
|
|
52
52
|
connection.close()
|
|
@@ -289,7 +289,7 @@ class APIModel:
|
|
|
289
289
|
"""Class to load and expose the API configuration as objects."""
|
|
290
290
|
|
|
291
291
|
def __init__(self, config: Dict[str, Any]):
|
|
292
|
-
|
|
292
|
+
log.info("building api_model")
|
|
293
293
|
self.schema_objects = {
|
|
294
294
|
name: SchemaObject(schema_data)
|
|
295
295
|
for name, schema_data in config.get("schema_objects", {}).items()
|
|
@@ -323,4 +323,4 @@ def set_api_model(engine_config: Mapping[str, str]):
|
|
|
323
323
|
os.environ.get("API_SPEC", "/var/task/api_spec.yaml"), "r"
|
|
324
324
|
) as file:
|
|
325
325
|
api_model = APIModel(yaml.safe_load(file))
|
|
326
|
-
log.info(
|
|
326
|
+
log.info("Loaded API model: %s", api_model)
|