Nasajon GCF Utilities
nsj-gcf-utils (v1.1.0) is a Python library providing utilities for building Google Cloud Functions, primarily designed for applications leveraging Django and Django REST Framework. It offers tools for handling function context, interacting with Google Cloud services like Firestore, Storage, and Secret Manager, and managing tasks. The library is actively maintained with a focus on specific enterprise use cases rather than general-purpose GCF development, and updates are released as needed.
Common errors
-
ModuleNotFoundError: No module named 'django'
cause The `nsj-gcf-utils` library has hard dependencies on Django and Django REST Framework, but these packages were not installed in the environment.fixInstall the required dependencies: `pip install nsj-gcf-utils Django djangorestframework django-cors-headers` or ensure they are listed in your `requirements.txt`. -
google.api_core.exceptions.PermissionDenied: 7 PERMISSION_DENIED: User lacks permission
cause The Google Cloud Function's service account does not have the necessary IAM permissions to access the Google Cloud resource (e.g., Firestore database, Cloud Storage bucket, Secret Manager secret) that the library is trying to use.fixGrant the appropriate IAM roles to the GCF's service account. For example, if accessing Firestore, add `Cloud Datastore User` (roles/datastore.user) or `Cloud Datastore Editor` (roles/datastore.editor). -
AttributeError: 'NoneType' object has no attribute 'request_id'
cause This typically occurs when `get_current_function_context()` is called, but the underlying Flask `request` object (or its mock) does not contain the expected headers (like `X-Request-ID`), causing `FunctionContext` properties to remain `None`.fixEnsure that the HTTP request object passed to your GCF handler contains the necessary headers (`X-Request-ID`, `X-User-ID`, `X-Entity-ID`, etc.) which `nsj-gcf-utils` expects to populate the context. For local testing, pass a mock request with these headers.
Warnings
- gotcha This library is not a general-purpose Google Cloud Functions utility. It has strong dependencies on Django and Django REST Framework, implying it's intended for specific architectural patterns where a Django/DRF application is deployed as a GCF. Attempting to use it in a pure, minimalist GCF environment without these frameworks will likely lead to `ModuleNotFoundError` or unexpected behavior.
- gotcha Google Cloud service clients (e.g., Firestore, Storage, Secret Manager) initialized by this library will rely on the default Google Cloud authentication mechanism, typically the GCF's associated service account. Incorrect IAM permissions for this service account will lead to `PermissionDenied` errors.
- gotcha The `FunctionContext` object populated by `get_current_function_context` relies on specific HTTP headers (e.g., `X-Request-ID`, `X-User-ID`, `X-Entity-ID`) being present in the incoming GCF request. If these headers are missing or not propagated, context properties might be `None` or raise `AttributeError`.
Install
-
pip install nsj-gcf-utils
Imports
- get_current_function_context
from nsj_gcf_utils.objects.function_context import get_current_function_context
- FunctionContext
from nsj_gcf_utils.objects.function_context import FunctionContext
- get_firestore_client
from nsj_gcf_utils.firestore import get_firestore_client
- GcfException
from nsj_gcf_utils.exception import GcfException
Quickstart
import json
from nsj_gcf_utils.objects.function_context import get_current_function_context
from nsj_gcf_utils.exception import GcfException
# Simulate a Flask-like request object for local testing
# In a real GCF environment, 'request' is provided by the framework.
class MockRequest:
def __init__(self, json_data, headers=None):
self._json_data = json_data
self.headers = headers if headers is not None else {}
@property
def json(self):
return self._json_data
def get_json(self):
return self._json_data
def get_data(self):
return json.dumps(self._json_data).encode('utf-8')
def my_gcf_handler(request):
try:
# Get the current function context
# In GCF, 'request' would be the actual Flask request object.
context = get_current_function_context(request)
# Access context properties (these would be populated by GCF headers)
print(f"Request ID: {context.request_id}")
print(f"User ID: {context.user_id}")
print(f"Entity ID: {context.entity_id}")
return "OK", 200
except GcfException as e:
print(f"Error: {e}")
return str(e), 500
except Exception as e:
print(f"Unexpected error: {e}")
return str(e), 500
# Example usage with a mock request (simulating a GCF invocation)
mock_headers = {
'X-Request-ID': 'mock-req-123',
'X-User-ID': 'mock-user-456',
'X-Entity-ID': 'mock-entity-789'
}
mock_json_payload = {'data': 'some_data'}
mock_request = MockRequest(mock_json_payload, headers=mock_headers)
response, status_code = my_gcf_handler(mock_request)
print(f"\nHandler Response: {response}, Status: {status_code}")
# Example of using Firestore client (requires actual GCP setup)
try:
# from nsj_gcf_utils.firestore import get_firestore_client
# firestore_client = get_firestore_client()
# print("Firestore client initialized successfully.")
print("\nUncomment Firestore client example for actual GCP interaction.")
except Exception as e:
print(f"Could not initialize Firestore client (expected outside GCF): {e}")