A lightweight, modular, and secure framework designed for building RESTful APIs in Appwrite Functions. It provides a streamlined development experience with built-in utilities for request handling, validation, authentication, and database interactions.
Project description
SecureAPI-Py - A Secure RESTful API Framework for Appwrite Functions
SecureAPI-Py is a lightweight, modular, and secure framework designed for building RESTful APIs in Appwrite Functions using Python. It provides a streamlined development experience with built-in utilities for request handling, validation, authentication, and database interactions.
Table of Contents
Features
- Core Library: Simplifies request/response handling, error management, and enhanced logging with pretty-print support.
- Utility Modules:
- Validator: Ensures input integrity by validating headers, query parameters, and body content.
- Security: Provides JWT validation and API key verification.
- DatabaseManager: Facilitates CRUD operations on Appwrite databases with flexible database ID management.
- Enhanced Logging: Pretty-print JSON/dicts with proper formatting for better debugging.
- Middleware Support: Customize request processing with authentication, logging, CORS, and validation middleware.
- Helper Properties: Convenient properties for accessing Appwrite Function metadata, user info, and environment variables.
- Response Types: Support for all Appwrite Function response types (JSON, text, binary, redirect, empty).
- Router: Simple routing system for handling multiple endpoints.
Installation
To use SecureAPI-Py in your Appwrite function, add it to your requirements.txt file:
secure-api-py>=1.0.0
appwrite>=7.0.0
Then, install the dependencies:
pip install -r requirements.txt
Getting Started
Core Library: SecureAPI
Usage
The SecureAPI class is your entry point to build APIs. It handles request processing and provides utility methods for standardized responses.
Example:
from secure_api import SecureAPI
def main(context):
# Option 1: Initialize with a default database ID
api = SecureAPI(context, database_id='YOUR_DATABASE_ID')
# Option 2: Initialize without default database ID (flexible approach)
# api = SecureAPI(context)
if api.context.req.path == '/tasks/create' and api.method == 'POST':
# Add task creation logic here
return api.send_success(message='Task created', data=task_doc)
Utility Modules
Validator
Ensures your API receives valid input.
from secure_api import Validator
async def input_validator(api):
Validator.validate_headers(api.headers, ['x-api-key'])
Validator.validate_query_params(api.query_params, ['type'])
api.log('Input validation passed.')
Security
Handle authentication via JWTs or API keys.
from secure_api import Security, auth_middleware
# Use built-in auth middleware
api.use_middleware(auth_middleware)
# Or create custom authentication
async def custom_auth(api):
headers = api.headers
if 'x-api-key' not in headers or not headers['x-api-key']:
raise Exception('Missing `x-api-key` header.')
jwt = headers['x-api-key']
security = Security(api.client)
try:
is_authenticated = await security.validate_jwt(jwt)
api.log(f'User authenticated: {is_authenticated}')
except Exception as e:
api.error(f'Authentication failed: {e}')
raise Exception('Invalid or expired token.')
DatabaseManager
Simplifies CRUD operations for Appwrite collections with flexible database management.
async def create_task(api):
task_doc = await api.db.create_document(
collection_id='tasks',
data=task,
database_id='YOUR_DATABASE_ID'
)
return await api.send_success(message='Task created', data=task_doc)
Key Features:
- Flexible Database IDs: Use different databases dynamically
- Named Parameters: Clean, readable function calls
- Backward Compatibility: Existing code continues to work via
api.db_helper(deprecated)
Enhanced Logging
The improved logging system now properly formats objects and dicts for better debugging:
# Simple logging
api.log('Processing request...')
# Pretty-print JSON objects
api.log_json('User Data', {
'id': '123',
'name': 'John Doe',
'permissions': ['read', 'write'],
})
# Automatic formatting for dicts/lists
api.log({
'status': 'success',
'count': 42,
'items': ['item1', 'item2']
})
# Output will be properly indented JSON
Helper Properties
SecureAPI includes convenient helper properties for common Appwrite Function patterns:
# Request helpers
api.path # Request path
api.url # Full URL
api.host # Hostname
api.method # HTTP method
# Authentication helpers
api.user_id # User ID if authenticated
api.user_jwt # JWT token if available
api.is_authenticated # Check if user is authenticated
# Function metadata
api.trigger_type # How function was triggered (http, schedule, event)
api.trigger_event # Event that triggered the function
# Environment variables with defaults
api.get_env('MY_VAR', default_value='default')
Response Types
Support for all Appwrite Function response types:
# JSON responses
await api.send_success(message='Success', data={...})
await api.send_error(message='Error', status_code=500)
# Other response types
await api.send_empty() # 204 No Content
await api.send_text('Plain text', status_code=200)
await api.send_redirect('https://example.com') # 301 Redirect
await api.send_binary(bytes_data) # Binary data
Middleware
Middleware functions process requests before hitting route handlers:
Built-in Middleware
- CORS Middleware:
from secure_api import cors_middleware
api.use_middleware(cors_middleware(
origin='*',
methods='GET, POST, PUT, DELETE, OPTIONS',
headers='Content-Type, Authorization',
))
- Logging Request Middleware (with enhanced formatting):
from secure_api import log_request
api.use_middleware(log_request) # Now with pretty-print support!
- Authentication Middleware:
from secure_api import auth_middleware
api.use_middleware(auth_middleware)
- Rate Limiting Middleware:
from secure_api import rate_limit_middleware
api.use_middleware(rate_limit_middleware(
max_requests=100,
window_minutes=1
))
Adding Middleware (Order Matters!)
api.use_middleware(cors_middleware()) # Handle CORS first
api.use_middleware(log_request) # Then log requests
api.use_middleware(auth_middleware) # Then check auth
Router
Use the built-in router for handling multiple endpoints:
from secure_api import SecureAPI, Router
async def main(context):
api = SecureAPI(context, database_id='YOUR_DATABASE_ID')
router = Router()
# Define routes
router.get('/tasks', list_tasks)
router.post('/tasks', create_task)
router.put('/tasks/:id', update_task)
router.delete('/tasks/:id', delete_task)
# Execute middleware
await api.execute_middleware()
# Handle request
return await router.handle(api)
async def list_tasks(api, params):
tasks = await api.db.list_documents(collection_id='tasks')
return await api.send_success(message='Tasks retrieved', data={'tasks': tasks})
async def create_task(api, params):
api.validate_body({'title': 'required|string', 'description': 'required|string'})
task = {
'title': api.body_json['title'],
'description': api.body_json['description'],
'completed': False,
}
task_doc = await api.db.create_document(collection_id='tasks', data=task)
return await api.send_success(message='Task created', data=task_doc)
async def update_task(api, params):
task_id = params['id']
data = api.body_json
task_doc = await api.db.update_document(
collection_id='tasks',
document_id=task_id,
data=data
)
return await api.send_success(message='Task updated', data=task_doc)
async def delete_task(api, params):
task_id = params['id']
await api.db.delete_document(collection_id='tasks', document_id=task_id)
return await api.send_success(message='Task deleted')
Real-World Example: Task Management System
Endpoints
- Create Task:
POST /tasks/create - List Tasks:
GET /tasks/get - Update Task:
PUT /tasks/update - Delete Task:
DELETE /tasks/delete
Example Implementation
from secure_api import SecureAPI, log_request, auth_middleware, Validator
async def main(context):
# Flexible initialization - can work with or without default database ID
api = SecureAPI(context)
# Middleware
api.use_middleware(log_request)
api.use_middleware(auth_middleware)
# Handle requests
try:
await api.execute_middleware()
path = api.context.req.path
if path == '/tasks/create' and api.method == 'POST':
return await create_task(api)
elif path == '/tasks/get' and api.method == 'GET':
return await list_tasks(api)
elif path == '/tasks/update' and api.method == 'PUT':
return await update_task(api)
elif path == '/tasks/delete' and api.method == 'DELETE':
return await delete_task(api)
else:
return await api.send_error(
message='Endpoint not found',
status_code=404,
)
except Exception as e:
api.error(f'Error: {e}')
return await api.handle_error(e)
async def create_task(api):
Validator.validate_body(api.body_json, ['title', 'description'])
task = {
'title': api.body_json['title'],
'description': api.body_json['description'],
'completed': False,
}
task_doc = await api.db.create_document(
collection_id='tasks',
data=task,
database_id='YOUR_DATABASE_ID'
)
return await api.send_success(message='Task created', data=task_doc)
async def list_tasks(api):
tasks = await api.db.list_documents(
collection_id='tasks',
database_id='YOUR_DATABASE_ID'
)
return await api.send_success(message='Tasks retrieved', data={'tasks': tasks})
Configuration
Configure your Appwrite function to use SecureAPI-Py by setting up the necessary environment variables and dependencies as described in the Getting Started section.
API Reference
SecureAPI Class
Main class for handling requests and responses.
Methods:
log(message)- Log a messageerror(message)- Log an errorlog_json(label, data)- Log JSON with labelsend_success(...)- Send success responsesend_error(...)- Send error responsesend_unauthorized(...)- Send 401 responsesend_empty()- Send 204 responsesend_redirect(url)- Send redirect responsesend_text(text)- Send text responsesend_binary(bytes)- Send binary responsevalidate_body(rules)- Validate request bodyhandle_error(error)- Handle errors
Properties:
method- HTTP methodheaders- Request headersquery_params- Query parametersbody_text- Request body as textbody_json- Request body as JSONpath- Request pathurl- Request URLuser_id- Authenticated user IDis_authenticated- Authentication status
Contributing
Contributions are welcome! Please submit pull requests or open issues for suggestions.
License
This package is distributed under the BSD-3-Clause License.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file secure_api_py-2.0.0.tar.gz.
File metadata
- Download URL: secure_api_py-2.0.0.tar.gz
- Upload date:
- Size: 24.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0088dff3d5f8ad79f71ef550ef5651af79a27dde08a0007c5cfd7ed5eb62044
|
|
| MD5 |
11391e4d5023a7d01850c7ef70491a25
|
|
| BLAKE2b-256 |
a93250469fdd8212a55c6595a6176ba1d076f8f9ed5091e61b8716f4a1df7c9e
|
File details
Details for the file secure_api_py-2.0.0-py3-none-any.whl.
File metadata
- Download URL: secure_api_py-2.0.0-py3-none-any.whl
- Upload date:
- Size: 23.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec29cf09d0d07514655e994218ac37c81508ffcb6602cd2a2d71c93436f3428a
|
|
| MD5 |
80d93d940f7f95ee53db17d249b86fd2
|
|
| BLAKE2b-256 |
ef47c546924cac34a1428e6f64a28fda77beeace07021dce9bafe386d2e1e321
|