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 🙏

© 2024 – Pkg Stats / Ryan Hefner

promise-validation

v4.0.1

Published

Validation using async await for simplicity

Downloads

21

Readme

Promise Validation

Promise Validation in JavaScript library which uses promises in a functional-like manner. It is light weight, composable, and really simple to use.

Installation

npm install promise-validation

Or just copy the file and paste it into your project.

Top-level View

A composable way to validate and create objects. This is how you would create a validator which will validate and transform your data to what you would like.

const nameValidator = {
    firstName: createString25('First Name'),
    lastName: maybe(createString25('Last Name'))
}

const personValidator = {
    ...name,
    birthdate: createDate('Birthdate')
}

You can see how you can compose the validators to build new validators. You can combine validators like maybe with createString25 — this will say that the string doesn't necessarily need to exist (it can be null or undefined) but if it is something will validate that it is a string of maximum length of 25. Then the name validator is composed into the person validator which adds the birthdate validation.

Then when you pass it to the function to do the actual validation:

const rawData = {
    firstName: "George",
    lastName: "Jungle",
    birthdate: "1967-09-09"
}

// No need to check anything about the person as you know it is a person and
// that person is there and the data just like you said it would be in the
// validator.
const person = await validateObject(rawData, personValidator)

console.log(person)
/*
{
    firstName: "George",
    lastName: "Jungle",
    birthdate: Date("1967-09-09")
}
*/

But what happens when the validation fails? Let us make one that fails for all properties:

const rawData = {
    lastName: "Jungle".repeat(5), // String length of 30
    birthdate: "1967-99-99"
}

// Returns x value in `catch` method. Normally you would catch this error higher
// up in the stack.
const failed = await validateObject(rawData, personValidator).catch(x => x)

console.log(failed)
/*
ValidationResult:
    reasons:
        [
            ValidationError:
                key: "firstName"
                reason: "'First Name' is undefined but is required."
            ValidationMessage:
                key: "lastName"
                reason: "'Last Name' is longer than 25."
            ValidationMessage:
                key: "birthdate"
                reason: "'Birthdate' is an invalid date."
        ]
*/

So, how would you normally do this?

const person = validatePerson(data)
if (person == null) {
    return null
}
const firstName = person?.firstName ?? "No name"

Rather messy. But with the validation above you can know that if the async function doesn't return an error that all your values are what they say they are.

More Details

So, how do we create the validation components?

function fail(message: string) {
    return Promise.reject(message)
}

function required<T>(name: string, value: T) : Promise<T> {
    return !value ? fail(`"${name}" is required but is falsey.`) : value
}

async function createString(name: string, value: string, length: number) {
    const v = await required(name, value?.trim())
    return v.length <= length ? v : fail(`${name} is longer than ${length} characters.`)
}

const createString25 =
    (name: string) =>
    (value: string | undefined) =>
        createString(name, value, 25)

const maybe =
    <T>(f: (val: T | undefined) => Promise<T>) =>
    (val: T | undefined) =>
        !val ? Promise.resolve(val) : f(val)

const createDate =
    (name: string) =>
    async (value: string | Date) => {
        let v = await required(name, value)
        if (v instanceof Date) {
            if (isNaN(+v)) {
                return fail(`"${name}" is not a valid date.`)
            }
            return v
        }
        let d = new Date(v)
        if (isNaN(+d)) {
            return fail(name, `is not a valid date.`)
        }
        return d
    }

As you can see, you can build up all the different validations just like you want to make them. They can be composable with high reuse of code in a functional and declarative way. No need for if statements. Just a simple async-await pattern gets you where you need to be!

How to handle an array of data?

Glad you asked. You could do it like so:

var results = Promise.all(data)
// OR if you want an aggregation
var results = validate(data)
// OR if you want partial results
var results = Promise.allSettled(data)

Change Log

4.0.0

  • Removed reason field from ValidationResult class.