@taskless/mongo-data-api
v0.5.2
Published
Mongo Data API client using fetch, suitable for lambda and edge functions
Downloads
16
Maintainers
Readme
A Mongo-like API for accessing the http-based Mongo Data API. Uses BSON to provide access to standard Mongo data types. BYO
fetch()for maximum portability.
Usage
import { MongoClient } from "@taskless/mongo-data-api";
const mc = new MongoClient({
/** @type URL | string */
endpoint: new URL(process.env.MONGO_HTTP_URL ?? "[not defined]"),
/** @type string */
dataSource: process.env.MONGO_HTTP_DATA_SOURCE ?? "[not defined]",
/* See "Authentication" below */
auth: {
/* ... */
},
});
const { data, error } = await mc.findOne({
/* good 'ole mongo! See the Collection Methods for what's available */
});Authentication
| Authentication Method | Supported | | :-------------------- | :-------: | | API Key | ✅ | | Email & Password | ✅ | | Custom JWT | ✅ | | Bearer | ⚠️ |
Using a Data API api key (preferred)
{
// ...
auth: {
/** @type string */
apiKey: process.env.MONGO_HTTP_API_KEY ?? "[not defined]",
},
}Using Email and Password
{
// ...
auth: {
/** @type string */
email: process.env.MONGO_EMAIL ?? "",
/** @type string */
password: process.env.MONGO_PASSWORD ?? "",
},
}Using a custom JWT
{
// ...
auth: {
/** @type string */
jwtTokenString: request.headers.get("jwt"),
},
}Using Bearer Auth (required for browser)
Read more about authenticating Realm users in the browser
{
// ...
auth: {
/** @type string */
bearerToken: tokenFromRealm,
},
}Supported Methods and API
Create a Mongo Client
const client = new MongoClient(options);options- MongoClient optionsoptions.endpoint-string | URLan endpoint for sending requests to. Your Data API Endpoint is available at your Mongo Data API UIhttps://cloud.mongodb.com/v2/<projectId>#/dataAPI, where<projectId>is your project ID. A single Data API is usable for the entire project, with individual data sources routing to specific atlas instances.options.dataSource-stringtheData Sourcefor your Data API. On the Data API UI, this is the "Data Source" column, and usually is either a 1:1 mapping of your cluster name, or the defaultmongodb-atlasif you enabled Data API through the Atlas Admin UI.options.auth-AuthOptionsone of the authentication methods, either api key, email & password, or a custom JWT string. At this time, only Credential Authentication is supported.options.fetch?- A customfetchfunction conforming to the native fetch API. We recommend cross-fetch, as it asserts a complaintfetch()interface and avoids you having to dofetch: _fetch as typeof fetchto satisfy the TypeScript compiler
Select a Database
const db = client.db(databaseName);databaseName-stringthe name of the database to connect to
Select a Collection
const collection = db.collection<TSchema>(collectionName);collectionName-stringthe name of the collection to connect to<TSchema>- generic A Type or Interface that describes the documents in this collection. Defaults to the generic MongoDBDocumenttype
Collection Methods
The following Data API resources are supported
| resource | support |
| :----------- | :-----: |
| findOne | ✅ |
| find | ✅ |
| insertOne | ✅ |
| insertMany | ✅ |
| updateOne | ✅ |
| updateMany | ✅ |
| replaceOne | ✅ |
| deleteOne | ✅ |
| deleteMany | ✅ |
| aggregate | ✅ |
Should Data API add support for other resources, the callApi method allows you to pass arbitrary JSON to a Data API resource. mongo-data-api automatically merges the dataSource, database, and collection parameters in if not specified.
Return Type
All collection methods return an object containing data? and error?. This avoids throwing during requests, making it easier to handle the response without nesting try/catch operations.
interface DataAPIResponse {
data?: TSchema;
error?: DataAPIError;
}Specifying Operation Names
To help with tracing and debugging, any Mongo Data API operation can be named by passing a string as the first parameter. This value is converted to the x-realm-op-name header and can be seen in the Mongo Data API logs.
const { data, error } = await collection./*operation*/("operation name for tracing", filter, options);Methods
findOne
const { data, error } = await collection.findOne(filter, options);filter?-Filter<TSchema>A MongoDB Query Filteroptions?- Query optionsoptions.projection?-DocumentA MongoDB Query Projection
find
const { data, error } = await collection.find(filter, options);filter?-Filter<TSchema>A MongoDB Query Filteroptions?Query optionsoptions.projection?-DocumentA MongoDB Query Projectionoptions.sort?-SortA MongoDB Sort Expressionoptions.limit?-numberThe maximum number of matched documents to include in the returned result set. Each request may return up to 50,000 documents.options.skip?-numberThe number of matched documents to skip before adding matched documents to the result set.
insertOne
const { data, error } = await collection.insertOne(document);document-TSchemaThe document to insert
insertMany
const { data, error } = await collection.insertMany(documents);documents-TSchema[]The documents to insert
updateOne
const { data, error } = await collection.updateOne(filter, update, options);filter-Filter<TSchema>A MongoDB Query Filterupdate-UpdateFilter<TSchema> | Partial<TSchema>A MongoDB Update Expression that specifies how to modify the matched documentoptions?Query optionsoptions.upsert-booleanThe upsert flag only applies if no documents match the specified filter. If true, the updateOne action inserts a new document that matches the filter with the specified update applied to it.
updateMany
const { data, error } = await collection.updateMany(filter, update, options);filter-Filter<TSchema>A MongoDB Query Filterupdate-UpdateFilter<TSchema> | Partial<TSchema>A MongoDB Update Expression that specifies how to modify the matched documentoptions?Query optionsoptions.upsert-booleanThe upsert flag only applies if no documents match the specified filter. If true, the updateOne action inserts a new document that matches the filter with the specified update applied to it.
replaceOne
const { data, error } = await collection.replaceOne(
filter,
replacement,
options
);filter-Filter<TSchema>A MongoDB Query Filterreplacement-WithoutId<TSchema>The replacement document, without an_idattributeoptions?Query optionsoptions.upsert-booleanThe upsert flag only applies if no documents match the specified filter. If true, the updateOne action inserts a new document that matches the filter with the specified update applied to it.
deleteOne
const { data, error } = await collection.deleteOne(filter);filter-Filter<TSchema>A MongoDB Query Filter
deleteMany
const { data, error } = await collection.deleteMany(filter);filter-Filter<TSchema>A MongoDB Query Filter
aggregate
const { data, error } = await collection.aggregate<TOutput>(pipeline);pipeline-Document[]A MongoDB Aggregation Pipeline<TOutput>- generic ADocumentlike object that describes the output of the aggregation pipeline
callApi
const { data, error } = await collection.callApi<T>(method, body);method-stringA supported Mongo Data API Request methodbody-Record<string, unknown>An arbitrary key/value JSON-like data structure representing the body payload sent to the Mongo Data API<T>- generic Describes the return type ofdataon a successful API call
Errors
Requests via fetch() have their resposne codes checked against the Data API Error Codes and on error, set the error property of the response to a MongoDataAPIError.
error.code-numberContains the HTTP error code from the Mongo Data APIerror.message-stringContains the response status text or error message included from the Data API call
FAQ
- Why is
mongodbin the dependencies? TypeScript requires it, however, the mongodb dependency is types-only and will not be included in your built lambda when usingtsc,rollup,webpack, etc. You can verify that mongo is not included by looking at the CommonJS build. - Why is
node-fetch'sfetchnot of the correct type?node-fetch'sfetchisn't a truefetchand wasn't typed as one. To work around this, you can either usecross-fetchwhich types thefetchAPI through a type assertion, or perform the type assertion yourself:fetch: _fetch as typeof fetch. It's not ideal, but with properfetchcoming to node.js, it's a small inconvienence in the short term. - How do I retry failed
fetchcalls?fetch-retry(github) is an excellent library. You can also use a lower level retry tool likep-retry(github) if you want to manage more than just thefetch()operation itself.
License
This library started out as a fork of the excellent deno atlas_sdk module, optimized for node.js.
MIT
