Coder Social home page Coder Social logo

florianpallas / monzod Goto Github PK

View Code? Open in Web Editor NEW
1.0 1.0 0.0 128 KB

Single Source of Truth & Database Layer Validation for MongoDB ⚡ powered by Zod ❤️

License: MIT License

TypeScript 100.00%
mongodb typescript zod bson convert json schema validate

monzod's Introduction

Monzod

Single Source of Truth & Database Layer Validation for MongoDB ⚡ powered by Zod ❤️

npm version test codecov npm weekly downloads bundlephobia license

Installation

Monzod is available on npm and can be installed with your favorite package manager. It requires MongoDB and Zod as peer dependencies.

npm  install monzod mongodb zod
pnpm install monzod mongodb zod
yarn add     monzod mongodb zod

Usage

⚠️ Monzod is still in early development and the API is subject to change. Expect breaking changes even for minor version bumps. Use at your own risk. Data loss may occur.

Models

The idea behind using Zod together with MongoDB is to have a type safe interface to the database. This requires all data that is put into the database to be validated beforehand. This is where Zod comes in. Zod is a TypeScript-first schema declaration and validation library. It allows you to define a schema for our entities and validate them.

Monzod provides a few additions that make this process easier. A basic model definition could look like this:

import { mz } from "monzod";

// Define your schema once!
export const bookSchema = z.object({
  _id: mz.objectId(), // Monzod adds support for BSON types within your schemas
  title: z.string(),
  description: z.string().optional(),
  author: z.string(),
});

export type Book = z.infer<typeof bookSchema>; // Zod allows you to infer the type from the schema

Mapping

The BSON types that MongoDB uses are ideally kept close to the database layer. We can define a few more objects that use the TypeScript analogues of those types, so we can use them in our application code. But now we have to keep track of even more schemas and convert objects between them.

Most often you will be mapping objectIds to strings. Lets see how we can do that with Monzod.

⚠️ Monzod currently only supports mapping the ObjectId type

import { mapSchema, mapEntity } from "monzod";

// Mapping schemas

const bookDTO = mapSchema(bookSchema);
type BookDTO = z.infer<typeof bookDTO>;
//    ^? type BookDTO = { id: string; ... }

// Mapping entities

const book = await bookCollection.findOne({ ... });
//     ^? const book: { _id: ObjectId; ... }

const bookDTO = mapEntity(book, bookDTO);
//     ^? const bookDTO: { id: string; ... }

bookDTOSchema.parse(bookDTO); // Mapped entities are compatible with their corresponding schemas

But sometimes you want more than just map ids. For example you might want to remove the author field in your custom schema. Easy! Just use what you already know about Zod and what you learned above.

import { mapSchema, mapEntity } from "monzod";

const anonymousBookSchema = mapSchema(bookSchema).omit({ author: true });

const mapAnonymousBook = (book: Book) => {
  const mappedBook = mapEntity(book);
  delete mappedBook.author; // You will probably find a nicer way to do this
  return mappedBook;
}

const book = await bookRepository.findOne({ ... });
const anonymousBook = mapAnonymousBook(book);

Validation

MongoDB is schemaless, but that does not mean that we should not validate our data. In fact, we should validate our data as much as possible. Zod provides validation on the application layer, but we can also validate our data on the database layer. MongoDB provides JSON / BSON schema validation out of the box, preventing invalid state from being persisted.

Monzod uses that existing functionality and provides a way to generate that schema from your models.

⚠️ Schema conversion is limited to only a few types right now. See the section below for all supported types.

import { bsonSchema } from "monzod";
import { db } from "./db";

// What MongoDB provides

const bookCollection = db.collection<Book>("books", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["_id", "title", "description", "author"],
      properties: {
        _id: { bsonType: "objectId" },
        title: { bsonType: "string" },
        // ...
        // This is tedious and error prone.
        // It is also completely detached from the actual schema.
        // If you miss a field here, your app will error out.
      },
    },
  },
});

// Do this instead

const bookCollection = db.collection<Book>("books", {
  ignoreUndefined: true, // Turn off undefined to null conversion
  validator: { $jsonSchema: bsonSchema(bookSchema) }, // Let Monzod do the heavy lifting
});

Notice the ignoreUndefined: true. This tells MongoDB to only accept null for nullable fields. Otherwise the documents you retrieve from the database could contain null values even though your schema may use optional values (undefined), causing issues while parsing.

Supported types

Zod
Primitives
  • String
  • Number
  • BigInt
  • Boolean
  • Date
  • Symbol
Empty Types
  • Undefined
  • Null
  • Void
Catch All Types
  • Any
  • Unknown
Never Type
  • Never
Complex Types
  • Array
  • Object
  • Union
  • Tuple
  • Record
  • Map
  • Set
  • Function
  • Literal
  • Enum
  • NativeEnum
Wrappers
  • Optional
    • within objects
    • within arrays
    • within tuples
    • within sets
    • within maps
    • within records
  • Nullable
Structure
  • Recursive schemas
  • Cyclic schemas
BSON
  • ObjectId
  • Binary
  • BSONRegExp
  • BSONSymbol
  • Code
  • DBRef
  • Decimal128
  • Double
  • Int32
  • Long
  • MaxKey
  • MinKey

monzod's People

Contributors

florianpallas avatar github-actions[bot] avatar

Stargazers

 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.