This guide covers the development of serverless functions in our system, ensuring consistency and maintainability across all implementations.
- Basic Python Function Template
- Implementation Steps
- Naming Conventions
- Response Format
- Error Handling
- Documentation Requirements
from typing import Dict, Any
import logging
def template_function(arguments: Dict[str, Any]) -> Dict[str, Any]:
"""
Description of what the function does.
Args:
arguments (dict): Contains:
- input.param1 (type): Description
- input.param2 (type): Description
Returns:
dict: Response containing:
- success (bool): Whether the operation was successful
- error (str, optional): Error message if operation failed
- messageKey (str): Translation key for messages
- [additional_field] (type): Description of additional return fields
"""
logging.info("########## Template Function ##########")
logging.debug(f"Arguments: {arguments}")
try:
# Your function logic here
result = do_something(arguments)
return {
"success": True,
"messageKey": "OPERATION_SUCCESS",
# Additional result fields
}
except ValueError as e:
logging.error(f"Invalid input: {str(e)}")
return {
"success": False,
"error": str(e),
"messageKey": "INVALID_INPUT"
}
except Exception as e:
logging.error(f"Error in template function: {str(e)}")
return {
"success": False,
"error": str(e),
"messageKey": "OPERATION_FAILED"
}-
Create Function File
- Path:
functions/callPythonFunction/pythonFunctions/your_function_name.py - Naming: Use snake_case (e.g.,
create_certificates.py) - Required imports:
from typing import Dict, Any import logging
- Path:
-
Register Function
- File:
functions/callPythonFunction/main.py - Import and register pattern:
from pythonFunctions.your_function_name import your_function_name PYTHON_FUNCTIONS: Dict[str, Callable] = { "your_function_name": your_function_name, }
- File:
-
Define a Trigger or Action in Hasura An action you can define as follows in the Hasura console:
type Mutation { yourFunctionName(param1: Type!, param2: Type): YourFunctionResult! }
With the result type defined as follows (under Type Configuration):
type YourFunctionResult { success: Boolean! messageKey: String! error: String # Additional fields specific to your function }
The Webhook URL you set to
{CLOUD_FUNCTION_LINK_CALL_PYTHON_FUNCTION}}, which will be set according to the current environment.Set the following mandatory headers:
Hasura-Secret: choose 'From env var' and set it toHASURA_CLOUD_FUNCTION_SECRETFunction-Name: choose 'Value' and set it toyour_function_nameOptional header:Bucket: choose 'From env var' and set it toHASURA_BUCKET
⚠️ Important: For functions that return a response (most cases), set the execution mode toSynchronous. It is set toAsynchronousby default, which will cause errors when trying to access the response fields. -
Create Frontend Query
- File:
frontend-nx/apps/edu-hub/queries/actions.ts - Add GraphQL mutation:
export const YOUR_FUNCTION = gql` mutation yourFunctionName($param1: Type!, $param2: Type) { yourFunctionName(param1: $param1, param2: $param2) { success messageKey error # Additional fields } } `;
- File:
-
Add Translation Keys If you use messageKeys in your function, you need to add them in the specific language file of the component calling the function.
-
Python
- Function names:
snake_case - Variables:
snake_case - Classes:
PascalCase - Constants:
UPPER_SNAKE_CASE
- Function names:
-
GraphQL
- Types:
PascalCasewithResultsuffix (e.g.,CreateCertificatesResult) - Mutations/Queries:
camelCase - Fields:
camelCase
- Types:
-
TypeScript
- Constants:
UPPER_SNAKE_CASE - Components:
PascalCase - Functions/Methods:
camelCase - Files: Match component name if containing a component
- Constants:
-
Message Keys
- Format:
UPPERCASE_WITH_UNDERSCORES - Categories:
- Success:
OPERATION_SUCCESS - Input Error:
INVALID_INPUT - General Error:
OPERATION_FAILED
- Success:
- Format:
All functions should return a standardized response:
{
"success": bool, # Required: Operation success status
"messageKey": str, # Required: Translation key for UI messages
"error": str, # Optional: Error message if success is False
# Additional fields specific to the function
}Do not use a nested data object to return the result of the function but rather return the fields directly in the response.
-
Standard Error Types
ValueErrorfor invalid inputsExceptionas fallback for unexpected errors- Custom exceptions for specific business logic
-
Error Response Format
{ "success": False, "error": str(e), # Human-readable error message "messageKey": "ERROR_TYPE" # Translation key for frontend } -
Common Message Keys
INVALID_INPUT: Input validation failuresUNAUTHORIZED: Permission issuesOPERATION_FAILED: General operation failuresNOT_FOUND: Resource not foundINTERNAL_ERROR: Unexpected system errors
-
Logging
- Always log errors with stack traces
- Include relevant context but no sensitive data
- Use appropriate log levels (ERROR for errors, INFO for operations)
-
Function Docstring
"""Short description of function purpose. Args: arguments (dict): Contains: - input.param1 (type): Description - input.param2 (type): Description Returns: dict: Response containing: - success (bool): Operation status - messageKey (str): Translation key - error (str, optional): Error message """
-
Code Comments
- Explain complex business logic
- Document assumptions
- Note any side effects
-
Function Registration
- Ensure function name in
main.pymatches theFunction-Nameheader - Function name must be snake_case in Python, camelCase in GraphQL
- Ensure function name in
-
Error Handling
- Always return the standard response format
- Log errors before returning
- Use appropriate message keys
-
Type Safety
- Use type hints in Python functions
- Validate input parameters
- Match GraphQL types with Python types
-
Testing
- Test with various input combinations
- Verify error handling
- Check translation keys exist