@angsana_consulting/api-core
v1.1.1
Published
Core API utilities for Angsana platform
Readme
@angsana_consulting/api-core
Foundation toolkit for building authenticated Retool APIs on Firestore. Ships a hardened base handler, query parser, and Firestore query builder that match the router’s standards.
1. Purpose
@angsana_consulting/api-core standardises how Retool-powered APIs interact with Firestore:
- Guard rails – only registered collections and operations execute.
- Declarative querying – parse complex
whereexpressions (AND/OR, parentheses, custom operators). - Efficient pagination – translates compatible filters to native Firestore queries with automatic client-side fallbacks.
- Observability – pluggable logger hook for duration/error reporting.
Use it inside Cloud Functions, Express handlers, or any service that fronts Firestore collections for Retool.
2. Architecture Overview
Retool Request ──▶ BaseRetoolApi.handleRequest()
│
├── validate collection + allowed ops
├── parse query params → Where AST
├── build Firestore query (native or hybrid)
├── run custom hooks (before*/after*)
└── return typed ApiResponse| Component | Description |
|-----------|-------------|
| BaseRetoolApi | Main request router, enforces collection policy and HTTP method guards. |
| whereParser | Tokenises/astifies Retool where strings (supports contains, startsWith, nested groups). |
| firestoreQueryBuilder | Converts AST → Firestore queries, falling back to client filtering when necessary. |
| types | Re-export of Firebase/Express types plus shared interfaces. |
3. Directory Structure
api-core/
├── src/
│ ├── handlers/
│ │ └── baseRetoolApi.ts # Core handler class
│ ├── parsers/
│ │ ├── whereParser.ts # WHERE clause tokenizer/parser
│ │ └── firestoreQueryBuilder.ts
│ ├── index.ts # Public exports
│ └── types/ # Type aliases + re-exports
├── dist/ # Compiled JS/typings
└── package.json4. Installation
npm install @angsana_consulting/api-corePeer dependencies: firebase-admin (v11/v12) and express.
5. Quick Start
import { BaseRetoolApi, CollectionRegistry } from '@angsana_consulting/api-core';
import { db } from 'firebase-admin';
const collections: CollectionRegistry = {
ClientNumbers: {
autoId: false,
customIdField: 'number',
allowedOperations: ['GET', 'POST', 'PUT'],
notes: 'Client phone numbers synced from Retool'
}
};
const handler = new BaseRetoolApi(db(), collections, 'dialer', console);
export const retoolApi = onRequest((req, res) => handler.handleRequest(req, res));- Register every collection with allowed HTTP verbs.
- Optionally provide
customHandlersfor lifecycle hooks. - Deploy as an HTTPS/Express handler (e.g., Cloud Functions, Cloud Run).
6. Advanced Querying
Supported WHERE Syntax
status==active AND (priority>=3 OR country in['GB','US'])
createdAt>=2024-01-01 AND createdAt<2024-02-01
message contains "callback failed"- Logical groups with parentheses.
- Operators:
==,!=,<,<=,>,>=,in,array-contains,array-contains-any,startsWith,contains. - Timestamp hints (
t,x,createdAt, etc.) auto-cast to Firestore timestamps.
Firestore Compatibility
- Automatic detection when filters can run entirely server-side.
- Mixed inequality fields or OR trees fall back to client filtering with warning messages.
- Pagination helpers (
limit,startAfter) work alongside the hybrid model.
7. Custom Hooks
Every collection entry can declare async hooks:
customHandlers: {
beforeCreate: async (data, ctx) => ({ ...data, createdAt: Date.now() }),
afterCreate: async (docRef, data) => audit(docRef.id, data),
beforeDelete: async (docId, ctx) => ctx.userId === 'admin'
}- Returning modified data allows sanitisation/enrichment.
- Throwing an error aborts the request with a 400/500.
beforeDeletereturningfalsedenies the deletion.
8. Responses & Errors
Every route returns the standard ApiResponse interface:
{
"success": true,
"count": 25,
"documents": [
{ "id": "abc123", "data": { "number": "+44123..." } }
],
"nextPageToken": "xyz"
}Failures include contextual information:
{
"error": "Operation not allowed",
"allowed": ["GET", "POST"]
}9. Logging Integration
Pass any logger with info/error methods (e.g., pino, @angsana_consulting/utils logger wrappers). The handler automatically logs request duration and failures for observability parity with the router.
10. Publishing
The package ships compiled JS in dist/. Run:
cd packages/api-core
npm run build
npm publish --access publicSee PUBLISHING.md for the workspace workflow.
