npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

owi-validator

v2.0.2

Published

A lightweight, Zod-like, schema-first validation library for TypeScript and JavaScript.

Readme

owi-validator

owi-validator is a beginner-friendly, lightweight validation library built with JavaScript. It features a powerful, dual-engine architecture offering both a simple chainable API (Legacy) and a robust, Zod-like Schema-First API for complex data structures and TypeScript inference.

Coverage Status Github All Releases GitHub forks GitHub stars GitHub issues

Installation

You can install owi-validator using npm or yarn:

npm install owi-validator
# OR
yarn add owi-validator

🚀 The Schema Engine (New API)

The new Schema Engine is highly recommended for modern applications. It is heavily inspired by Zod and allows you to define a schema once, infer TypeScript types automatically, and validate complex, nested payloads safely.

1. Primitives

You can validate basic data types using primitive builders. You can optionally pass a custom error message to be used if the type check fails.

const { owi } = require('owi-validator');

const stringSchema = owi.string();
const numberSchema = owi.number("Must be a valid number"); // Custom type error
const boolSchema = owi.boolean({ error: "Must be true or false" });

stringSchema.parse("hello"); // Returns "hello"
numberSchema.parse(42); // Returns 42

Primitive Constraints: You can chain constraints to primitives. You can optionally pass a custom error message for the constraint as the second argument.

  • Strings: .min(len, msg), .max(len, msg), .email(msg), .regex(pattern, msg), .url(msg)
  • Numbers: .min(val, msg), .max(val, msg)
owi.string().min(3, "Too short!").max(20).email("Invalid email").parse("[email protected]");
owi.number().min(18, "You must be an adult").max(99).parse(25);

2. Objects and Unknown Keys

Validate objects by defining their "shape".

const userSchema = owi.object({
  name: owi.string().min(2),
  age: owi.number()
});

Unknown Keys (Passthrough by default): By default, owi.object() allows unknown keys and passes them through to the output. This is great for wrapping objects like Express req objects.

You can modify this behavior:

// 1. Passthrough (Default) - Allows unknown keys and keeps them in the output
userSchema.parse({ name: 'John', age: 30, admin: true }); // Returns { name: 'John', age: 30, admin: true }

// 2. Strict - Throws an error on unknown keys
userSchema.strict().parse({ name: 'John', age: 30, admin: true }); // Throws OwiError!

// 3. Strip - Silently remove unknown keys
userSchema.strip().parse({ name: 'John', age: 30, admin: true }); // Returns { name: 'John', age: 30 }

3. Arrays, Enums, and Unions

// Arrays
const tagsSchema = owi.array(owi.string()).min(1, "At least one tag required");
tagsSchema.parse(["javascript", "nodejs"]);

// Enums (Restrict values to a specific set)
const statusSchema = owi.enum(["active", "inactive"], { error: "Invalid status" });
statusSchema.parse("active");

// Unions (Allow data to match one of several schemas)
const stringOrNumber = owi.union([owi.string(), owi.number()]);
stringOrNumber.parse("hello"); // Valid
stringOrNumber.parse(42);      // Valid

4. Optional and Default Values

const schema = owi.object({
  bio: owi.string().optional(),
  role: owi.string().default('user')
});

schema.parse({}); 
// Returns: { bio: undefined, role: 'user' }

5. Transforms and Refinements

You can mold the data into the shape you want using .transform(), and add custom validation logic using .refine().

// Transform a string to uppercase
const upperString = owi.string().transform(val => val.toUpperCase());
upperString.parse('hello'); // Returns 'HELLO'

// Custom refinement logic
const evenNumber = owi.number().refine(val => val % 2 === 0, 'Must be an even number');
evenNumber.parse(4); // Valid

6. Advanced Validation with superRefine

For complex, cross-field validation, use .superRefine((data, ctx) => { ... }). This allows you to inspect the entire object and attach errors to specific paths.

const rentalSchema = owi.object({
  rentalType: owi.enum(["FIXED", "FLAT"]),
  dailyRate: owi.number().optional(),
  flatRate: owi.number().optional()
}).superRefine((data, ctx) => {
  if (data.rentalType === "FIXED" && data.dailyRate === undefined) {
    ctx.addIssue({ path: ["dailyRate"], message: "dailyRate is required for FIXED rentals" });
  }
  if (data.rentalType === "FLAT" && data.flatRate === undefined) {
    ctx.addIssue({ path: ["flatRate"], message: "flatRate is required for FLAT rentals" });
  }
});

7. Execution: parse vs safeParse

parse(data): Throws an OwiError if validation fails. The error object contains a detailed array of issues indicating exactly where the validation failed.

try {
  schema.parse(badData);
} catch (error) {
  console.log(error.errors); // Array of { path: (string|number)[], message: string }
}

safeParse(data): Does NOT throw. It returns an object containing { success: true, data } or { success: false, error }.

const result = schema.safeParse(badData);
if (!result.success) {
  console.log(result.error.errors);
} else {
  console.log(result.data); // Safely parsed and typed data
}

8. TypeScript Support

Extract the inferred TypeScript type from any schema using Types.Infer<typeof schema>.

import { owi, Types } from 'owi-validator';

const personSchema = owi.object({
  name: owi.string(),
  age: owi.number()
});

type Person = Types.Infer<typeof personSchema>;
// Equivalent to: { name: string; age: number; }

🏛️ The Legacy API

The original owi-validator API evaluates rules immediately upon execution. It is fully supported for backwards compatibility.

Basic usage

const { owi, validate } = require("owi-validator");

const schema = {
  productName: owi("Laptop")
    .string()
    .min(2)
    .error('product name must be atleast 2 characters long')
    .required()
    .exec(),
  price: owi(2000)
    .number()
    .error('price must be a number')
    .required()
    .exec(),
}

const check = validate(schema);

if (check.isValid) {
  // validation successful
} else {
  console.log(check.errors); // Array of validation errors
}

Using as Express Middleware

const { owi, validate } = require("owi-validator");

const validateData = (req, res, next) => {
  const check = validate({
    name: owi(req.body.name).string().min(2).required().error("Name must be atleast 2 characters long").exec(),
    email: owi(req.body.email).email().required().error("Please enter a valid email").exec(),
    password: owi(req.body.password).string().min(6).max(10).exec(),
  });

  if (check.isValid) {
    next();
  } else {
    return res.status(400).json({ errors: check.errors });
  }
};

Legacy Methods Reference

| Method | Description | Example Usage | |--------|-------------|---------------| | max() | Validates max string length or max integer value | owi(string).max(20).exec() | | min() | Validates min string length or min integer value | owi(integer).min(20).exec() | | equal() | Validates the equality of a parameter | owi(20).equal(20).exec() | | number() | Checks if parameter is a valid number | owi(20).number().exec() | | string() | Checks if parameter is a valid string | owi("20").string().exec() | | boolean() | Checks if parameter is a valid boolean | owi(true).boolean().exec() | | length() | Validates the exact length of a string/integer | owi("foo").length(3).exec() | | email() | Checks if parameter is a valid email | owi("[email protected]").email().exec() | | telephone() | Checks if parameter is a valid telephone | owi("+1 000 4243 9889").telephone().exec() | | url() | Checks if parameter is a valid url | owi("https://example.com").url().exec() | | date() | Checks if parameter is a valid date | owi("04-06-2020").date().exec() | | array() | Checks if parameter is an array | owi([]).array().exec() | | card() | Validates a specific credit card type | owi("...").card('master').exec() | | regex() | Checks if parameter matches a regex pattern | owi("john").regex(/[a-zA-Z]/).exec() | | required() | Ensures a parameter is supplied | owi(param).required().exec() | | optional() | Makes a parameter optional | owi(param).optional().exec() | | error() | Chainable custom error message | owi(param).error('Custom message').exec() |


Contributors