Initial commit: Shop Database Flask Application
Flask backend with Vue 3 frontend for shop floor machine management. Includes database schema export for MySQL shopdb_flask database. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
20
shopdb/utils/__init__.py
Normal file
20
shopdb/utils/__init__.py
Normal file
@@ -0,0 +1,20 @@
|
||||
"""Utility modules."""
|
||||
|
||||
from .responses import (
|
||||
api_response,
|
||||
success_response,
|
||||
error_response,
|
||||
paginated_response,
|
||||
ErrorCodes
|
||||
)
|
||||
from .pagination import get_pagination_params, paginate_query
|
||||
|
||||
__all__ = [
|
||||
'api_response',
|
||||
'success_response',
|
||||
'error_response',
|
||||
'paginated_response',
|
||||
'ErrorCodes',
|
||||
'get_pagination_params',
|
||||
'paginate_query'
|
||||
]
|
||||
43
shopdb/utils/pagination.py
Normal file
43
shopdb/utils/pagination.py
Normal file
@@ -0,0 +1,43 @@
|
||||
"""Pagination utilities."""
|
||||
|
||||
from flask import request, current_app
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
def get_pagination_params(req=None) -> Tuple[int, int]:
|
||||
"""
|
||||
Extract pagination parameters from request.
|
||||
|
||||
Returns:
|
||||
Tuple of (page, per_page)
|
||||
"""
|
||||
if req is None:
|
||||
req = request
|
||||
|
||||
default_size = current_app.config.get('DEFAULT_PAGE_SIZE', 20)
|
||||
max_size = current_app.config.get('MAX_PAGE_SIZE', 100)
|
||||
|
||||
try:
|
||||
page = max(1, int(req.args.get('page', 1)))
|
||||
except (TypeError, ValueError):
|
||||
page = 1
|
||||
|
||||
try:
|
||||
per_page = int(req.args.get('per_page', default_size))
|
||||
per_page = max(1, min(per_page, max_size))
|
||||
except (TypeError, ValueError):
|
||||
per_page = default_size
|
||||
|
||||
return page, per_page
|
||||
|
||||
|
||||
def paginate_query(query, page: int, per_page: int):
|
||||
"""
|
||||
Apply pagination to a SQLAlchemy query.
|
||||
|
||||
Returns:
|
||||
Tuple of (items, total)
|
||||
"""
|
||||
total = query.count()
|
||||
items = query.offset((page - 1) * per_page).limit(per_page).all()
|
||||
return items, total
|
||||
171
shopdb/utils/responses.py
Normal file
171
shopdb/utils/responses.py
Normal file
@@ -0,0 +1,171 @@
|
||||
"""Standardized API response helpers."""
|
||||
|
||||
from flask import jsonify, make_response
|
||||
from typing import Any, Dict, List, Optional
|
||||
from datetime import datetime
|
||||
import uuid
|
||||
|
||||
|
||||
class ErrorCodes:
|
||||
"""Standard error codes."""
|
||||
|
||||
VALIDATION_ERROR = 'VALIDATION_ERROR'
|
||||
NOT_FOUND = 'NOT_FOUND'
|
||||
UNAUTHORIZED = 'UNAUTHORIZED'
|
||||
FORBIDDEN = 'FORBIDDEN'
|
||||
CONFLICT = 'CONFLICT'
|
||||
INTERNAL_ERROR = 'INTERNAL_ERROR'
|
||||
BAD_REQUEST = 'BAD_REQUEST'
|
||||
PLUGIN_ERROR = 'PLUGIN_ERROR'
|
||||
|
||||
|
||||
def api_response(
|
||||
data: Any = None,
|
||||
message: str = None,
|
||||
status: str = 'success',
|
||||
meta: Dict = None,
|
||||
http_code: int = 200
|
||||
):
|
||||
"""
|
||||
Create standardized API response.
|
||||
|
||||
Response format:
|
||||
{
|
||||
"status": "success" | "error",
|
||||
"data": {...} | [...],
|
||||
"message": "Optional message",
|
||||
"meta": {
|
||||
"timestamp": "2025-01-12T...",
|
||||
"request_id": "uuid"
|
||||
}
|
||||
}
|
||||
"""
|
||||
response = {
|
||||
'status': status,
|
||||
'meta': {
|
||||
'timestamp': datetime.utcnow().isoformat() + 'Z',
|
||||
'request_id': str(uuid.uuid4())[:8],
|
||||
**(meta or {})
|
||||
}
|
||||
}
|
||||
|
||||
if data is not None:
|
||||
response['data'] = data
|
||||
|
||||
if message:
|
||||
response['message'] = message
|
||||
|
||||
return make_response(jsonify(response), http_code)
|
||||
|
||||
|
||||
def success_response(
|
||||
data: Any = None,
|
||||
message: str = None,
|
||||
meta: Dict = None,
|
||||
http_code: int = 200
|
||||
):
|
||||
"""Success response helper."""
|
||||
return api_response(
|
||||
data=data,
|
||||
message=message,
|
||||
meta=meta,
|
||||
status='success',
|
||||
http_code=http_code
|
||||
)
|
||||
|
||||
|
||||
def error_response(
|
||||
code: str,
|
||||
message: str,
|
||||
details: Dict = None,
|
||||
http_code: int = 400
|
||||
):
|
||||
"""
|
||||
Error response helper.
|
||||
|
||||
Response format:
|
||||
{
|
||||
"status": "error",
|
||||
"error": {
|
||||
"code": "VALIDATION_ERROR",
|
||||
"message": "Human-readable message",
|
||||
"details": {...}
|
||||
}
|
||||
}
|
||||
"""
|
||||
error_data = {
|
||||
'code': code,
|
||||
'message': message
|
||||
}
|
||||
if details:
|
||||
error_data['details'] = details
|
||||
|
||||
return api_response(
|
||||
data={'error': error_data},
|
||||
status='error',
|
||||
http_code=http_code
|
||||
)
|
||||
|
||||
|
||||
def api_error(
|
||||
message: str,
|
||||
code: str = ErrorCodes.BAD_REQUEST,
|
||||
details: Dict = None,
|
||||
http_code: int = 400
|
||||
):
|
||||
"""
|
||||
Simplified error response helper.
|
||||
|
||||
Args:
|
||||
message: Human-readable error message
|
||||
code: Error code (default BAD_REQUEST)
|
||||
details: Optional error details
|
||||
http_code: HTTP status code (default 400)
|
||||
"""
|
||||
return error_response(code=code, message=message, details=details, http_code=http_code)
|
||||
|
||||
|
||||
def paginated_response(
|
||||
items: List,
|
||||
page: int,
|
||||
per_page: int,
|
||||
total: int,
|
||||
schema=None
|
||||
):
|
||||
"""
|
||||
Paginated list response.
|
||||
|
||||
Response format:
|
||||
{
|
||||
"status": "success",
|
||||
"data": [...],
|
||||
"meta": {
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"per_page": 20,
|
||||
"total": 150,
|
||||
"total_pages": 8,
|
||||
"has_next": true,
|
||||
"has_prev": false
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
total_pages = (total + per_page - 1) // per_page if per_page > 0 else 0
|
||||
|
||||
if schema:
|
||||
items = schema.dump(items, many=True)
|
||||
|
||||
return api_response(
|
||||
data=items,
|
||||
meta={
|
||||
'pagination': {
|
||||
'page': page,
|
||||
'per_page': per_page,
|
||||
'total': total,
|
||||
'total_pages': total_pages,
|
||||
'has_next': page < total_pages,
|
||||
'has_prev': page > 1
|
||||
}
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user