Skip to content

Commit 2b9e84a

Browse files
committed
Enhances API routing and event processing
Improves API routing with authentication support. Provides consistent event processing across AWS services. Updates description and keywords to better reflect project goals.
1 parent 1c827f9 commit 2b9e84a

File tree

2 files changed

+154
-29
lines changed

2 files changed

+154
-29
lines changed

README.md

Lines changed: 120 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,23 @@ pip install acai_aws
8484
# app.py (entry point for your Lambda)
8585
from acai_aws.apigateway.router import Router
8686

87+
88+
def authenticate(request, response, requirements):
89+
if request.headers.get('x-api-key') != 'secret-key':
90+
response.code = 401
91+
response.set_error('auth', 'Unauthorized')
92+
93+
8794
router = Router(
8895
base_path='api/v1',
8996
handlers='handlers', # directory mode
9097
schema='openapi.yml', # optional OpenAPI document
9198
auto_validate=True,
9299
validate_response=True,
93-
before_all=lambda request, response, _: request.context.update({'trace_id': request.headers.get('trace-id')})
100+
with_auth=authenticate
94101
)
102+
router.auto_load()
103+
95104

96105
def handler(event, context):
97106
return router.route(event, context)
@@ -101,14 +110,8 @@ def handler(event, context):
101110
# handlers/users.py
102111
from acai_aws.apigateway.requirements import requirements
103112

104-
def authenticate(request, response, _requirements):
105-
if request.headers.get('x-api-key') != 'secret':
106-
response.code = 401
107-
response.set_error('auth', 'Unauthorized')
108-
109113
@requirements(
110114
auth_required=True,
111-
before=authenticate,
112115
required_body={
113116
'type': 'object',
114117
'required': ['email', 'name'],
@@ -179,31 +182,129 @@ pipenv run generate
179182

180183
## 🔄 Event Processing
181184

182-
Acai AWS provides consistent event objects for AWS stream and queue services. Decorate your handler with `acai_aws.common.records.requirements.requirements` to auto-detect the source and normalize each record.
185+
Acai AWS provides consistent event objects for AWS stream and queue services. Decorate your handler with `acai_aws.common.records.requirements.requirements` to auto-detect the source and wrap records.
183186

184187
```python
185188
from acai_aws.dynamodb.requirements import requirements
186189

190+
class ProductRecord:
191+
def __init__(self, record):
192+
self.id = record.body['id']
193+
self.payload = record.body
194+
187195
@requirements(
188196
operations=['created', 'updated'],
189197
timeout=10,
190-
data_class=lambda record: record.body
198+
data_class=ProductRecord
191199
)
192-
def handler(event):
193-
for record in event.records:
194-
process(record) # record is dict from the stream, filtered and validated
195-
return {'processed': len(event.records)}
200+
def handler(records):
201+
for record in records.records:
202+
process_product(record.id, record.payload)
203+
return {'processed': len(records.records)}
196204
```
197205

198206
Supported services include:
199207

200-
- **DynamoDB Streams** (`acai_aws.dynamodb.event.Event`)
201-
- **SQS** (`acai_aws.sqs.event.Event`)
202-
- **SNS** (`acai_aws.sns.event.Event`)
203-
- **S3** (optional `get_object` helper to pull objects)
204-
- **Kinesis**, **Firehose**, **MSK**, **MQ**, **DocumentDB**
208+
**DynamoDB Streams**
209+
210+
```python
211+
from acai_aws.dynamodb.requirements import requirements as ddb_requirements
212+
213+
@ddb_requirements()
214+
def dynamodb_handler(records):
215+
for record in records.records:
216+
handle_ddb_change(record.operation, record.body)
217+
```
218+
219+
**Amazon SQS**
220+
221+
```python
222+
from acai_aws.sqs.requirements import requirements as sqs_requirements
223+
224+
@sqs_requirements()
225+
def sqs_handler(records):
226+
for record in records.records:
227+
handle_message(record.body, record.attributes)
228+
```
229+
230+
**Amazon SNS**
231+
232+
```python
233+
from acai_aws.sns.requirements import requirements as sns_requirements
234+
235+
@sns_requirements()
236+
def sns_handler(records):
237+
for record in records.records:
238+
handle_notification(record.body, record.subject)
239+
```
240+
241+
**Amazon S3**
242+
243+
```python
244+
from acai_aws.s3.requirements import requirements as s3_requirements
245+
246+
@s3_requirements(get_object=True, data_type='json')
247+
def s3_handler(records):
248+
for record in records.records:
249+
handle_object(record.bucket, record.key, record.body)
250+
```
251+
252+
**Amazon Kinesis**
253+
254+
```python
255+
from acai_aws.kinesis.requirements import requirements as kinesis_requirements
256+
257+
@kinesis_requirements()
258+
def kinesis_handler(records):
259+
for record in records.records:
260+
handle_stream_event(record.partition_key, record.body)
261+
```
262+
263+
**Amazon Firehose**
264+
265+
```python
266+
from acai_aws.firehose.requirements import requirements as firehose_requirements
267+
268+
@firehose_requirements()
269+
def firehose_handler(records):
270+
for record in records.records:
271+
handle_delivery(record.record_id, record.body)
272+
```
273+
274+
**Amazon MSK**
275+
276+
```python
277+
from acai_aws.msk.requirements import requirements as msk_requirements
278+
279+
@msk_requirements()
280+
def msk_handler(records):
281+
for record in records.records:
282+
handle_msk_message(record.topic, record.body)
283+
```
284+
285+
**Amazon MQ**
286+
287+
```python
288+
from acai_aws.mq.requirements import requirements as mq_requirements
289+
290+
@mq_requirements()
291+
def mq_handler(records):
292+
for record in records.records:
293+
handle_mq_message(record.message_id, record.body)
294+
```
295+
296+
**Amazon DocumentDB Change Streams**
297+
298+
```python
299+
from acai_aws.documentdb.requirements import requirements as docdb_requirements
300+
301+
@docdb_requirements()
302+
def docdb_handler(records):
303+
for record in records.records:
304+
handle_docdb_change(record.operation, record.full_document)
305+
```
205306

206-
Each record exposes intuitive properties like `record.operation`, `record.body`, `record.headers`, or service-specific fields.
307+
Each record exposes intuitive properties like `record.operation`, `record.body`, or service-specific metadata (bucket, partition, headers, etc.).
207308

208309
---
209310

setup.py

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66

77
setup(
88
name='acai_aws',
9-
version=os.getenv('CIRCLE_TAG'),
10-
url='https://github.com/syngenta/acai-python.git',
9+
version=os.getenv('CIRCLE_TAG', '0.0.0'),
10+
url='https://github.com/syngenta/acai-python',
1111
author='Paul Cruse III',
1212
author_email='[email protected]',
13-
description='DRY, configurable, opinionated, minimalist framework for use with AWS Serverless Lambdas',
13+
description='DRY, configurable, declarative framework for building AWS Lambda APIs and event processors',
1414
long_description=long_description,
1515
long_description_content_type='text/markdown',
1616
packages=find_packages(),
17-
python_requires='>=3.0',
17+
include_package_data=True,
18+
python_requires='>=3.8',
1819
install_requires=[
1920
'boto3',
2021
'dynamodb_json',
@@ -27,18 +28,41 @@
2728
'simplejson',
2829
'xmltodict'
2930
],
31+
keywords=[
32+
'aws', 'lambda', 'serverless', 'apigateway', 'router', 'openapi', 'pydantic',
33+
'dynamodb', 'sqs', 'sns', 's3', 'kinesis', 'firehose', 'msk', 'documentdb',
34+
'event-driven', 'validation', 'jsonschema', 'python-framework'
35+
],
36+
project_urls={
37+
'Homepage': 'https://github.com/syngenta/acai-python',
38+
'Documentation': 'https://syngenta.github.io/acai-python-docs/',
39+
'Source': 'https://github.com/syngenta/acai-python',
40+
'Issue Tracker': 'https://github.com/syngenta/acai-python/issues',
41+
'CI/CD': 'https://circleci.com/gh/syngenta/acai-python'
42+
},
43+
license='Apache 2.0',
44+
platforms=['any'],
45+
zip_safe=False,
3046
classifiers=[
31-
'Environment :: Web Environment',
47+
'Development Status :: 5 - Production/Stable',
3248
'Intended Audience :: Developers',
33-
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
34-
'Topic :: Software Development :: Libraries :: Python Modules',
49+
'Intended Audience :: Information Technology',
50+
'License :: OSI Approved :: Apache Software License',
51+
'Environment :: Web Environment',
52+
'Environment :: Console',
53+
'Operating System :: OS Independent',
3554
'Programming Language :: Python',
3655
'Programming Language :: Python :: 3',
37-
'Programming Language :: Python :: 3.6',
38-
'Programming Language :: Python :: 3.7',
3956
'Programming Language :: Python :: 3.8',
4057
'Programming Language :: Python :: 3.9',
4158
'Programming Language :: Python :: 3.10',
42-
'Programming Language :: Python :: 3.11'
59+
'Programming Language :: Python :: 3.11',
60+
'Programming Language :: Python :: 3.12',
61+
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
62+
'Topic :: Software Development :: Libraries :: Python Modules',
63+
'Topic :: Software Development :: Libraries :: Application Frameworks',
64+
'Topic :: System :: Distributed Computing',
65+
'Topic :: System :: Monitoring',
66+
'Natural Language :: English'
4367
]
4468
)

0 commit comments

Comments
 (0)