Easy server-side and client-side validation for FormData, URLSearchParams and JSON data in your Fresh app 🍋

Overview

Fresh Validation 🍋    Badge License

Easily validate FormData, URLSearchParams and JSON data in your Fresh app server-side or client-side!


Validation

Fresh Validation is built on top of Zod. For more information on different validation rules you can check Zod's documentation.

Getting Started

You can use Fresh Validation directly without any setup:

Validate FormData

FormData are natively support on the web platform but suffer from loosing data typing as all data are plain string when sent through the wire.

By using validateFormData, we can validate and cast back our data to the right type.

// routes/login.tsx
/** @jsx h */
import { h } from "preact";
import {
  error,
  validateFormData,
  z,
  ZodIssue,
} from "https://deno.land/x/[email protected]/mod.ts";
import { Handlers } from "$fresh/server.ts";
import type { WithSession } from "https://deno.land/x/[email protected]/mod.ts";

export const handler: Handlers<{ errors: ZodIssue[] }, WithSession> = {
  GET(req, ctx) {
    // We use Fresh Session to flash errors and pass it down to the page
    // more info: https://github.com/xstevenyung/fresh-session
    const errors = ctx.state.session.flash("errors");
    return ctx.render({ errors });
  },

  async POST(req, ctx) {
    // We just need this to validate our FormData
    const { validatedData, errors } = await validateFormData(req, {
      username: z.string().min(2),
      password: z.string().min(8),
    });

    // `errors` will be null if the validation is correct
    if (errors) {
      // we can deal with errors here
      // we recommand using Fresh Session to pass errors between endpoints
      // more info: https://github.com/xstevenyung/fresh-session
      ctx.state.session.flash("errors", errors);
    }

    // here we get back the validated data casted to the right type
    validatedData.username;
    validatedData.password;

    // For the sake of the example, we will redirect to the dashboard after a successful login
    return new Response(null, {
      status: 303,
      headers: { Location: "/dashboard" },
    });
  },
};

export default function ({ data }) {
  return (
    <form method="post">
      <label
        for="username"
        // We can display a specific class or style if there is any errors on a specific field
        class={error(data.errors, "username") ? "invalid" : ""}
      >
        Username
      </label>
      <input id="username" name="username" />
      {/* And we can use the `error` function to retrieve the right error to display to the user*/}
      {!!error(data.errors, "username") && (
        <p>{error(data.errors, "username")?.message}</p>
      )}

      <label for="password">Password</label>
      <input id="password" name="password" />
      {!!error(data.errors, "password") && (
        <p>{error(data.errors, "password")?.message}</p>
      )}
    </form>
  );
}

Validate URLSearchParams

URLSearchParams works the same as FormData.

// routes/search.tsx
/** @jsx h */
import { h } from "preact";
import {
  error,
  validate,
  z,
  ZodIssue,
} from "https://deno.land/x/[email protected]/mod.ts";
import testShape from "@/shapes/test.ts";
import { Handlers } from "$fresh/server.ts";
import type { WithSession } from "https://deno.land/x/[email protected]/mod.ts";

export const handler: Handlers<{ errors: ZodIssue[] }, WithSession> = {
  GET(req, ctx) {
    // Validate search params
    const { validatedData, errors } = await validateSearchParams(req, {
      q: z.string().nullable(),
      page: z.number().default(1),
    });

    if (errors) {
      // We can deal with errors here but in our example, it's not necessary
    }

    // We can then use it here
    validatedData.q;
    validatedData.page;

    return ctx.render({ validatedData });
  },
};

export default function ({ data }) {
  return (
    <form method="get">
      <input id="search" name="search" />

      <a href="/search?page=2">Page 2</a>
    </form>
  );
}

Validate JSON

validateJSON will extract the req.json() and validate against a Zod schema

Note: We transform any date into a Date instance to simplify validation with Zod

// routes/login.tsx
/** @jsx h */
import { h } from "preact";
import {
  validateJSON,
  z,
} from "https://deno.land/x/[email protected]/mod.ts";
import { Handlers } from "$fresh/server.ts";
import Form from "../islands/LoginForm.tsx";

export const handler: Handlers = {
  GET: (req, ctx) => {
    return ctx.render({ errors });
  },

  async POST(req) {
    const { validatedData, errors } = await validateJSON(req, {
      username: z.string().min(2),
      password: z.string().min(8),
    });

    if (errors) {
      // We deal with errors here
      return new Response(JSON.stringify(errors), {
        status: 422,
        headers: { "Content-Type": "application/json" },
      });
    }

    // We can access validatedData here
    validatedData.username;
    validatedData.password;

    return new Response(null, {
      status: 204,
      headers: { "Content-Type": "application/json" },
    });
  },
};

export default function ({ data }) {
  return <Form />;
}
// islands/LoginForm.tsx
/** @jsx h */
import { h } from "preact";
import { useState } from "preact/hooks";
import {
  error,
  validateFormData,
  z,
  ZodIssue,
} from "https://deno.land/x/[email protected]/mod.ts";

export default function ({ data }) {
  const [errors, setErrors] = useState<ZodIssue[]>([]);

  return (
    <form
      method="post"
      onSubmit={async (e) => {
        e.preventDefault();

        // We can even do client-side validation with the exact same code!
        const { validatedData, errors } = await validateFormData(
          new FormData(e.target),
          {
            username: z.string().min(2),
            password: z.string().min(8),
          },
        );

        if (errors) {
          return setErrors(errors);
        }

        fetch("/json", {
          method: "POST",
          body: JSON.stringify(validatedData),
          headers: { "Content-Type": "application/json" },
        }).then(async (response) => {
          // We handle server-side errors in case there is some
          if (response.status === 422) {
            const { errors } = await response.json();
            return setErrors(errors);
          }
          //
        });
      }}
    >
      <label for="username">Username</label>
      <input id="username" name="username" />
      {!!error(errors, "username") && (
        <p>{error(errors, "username")?.message}</p>
      )}

      <label for="password">Password</label>
      <input id="password" name="password" />
      {!!error(errors, "password") && (
        <p>{error(errors, "password")?.message}</p>
      )}

      <button type="submit">Submit</button>
    </form>
  );
}
You might also like...

Package fetcher is a bot messenger which gather npm packages by uploading either a json file (package.json) or a picture representing package.json. To continue...

package-fetcher Ce projet contient un boilerplate pour un bot messenger et l'executable Windows ngrok qui va permettre de créer un tunnel https pour c

Mar 29, 2022

A demonstration app for Fresh that shows how to use SSR, the islands functionality, APIs and more

Fresh Pokemon Demo Code This is a demonstration app for Fresh that shows how to use SSR, the islands functionality, APIs and more. You do need to conn

Dec 18, 2022

A fresh (deno) app

A fresh (deno) app

Welcome to fresh-deno-app 👋 A fresh (deno) app 🏠 Homepage ✨ Demo Prerequisites Deno version 1.22.3 or higher installed. - A modern runtime for JavaS

Oct 17, 2022

The fastest way ⚡️ to create sitemap in your Deno Fresh project 🍋

Fresh SEO 🍋     Quickly creating sitemaps for your Deno Fresh project. Getting Started Run the setup at the root of your project. deno run

Dec 19, 2022

A robust form library for Lit that enriches input components with easy-to-use data validation features.

A robust form library for Lit that enriches input components with easy-to-use data validation features.

EliteForms A robust form library for Lit that enriches input components with easy-to-use data validation features. Installation npm install elite-form

Jun 28, 2022

The jQuery plugin for validation and post form data to server

NiceForm The jQuery plugin for validation and post form data to server (http://ducdhm.github.io/jquery.niceform/) Shortcuts Dependencies Rules Configu

Jul 27, 2022

Prisma 2+ generator to emit a JSON file that can be run with json-server

Prisma 2+ generator to emit a JSON file that can be run with json-server

Prisma JSON Server Generator A Prisma generator that automates creating a JSON file that can be run as a server from your Prisma schema. Explore the o

Jan 7, 2023

View component and controller of YouTube Player API, for fresh framework.

View component and controller of YouTube Player API, for fresh framework.

fresh-youtube View component and controller of YouTube Player API, for fresh framework. Try it now! git clone [email protected]:otiai10/fresh-youtube.git

Nov 2, 2022

A fresh look for the Hackage. Follow us: https://twitter.com/HackageUI

A fresh look for the Hackage. Follow us: https://twitter.com/HackageUI

Hackage UI Fresh look for the https://hackage.haskell.org/. Work in progress. Search Search on Hoogle. Search on Hackage. Full-text search integration

Dec 28, 2022
Owner
Steven Yung
Freelance fullstack developer 🥞 | Serial unlaunched side-projects maker 🚀 | Bouldering fanatic 🧗
Steven Yung
JSON Visio is data visualization tool for your json data which seamlessly illustrates your data on graphs without having to restructure anything, paste directly or import file.

JSON Visio is data visualization tool for your json data which seamlessly illustrates your data on graphs without having to restructure anything, paste directly or import file.

Aykut Saraç 20.6k Jan 4, 2023
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Fast and minimal JS server-side writer and client-side manager.

unihead Fast and minimal JS <head> server-side writer and client-side manager. Nearly every SSR framework out there relies on server-side components t

Jonas Galvez 24 Sep 4, 2022
Generate a zodios (typescript http client with zod validation) from an OpenAPI spec (json/yaml)

openapi-zod-client Generates a zodios (typescript http client with zod validation) from a (json/yaml) OpenAPI spec (or just use the generated schemas/

Alexandre Stahmer 104 Jan 4, 2023
Picky is a jQuery plugin that provides simple client-side date validation when entering dates using select tags.

jquery.picky.js Picky is a jQuery plugin that provides simple client-side date validation when entering dates using select tags. Features Instead of g

Patrick Crowley 5 Apr 25, 2021
A remote nodejs Cache Server, for you to have your perfect MAP Cache Saved and useable remotely. Easy Server and Client Creations, fast, stores the Cache before stopping and restores it again!

remote-map-cache A remote nodejs Cache Server, for you to have your perfect MAP Cache Saved and useable remotely. Easy Server and Client Creations, fa

Tomato6966 8 Oct 31, 2022
RenderIf is a function that receives a validation as a parameter, and if that validation is true, the content passed as children will be displayed. Try it!

RenderIf RenderIf is a function that receives a validation as a parameter, and if that validation is true, the content passed as children will be disp

Oscar Cornejo Aguila 6 Jul 12, 2022
JCS (JSON Canonicalization Scheme), JSON digests, and JSON Merkle hashes

JSON Hash This package contains the following JSON utilties for Deno: digest.ts provides cryptographic hash digests of JSON trees. It guarantee that d

Hong Minhee (洪 民憙) 13 Sep 2, 2022