This project provides a TypeScript implementation inspired by the deprecated Atlas Data API, utilizing H3 for the HTTP server, Zod for schema validation, and the official MongoDB Node.js Driver.
- The HTTP server supports both JSON and EJSON content types.
- Endpoint request bodies mirror the structure of the MongoDB Node.js Driver methods, with the addition of
dataSource,database, andcollectionfields to specify the target, similar to the Atlas Data API. - For detailed usage examples and endpoints, refer to the:
test/client.ts,test/custom/*,test/default/*or the Endpoints documentation.
To run this application, ensure you have Node.js installed. Then, execute the following commands in the project's root directory:
npm install: Installs all necessary dependencies.npm start: Starts the application server.
The application starts with the following default environment variable settings:
APP_NAME=delbridge-typescript-data-apiDATA_SOURCES='{"local": "mongodb://127.0.0.1:27017"}'JWT_SECRET=something-secureSERVER_ADDRESS=127.0.0.1SERVER_PORT=8080
These default values are defined in ./src/envs.ts. You can override them by setting environment variables. For more information, see the Environment Variables section.
Here are example curl commands to test insertOne and findOne operations against a running TypeScript Data API instance.
# Insert One Document
curl -s "http://127.0.0.1:8080/defaults/insertOne" \
-X POST \
-H "Content-Type: application/ejson" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3NDkwNjk3MDF9.aLgkBEzvsyDCRtpfAmIYxCxMI1ck9A4EFu6BipwARbM" \
-d '{
"dataSource": "local",
"database": "test",
"collection": "users",
"document": {
"name": "john"
}
}'
# Find One Document
curl -s "http://127.0.0.1:8080/defaults/findOne" \
-X POST \
-H "Content-Type: application/ejson" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3NDkwNjk3MDF9.aLgkBEzvsyDCRtpfAmIYxCxMI1ck9A4EFu6BipwARbM" \
-d '{
"dataSource": "local",
"database": "test",
"collection": "users",
"filter": {
"name": "john"
},
"options": {
"projection": {"_id": 0, "name": 1}
}
}'While this application isn't a drop-in replacement for the Atlas Data API, migrating is straightforward. The differences aim to align closely with the MongoDB Node.js Driver's parameter structure, offer greater customization and newer functions.
- Atlas Data API: Used an
apiKeyheader for authentication. - Delbridge TypeScript Data API: Uses JWT (JSON Web Token) authentication. Requests must include an
Authorizationheader with aBearertoken.
The authentication functionality is implemented in the is-authenticated middleware, which you can customize.
- Atlas Data API: Linked authorization rules (e.g.,
No Access,Read Only,Read and Write,Custom Access) to theapiKey. - Delbridge TypeScript Data API: Currently, this application does not implement granular authorization beyond authentication. All authenticated users have full access.
- Atlas Data API:
https://<atlas-data-api-base-url>/action/<function-name> - Delbridge TypeScript Data API:
- Standard MongoDB operations:
http://<your-host>:<your-port>/defaults/<function-name> - Custom functions:
http://<your-host>:<your-port>/custom/<function-name>
- Standard MongoDB operations:
Obs: The base URL depends on your deployment and the SERVER_ADDRESS and SERVER_PORT environment variables.
Request bodies for the Atlas Data API are detailed in its OpenAPI documentation. Generally, Atlas Data API used a flat structure for MongoDB function parameters.
This application, however, mirrors the MongoDB Node.js Driver's structure, often nesting options within an options object. Here's a comparison for a find operation:
// Atlas Data API Body Structure
const AtlasDataAPIBody = {
dataSource: "local",
database: "todo",
collection: "tasks",
filter: {
status: "complete",
},
projection: {
// Flat options
text: 1,
completedAt: 1,
},
sort: {
// Flat options
completedAt: 1,
},
limit: 10, // Flat options
};
// TS Data API Body Structure
const TSDataAPIBody = {
dataSource: "local",
database: "todo",
collection: "tasks",
filter: {
status: "complete",
},
options: {
// Options nested under an 'options' key
projection: {
text: 1,
completedAt: 1,
},
sort: {
completedAt: 1,
},
limit: 10,
},
};The following curl commands are a comparison between a find operation in Atlas Data API and Delbridge TypeScript Data API.
# Atlas Data API
curl -s "https://<atlas-data-api-base-url>/action/find" \
-X POST \
-H "Content-Type: application/ejson" \
-H "Accept: application/json" \
-H "apiKey: $API_KEY" \
-d '{
"dataSource": "local",
"database": "todo",
"collection": "tasks",
"filter": {
"status": "complete"
},
"projection": {
"text": 1,
"completedAt": 1
},
"sort": {
"completedAt": 1
},
"limit": 10
}'
# Delbridge TypeScript Data API
curl -s "http://<delbridge-typescript-data-api-base-url>/defaults/find" \
-X POST \
-H "Content-Type: application/ejson" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"dataSource": "local",
"database": "todo",
"collection": "tasks",
"filter": {
"status": "complete"
},
"options": {
"projection": {
"text": 1,
"completedAt": 1
},
"sort": {
"completedAt": 1
},
"limit": 10
}
}'The configuration for environment variables, including their management, parsing, and default values, is located in envs.ts.
-
APP_NAME- Specifies the application name used in the MongoDB Client connection.
- This helps identify the source of operations when analyzing MongoDB queries, logs, and performance.
- Default:
delbridge-typescript-data-api
-
DATA_SOURCES- Defines the data sources available to the Data API.
- This must be a stringified JSON object where each key is a data source name and its corresponding value is the MongoDB connection URI.
- Example:
To configure two data sources,
localandatlas, you would set the environment variable as follows:This configuration connects:DATA_SOURCES='{"local": "mongodb://127.0.0.1:27017/mydb", "atlas": "mongodb+srv://user:pwd@cluster-name.123abc.net/anotherdb"}'localtomongodb://127.0.0.1:27017/mydbatlastomongodb+srv://user:pwd@cluster-name.123abc.net/anotherdb
- Default:
'{"local": "mongodb://127.0.0.1:27017"}'
-
JWT_SECRET- The secret key used to sign and verify JSON Web Tokens (JWTs) for authentication.
- Important: This should be a strong, unique, and private string.
- Default:
something-secure
-
SERVER_ADDRESS- The IP address to which the server will bind.
- Default:
127.0.0.1(listens to localhost)
-
SERVER_PORT- The port number to which the server will bind.
- Default:
8080
When exchanging data with the API, understanding the difference between JSON and EJSON is crucial for data integrity, especially when working with MongoDB's rich BSON types.
-
Standard
JSON: If you use the standardJSONformat, the data types available to your application are limited to:nullbooleannumberstringobjectarray
-
EJSON(Extended JSON): EJSON allows your application to utilize all data types from theBSONspecification. This includes, but is not limited to, types like:DoubleObjectIdDate(represented as{$date: "YYYY-MM-DDTHH:mm:ss.SSSZ"})UUID(represented as{$uuid: "..."})- And many others.
Recommendation:
For users of this application, it is highly recommended to use the EJSON content type format. This ensures that field values retain their original BSON data types, preventing data loss or unintended type coercion when interacting with MongoDB. The following code demonstrates that when you stringify and parse a document containing ObjectId and Date fields using standard JSON, these fields are converted to string. In contrast, using EJSON preserves their original data types.
import { EJSON, ObjectId } from "bson";
const document = {
_id: new ObjectId(),
now: new Date(),
};
const documentEJSON = EJSON.parse(EJSON.stringify(document));
const documentJSON = JSON.parse(JSON.stringify(document));
console.log("EJSON:", documentEJSON);
/*
EJSON: {
_id: new ObjectId('68373f58236c235ceae63814'),
now: new Date(2025-05-28T16:52:40.408Z)
}
*/
console.log("JSON:", documentJSON);
/*
JSON: {
_id: '68373f58236c235ceae63814',
now: '2025-05-28T16:52:40.408Z'
}
*/To create your own JSON Web Token (JWT), you can use the script provided in the file ./test/jwt.ts. Follow these steps to generate a JWT:
-
Ensure you have the required dependencies installed in your project by running:
npm install
-
Execute the following command in your terminal to run the script:
npx ts-node ./test/jwt.ts
By default, this script generates a JWT using the secret key specified in the JWT_SECRET environment variable. The payload of the token will be empty unless you modify the script to include additional data.
If you want to customize the payload or use a different secret, you can edit the script located at ./test/jwt.ts. For example, you can add fields to the payload or change the signing algorithm as needed.