mongodb-rest-relay
v1.11.0
Published
Relay mongodb queries over HTTP REST. Great for Edge.
Downloads
659
Maintainers
Readme
mongodb-rest-relay
Relay mongodb queries over HTTP REST. Great for Edge.
Copyright (c) 2023 by Gadi Cohen. MIT Licensed.
Intro
mongodb-rest-relay
is meant to be a drop-in replacement for mongodb
, that sends
the actual request to the real mongodb
elsewhere over HTTP. It may be a better fit
for edge and serverless, depending on your use case. You get the advantages of
MongoDB's own REST service but with the same fixed and predictable pricing (but no
elastic scaling).
Quick Start
- Modify an existing edge or serverless function (or create one as usual):
- import { MongoClient } from "mongodb";
+ import { MongoClient } from "mongodb-rest-relay"
- const MONGO_URL = process.env.MONGO_URL;
+ const MONGO_URL = "http://localhost:3000/api/mongoRelay.ts"
+
+ // Optional: only if Mongo's ObjectId doesn't work in your edge environment.
+ // Before this, try set `{ browser: { crypto: false }}` in your app's package.json
- import { ObjectId } from "mongodb" // "bson"
+ import { ObjectId } from "mongodb-rest-relay"
+
+ export const runtime = 'edge' // if relevant (e.g. on Vercel)
// Then use as usual.
const client = new MongoClient(MONGO_URL);
That's it! Since the API is the same, there's nothing else to do. Note: only basic functionality / simple CRUD operations are supported (see notes at the end of the README).
See also the section on Caching below.
- You can run the other side of the relay as serverless
or servered (near your database), e.g.
pages/api/mongoRelay.ts
:
import { MongoClient } from "mongodb";
// There is also server/{nextServerless{App,Pages},vercelServerlessOther}
import makeExpressRelay from "mongodb-rest-relay/lib/server/express";
const MONGO_URL = process.env.MONGO_URL || "mongodb://127.0.0.1";
const client = new MongoClient(MONGO_URL);
export default makeExpressRelay((await client.connect()).db(/* dbName? */));
// or next app router: export const POST = makeRelay.... with correct import.
- Set the
MONGODB_RELAY_PASSWORD
environment variable to the same value on both sides.
Notes
Supported functionality:
insertOne()
,insertMany()
find()
- withsort()
,limit()
,skip()
,project()
.toArray()
,stream()
(yes! streaming!)
updateOne()
,updateMany()
replaceOne()
bulkWrite()
deleteOne()
,deleteMany()
countDocuments()
,estimatedDocumentCount()
- Open an issue or submit a PR for more :)
Init Options
new MongoClient(url, {
fetch: {}, // Additional options to past to ALL fetch requests (RequestInit)
});
Caching
mongodb-rest-relay
can take advantage of the
NextJS Cache
and
Vercel's Data Cache
for significantly faster repeat results and lower load on your database.
You should read these docs for a full picture but the basics are (for NextJS):
You need to call
mongodb-rest-relay
from within theapp
router, the functionality does not exist inpages
. So instead of e.g.pages/api/something.ts
, you wantapp/api/something/route.ts
, with the necessary changes.You can set your GLOBAL cache policy for ALL (internal)
fetch()
requests, using:new MongoClient(url, { fetch: { next: { revalidate: 1, // revalidate after this amount of time (in seconds) tags: ["myTag"], // can use revalidateTag("myTag") later. }, // or cache: "force-cache", // this lasts a long time, probably you don't want it :) }, });
Note: after
revalidate
seconds, the stale cache is still returned, and fresh data will be fetched in the background. For more info, see NextJS time-based revalidation.You can also set these options PER REQUEST. This involves a separate API call, so that you can still switch back between the original
mongodb
driver without polluting the real mongo options or failing type validation.- import { MongoClient } from "mongodb"; + import { MongoClient, setOptionsOnce } from "mongodb-rest-relay"; // ... setup the client, etc. + setOptionsOnce({ fetch: { next: { revalidate: 1 } } }); const result = await db.collection("test").find().toArray();
You can call
setOptionsOnce()
multiple times and the options will be used in that order (think of Jest'smockImplementationOnce()
).
The result is that even in next dev
you'll get output like this:
- ┌ POST /api/something 200 in 148ms
│
├──── POST http://localhost:3000/api/mongoRelay?coll=accounts&o.. 200 in 6ms (cache: HIT)
│
├──── POST http://localhost:3000/api/mongoRelay?coll=stars&op=f.. 200 in 3ms (cache: HIT)
│
├──── POST http://localhost:3000/api/mongoRelay?coll=sessions&o.. 200 in 2ms (cache: HIT)
│
├── 1 level ── POST http://localhost:3000/api/mongoRelay?coll=users&op=f.. 200 in 1ms (cache: HIT)
│
└── 1 level ── POST http://localhost:3000/api/mongoRelay?coll=likes&op=f.. 200 in 1ms (cache: HIT)
Note:
- Mutations (insert, update, delete, etc) will always set
{ cache: "no-store" }
. So caching is only applied to:find()
,findOne()
,estimatedDocumentCount()
,countDocuments()
.
TODO
- [x] ObjectID / Date support `:) - in next release!
- [x] streaming!
- [ ] aggregation - ask for it.
- [ ] Instead of sending MONGODB_RELAY_PASSWORD, just use it to sign requests.
- [x] Caching
- [x] Global options
- [x] Per-request options