Skip to content
This repository was archived by the owner on Feb 21, 2024. It is now read-only.

Latest commit

History

14 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

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/fresh_validation@0.1.1/mod.ts";import{Handlers}from"$fresh/server.ts";importtype{WithSession}from"https://deno.land/x/fresh_session@0.1.7/mod.ts";exportconsthandler: 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-sessionconsterrors=ctx.state.session.flash("errors");returnctx.render({ errors });},asyncPOST(req,ctx){// We just need this to validate our FormDataconst{ validatedData, errors }=awaitvalidateFormData(req,{username: z.string().min(2),password: z.string().min(8),});// `errors` will be null if the validation is correctif(errors){// we can deal with errors here// we recommand using Fresh Session to pass errors between endpoints// more info: https://github.com/xstevenyung/fresh-sessionctx.state.session.flash("errors",errors);}// here we get back the validated data casted to the right typevalidatedData.username;validatedData.password;// For the sake of the example, we will redirect to the dashboard after a successful loginreturnnewResponse(null,{status: 303,headers: {Location: "/dashboard"},});},};exportdefaultfunction({ data }){return(<formmethod="post"><labelfor="username"// We can display a specific class or style if there is any errors on a specific fieldclass={error(data.errors,"username") ? "invalid" : ""}>
Username
</label><inputid="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>)}<labelfor="password">Password</label><inputid="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/fresh_validation@0.1.1/mod.ts";importtestShapefrom"@/shapes/test.ts";import{Handlers}from"$fresh/server.ts";importtype{WithSession}from"https://deno.land/x/fresh_session@0.1.7/mod.ts";exportconsthandler: Handlers<{errors: ZodIssue[]},WithSession>={GET(req,ctx){// Validate search paramsconst{ validatedData, errors }=awaitvalidateSearchParams(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 herevalidatedData.q;validatedData.page;returnctx.render({ validatedData });},};exportdefaultfunction({ data }){return(<formmethod="get"><inputid="search"name="search"/><ahref="/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/fresh_validation@0.1.1/mod.ts";import{Handlers}from"$fresh/server.ts";importFormfrom"../islands/LoginForm.tsx";exportconsthandler: Handlers={GET: (req,ctx)=>{returnctx.render({ errors });},asyncPOST(req){const{ validatedData, errors }=awaitvalidateJSON(req,{username: z.string().min(2),password: z.string().min(8),});if(errors){// We deal with errors herereturnnewResponse(JSON.stringify(errors),{status: 422,headers: {"Content-Type": "application/json"},});}// We can access validatedData herevalidatedData.username;validatedData.password;returnnewResponse(null,{status: 204,headers: {"Content-Type": "application/json"},});},};exportdefaultfunction({ 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/fresh_validation@0.1.1/mod.ts";exportdefaultfunction({ data }){const[errors,setErrors]=useState<ZodIssue[]>([]);return(<formmethod="post"onSubmit={async(e)=>{e.preventDefault();// We can even do client-side validation with the exact same code!const{ validatedData, errors }=awaitvalidateFormData(newFormData(e.target),{username: z.string().min(2),password: z.string().min(8),},);if(errors){returnsetErrors(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 someif(response.status===422){const{ errors }=awaitresponse.json();returnsetErrors(errors);}//});}}><labelfor="username">Username</label><inputid="username"name="username"/>{!!error(errors,"username")&&(<p>{error(errors,"username")?.message}</p>)}<labelfor="password">Password</label><inputid="password"name="password"/>{!!error(errors,"password")&&(<p>{error(errors,"password")?.message}</p>)}<buttontype="submit">Submit</button></form>);}

About

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

Topics

Resources

Stars

23 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages