mongodb-rest-relay
TypeScript icon, indicating that this package has built-in type declarations

1.11.0 • Public • Published

mongodb-rest-relay

Relay mongodb queries over HTTP REST. Great for Edge.

Copyright (c) 2023 by Gadi Cohen. MIT Licensed.

npm GitHub Workflow Status (with event) Coverage semantic-release TypeScript MIT License

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

  1. 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.

  1. 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.
  1. Set the MONGODB_RELAY_PASSWORD environment variable to the same value on both sides.

Notes

  • Supported functionality:

    • insertOne(), insertMany()
    • find() - with sort(), 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):

  1. You need to call mongodb-rest-relay from within the app router, the functionality does not exist in pages. So instead of e.g. pages/api/something.ts, you want app/api/something/route.ts, with the necessary changes.

  2. 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.

  3. 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's mockImplementationOnce()).

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:

  1. 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

Package Sidebar

Install

npm i mongodb-rest-relay

Weekly Downloads

43

Version

1.11.0

License

MIT

Unpacked Size

108 kB

Total Files

45

Last publish

Collaborators

  • gadicc