{"pageProps":{"post":{"source":{"compiledSource":"/*@jsxRuntime automatic @jsxImportSource react*/\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = Object.assign({\n p: \"p\",\n pre: \"pre\",\n code: \"code\",\n span: \"span\",\n h2: \"h2\"\n }, _provideComponents(), props.components);\n return _jsxs(_Fragment, {\n children: [_jsx(_components.p, {\n children: \"Users' inputs validation has always been extremely important when building any type of service or API.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"We know that not doing runtime checks and validation could result in a slower and much less secure application.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"When you're starting off with input validation, you probably just add conditionnal statements every where in your code.\\nMaking your code looking something like this :\"\n }), \"\\n\", _jsx(_components.pre, {\n children: _jsxs(_components.code, {\n className: \"hljs language-js\",\n children: [\"app.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"post\"\n }), \"(\", _jsxs(_components.span, {\n className: \"hljs-function\",\n children: [\"(\", _jsx(_components.span, {\n className: \"hljs-params\",\n children: \"req, res\"\n }), \") =>\"]\n }), \" {\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" body = req.\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"body\"\n }), \"\\n\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"if\"\n }), \" (!body.\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"email\"\n }), \" || !body.\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"password\"\n }), \") {\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"throw\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"new\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title class_\",\n children: \"Error\"\n }), \"()\\n }\\n\\n \", _jsx(_components.span, {\n className: \"hljs-comment\",\n children: \"// Check if input respect the email format\"\n }), \"\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"if\"\n }), \" (!\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"isEmail\"\n }), \"(body.\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"email\"\n }), \")) {\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"throw\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"new\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title class_\",\n children: \"Error\"\n }), \"()\\n }\\n\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"if\"\n }), \" (body.\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"password\"\n }), \".\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"length\"\n }), \" < \", _jsx(_components.span, {\n className: \"hljs-number\",\n children: \"8\"\n }), \" || body.\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"password\"\n }), \".\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"length\"\n }), \" > \", _jsx(_components.span, {\n className: \"hljs-number\",\n children: \"30\"\n }), \") {\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"throw\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"new\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title class_\",\n children: \"Error\"\n }), \"()\\n }\\n\\n \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"doSomething\"\n }), \"(body)\\n})\\n\"]\n })\n }), \"\\n\", _jsx(_components.p, {\n children: \"Doesn't look good, quite painful to develop and maintain right ?\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"Moreover, if you are using typescript, it should feel a bit counter intuitive to have to make your validation in such a imperative way.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"But in fact, Typescript has a blind spot for runtime validation, as it only does build time checks.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"Thankfully, there's a solution that will fit way better what you are trying to accomplish.\"\n }), \"\\n\", _jsx(_components.h2, {\n id: \"what-is-zod-\",\n children: \"What is Zod ?\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"Presenting Zod, a schema declaration and validation for your backend, that works hand in hand with Typescript to provide runtime validation.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"Working with Zod is super easy, you create a schema, then you parse your users' inputs with the schema.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"If the inputs does not fit the pattern of the schema, Zod will automatically throw an error that you can catch.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"You can infer the type of the schema to statically type with Typescript.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"Here's our above example made with Zod :\"\n }), \"\\n\", _jsx(_components.pre, {\n children: _jsxs(_components.code, {\n className: \"hljs language-ts\",\n children: [_jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"import\"\n }), \" { z } \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"from\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-string\",\n children: \"'zod'\"\n }), \"\\n\\n\", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" userSchema = z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"object\"\n }), \"({\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"email\"\n }), \": z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"string\"\n }), \"().\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"email\"\n }), \"(),\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"password\"\n }), \": z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"string\"\n }), \"().\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"min\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-number\",\n children: \"8\"\n }), \").\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"max\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-number\",\n children: \"30\"\n }), \")\\n})\\n\\n\", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"type\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title class_\",\n children: \"User\"\n }), \" = z.\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"infer\"\n }), \"<\", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"typeof\"\n }), \" userSchema>\\n\\napp.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"post\"\n }), \"(\", _jsxs(_components.span, {\n className: \"hljs-function\",\n children: [\"(\", _jsx(_components.span, {\n className: \"hljs-params\",\n children: \"req, res\"\n }), \") =>\"]\n }), \" {\\n \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" body = req.\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"body\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"as\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title class_\",\n children: \"User\"\n }), \"\\n\\n \", _jsx(_components.span, {\n className: \"hljs-comment\",\n children: \"// Zod does the checking and validation here\"\n }), \"\\n userSchema.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"parse\"\n }), \"(body)\\n\\n \", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"doSomething\"\n }), \"(body)\\n})\\n\"]\n })\n }), \"\\n\", _jsx(_components.p, {\n children: \"You can also provide custom error message in your schema :\"\n }), \"\\n\", _jsx(_components.pre, {\n children: _jsxs(_components.code, {\n className: \"hljs language-ts\",\n children: [_jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" userSchema = z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"object\"\n }), \"({\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"email\"\n }), \": z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"string\"\n }), \"().\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"email\"\n }), \"(),\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"password\"\n }), \": z\\n .\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"string\"\n }), \"()\\n .\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"min\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-number\",\n children: \"8\"\n }), \", { \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"message\"\n }), \": \", _jsx(_components.span, {\n className: \"hljs-string\",\n children: \"'Password should be at least 8 characters'\"\n }), \" })\\n .\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"max\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-number\",\n children: \"30\"\n }), \")\\n})\\n\"]\n })\n }), \"\\n\", _jsx(_components.h2, {\n id: \"using-zod-for-more-advanced-schemas\",\n children: \"Using Zod for more advanced schemas\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"Zod provides a bunch a useful prebuilt validators to check for an email, a url, a uuid, a cuid...\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"All of those that could be usefull on more complex schemas, for example :\"\n }), \"\\n\", _jsx(_components.pre, {\n children: _jsxs(_components.code, {\n className: \"hljs language-ts\",\n children: [_jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"const\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title class_\",\n children: \"User\"\n }), \" = z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"object\"\n }), \"({\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"id\"\n }), \": z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"string\"\n }), \"().\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"uuid\"\n }), \"()\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"name\"\n }), \": z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"string\"\n }), \"().\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"max\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-number\",\n children: \"30\"\n }), \")\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"websiteUrl\"\n }), \": z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"string\"\n }), \"().\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"url\"\n }), \"()\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"ipAdress\"\n }), \": z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"string\"\n }), \"().\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"ip\"\n }), \"()\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"skills\"\n }), \": z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"array\"\n }), \"(z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"string\"\n }), \"()).\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"nonempty\"\n }), \"()\\n\\n \", _jsx(_components.span, {\n className: \"hljs-comment\",\n children: \"// Create enums that you can infer with z.infer, or use z.nativeEnum() for external libs\"\n }), \"\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"role\"\n }), \": z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"enum\"\n }), \"([\", _jsx(_components.span, {\n className: \"hljs-string\",\n children: \"'visitor'\"\n }), \", \", _jsx(_components.span, {\n className: \"hljs-string\",\n children: \"'admin'\"\n }), \"])\\n\\n \", _jsx(_components.span, {\n className: \"hljs-comment\",\n children: \"// Age must be an positive interger that is less than 100\"\n }), \"\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"age\"\n }), \": z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"number\"\n }), \"().\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"int\"\n }), \"().\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"positive\"\n }), \"().\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"lt\"\n }), \"(\", _jsx(_components.span, {\n className: \"hljs-number\",\n children: \"100\"\n }), \")\\n\\n \", _jsx(_components.span, {\n className: \"hljs-comment\",\n children: \"// UTC Format by default\"\n }), \"\\n \", _jsx(_components.span, {\n className: \"hljs-attr\",\n children: \"createdAt\"\n }), \": z.\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"string\"\n }), \"().\", _jsx(_components.span, {\n className: \"hljs-title function_\",\n children: \"datetime\"\n }), \"()\\n})\\n\"]\n })\n }), \"\\n\", _jsx(_components.h2, {\n id: \"the-great-part-of-zod-infering-types\",\n children: \"The great part of Zod: Infering types\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"We've seen how usefull a validation library can be, but the real great thing about zod is its \", _jsx(_components.code, {\n children: \"z.infer\"\n }), \" method that allows to work with typescript super easily. No need to maintain a relation between your types and schemas, as Zod does it on its own.\"]\n }), \"\\n\", _jsx(_components.p, {\n children: \"To get the proper type, you simply have to infer the type of your schema:\"\n }), \"\\n\", _jsx(_components.pre, {\n children: _jsxs(_components.code, {\n className: \"hljs language-ts\",\n children: [_jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"type\"\n }), \" \", _jsx(_components.span, {\n className: \"hljs-title class_\",\n children: \"YourSchemaType\"\n }), \" = z.\", _jsx(_components.span, {\n className: \"hljs-property\",\n children: \"infer\"\n }), \"<\", _jsx(_components.span, {\n className: \"hljs-keyword\",\n children: \"typeof\"\n }), \" yourSchema>\\n\"]\n })\n }), \"\\n\", _jsx(_components.h2, {\n id: \"conclusion\",\n children: \"Conclusion\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"As we've seen, if you are using Typescript for your backend, or even more if you use it accross the frontend and backend of your application, Zod can be a great solution to fill the blindspots of Typescript when it comes to runtime checking.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"If you havn't tried it yet, feel free to share with me your first experience with it, I'm sure it will save you time with its great developer experience.\"\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = Object.assign({}, _provideComponents(), props.components);\n return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {\n children: _jsx(_createMdxContent, props)\n })) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"meta":{"slug":"validate-user-input-with-zod","title":"How to validate user input on your backend with Zod ?","desc":"Learn how to integrate Zod, a TypeScript-first schema validation for your backend","image":"","date":"Sun Jun 11 2023 00:00:00 GMT+0000 (Coordinated Universal Time)","keywords":""}}},"__N_SSG":true}