Module for Apostol CRM1.
App Server is a C++ HTTP/RESTful server module for the Apostol (C++20) framework. It runs inside Apostol worker processes and handles all incoming HTTP requests routed to the /api/ path prefix.
Key characteristics:
- Written in C++20 using an asynchronous, non-blocking I/O model based on the epoll API — suitable for high-throughput, low-latency deployments.
- Connects directly to PostgreSQL via the
libpqlibrary. Every API request is dispatched to a PL/pgSQL function in the database; all business logic lives in the database, not in the module itself. - Implements REST (Representational State Transfer) conventions for remote procedure calls over HTTP.
- Supports multiple authentication methods: Bearer JWT token, Session + Secret headers, and Cookie-Based authentication (
__Secure-AT). - Response format is always
application/json. - Built-in endpoints (
/ping,/time) require no database interaction and are handled entirely in C++. All other endpoints are forwarded to the PostgreSQLdaemonschema functions.
Apostol runs a master process that forks N worker processes. Each worker loads a set of modules. AppServer is one such module — it registers itself as the handler for any request whose path starts with /api/. When a matching request arrives:
- The worker's event loop (epoll) accepts the connection and reads the HTTP request.
AppServerinspects theAuthorizationheader to determine the authentication context.- Based on the authentication result, it constructs a parameterised SQL call and submits it to the PostgreSQL connection pool asynchronously:
- Bearer JWT (valid token) →
daemon.fetch - Session + Secret headers →
daemon.session_fetch - No credentials →
daemon.unauthorized_fetch - Expired token with refresh cookie → auto-refreshes via
daemon.refresh_token, then callsdaemon.fetchwith the new token
- Bearer JWT (valid token) →
- When the query result arrives, the module serialises it as JSON and sends the HTTP reply.
- Base endpoint: http://localhost:8080
- All endpoints return a JSON object.
- All time and timestamp fields are in milliseconds (Unix epoch).
2XX— success.4XX— client error (malformed request, authentication failure, resource not found, etc.).5XX— server error. The outcome of the operation is unknown — do not assume failure without verifying.
Any endpoint may return an error. The response body will contain an error object:
{
"error": {
"code": 404,
"message": "Not Found"
}
}Error codes >= 10000 are divided by 100 to map to standard HTTP status codes (e.g. 40401 → 404).
- For
GETendpoints, all parameters are passed as query string values. - For
POSTendpoints, parameters may be sent as a query string or as the request body. Supported content types for the request body:application/jsonapplication/x-www-form-urlencodedmultipart/form-data
- Parameters may be sent in any order.
- The module accepts
GET,POST,PUT,PATCH,DELETE, andOPTIONS. All other HTTP methods return405 Method Not Allowed.
Two optional query parameters influence how PostgreSQL query results are serialised:
| Parameter | Allowed values | Effect |
|---|---|---|
result_object |
true, false |
When true, wraps the result in {"result": ...} |
result_format |
object, array, null |
Forces the JSON serialisation format of the result set. Paths containing /list default to array. |
Access requires a Bearer access token, Session + Secret headers, or Cookie-Based authentication.
The access token must be present in the Authorization HTTP header of every authenticated request.
Format:
Authorization: Bearer <access_token>
The access token is a JSON Web Token (RFC 7519). It is issued by the AuthServer module (which is part of the same Apostol application).
The module validates the token locally using the configured provider secrets/keys before forwarding the request to the database. Supported algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512.
Tokens are also accepted from the __Secure-AT cookie (set by the server after login); the accompanying refresh token is read from __Secure-RT.
Example request:
GET /api/v1/whoami HTTP/1.1
Host: localhost:8080
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiIDogImFjY291bnRzLnNoaXAtc2FmZXR5LnJ1IiwgImF1ZCIgOiAid2ViLXNoaXAtc2FmZXR5LnJ1IiwgInN1YiIgOiAiZGZlMDViNzhhNzZiNmFkOGUwZmNiZWYyNzA2NzE3OTNiODZhYTg0OCIsICJpYXQiIDogMTU5MzUzMjExMCwgImV4cCIgOiAxNTkzNTM1NzEwfQ.NorYsi-Ht826HUFCEArVZ60_dEUmYiJYXubnTyweIMgThese endpoints are handled entirely in C++ and require no database access or authentication.
GET /api/v1/pingTests connectivity to the REST API.
Parameters: none
Response:
{}GET /api/v1/timeTests connectivity and returns the current server time.
Parameters: none
Response:
{
"serverTime": 1583495795455
}serverTime is the number of milliseconds since the Unix epoch (UTC).
All paths under /api/ that are not handled by the built-in endpoints above are forwarded to PostgreSQL. The database function called depends on the authentication context:
| Context | PostgreSQL function |
|---|---|
| Bearer JWT token | daemon.fetch(token, method, path, payload, agent, host) |
| Session + Secret headers (Basic) | daemon.session_fetch(session, secret, method, path, payload, agent, host) |
| No credentials (when enabled) | daemon.unauthorized_fetch(method, path, payload, agent, host) |
The full set of application endpoints is therefore defined entirely in the project's database, in the daemon schema PL/pgSQL functions. See your project's repository for endpoint documentation.
Follow the build and installation instructions for Apostol (C++20).
Footnotes
-
Apostol CRM — a template project built on the A-POST-OL (C++20) and PostgreSQL Framework for Backend Development frameworks. ↩