<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged validation</title>
<link>https://coderlegion.com/tag/validation</link>
<description>Powered by Question2Answer</description>
<item>
<title>Zod vs Yup in 2026: Which Validation Library Should You Use?</title>
<link>https://coderlegion.com/25116/zod-vs-yup-in-2026-which-validation-library-should-you-use</link>
<description>&lt;p&gt;You've got a signup form. Email, password, maybe a checkbox for terms and conditions. Simple, right? Then someone submits &lt;code&gt;email: 123&lt;/code&gt; and your API route crashes with a cryptic error three files deep, because nothing ever checked that the data coming in actually matched what your code expected.&lt;/p&gt;
&lt;p&gt;That's the exact gap schema validation libraries fill — and if you've searched for one, you've almost certainly landed on two names: &lt;strong&gt;Zod&lt;/strong&gt; and &lt;strong&gt;Yup&lt;/strong&gt;. Both let you describe the shape of your data once and validate real values against it. Both work great with React Hook Form. Both have been around long enough to be genuinely production-tested.&lt;/p&gt;
&lt;p&gt;But they're not interchangeable, and picking the wrong one for your setup means either fighting TypeScript for months or hand-writing types you shouldn't have to. By the end of this guide, you'll know exactly how Zod and Yup differ, see real code for both, and know which one actually fits your project — not just which one has more GitHub stars.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;quick-answer&quot;&gt;Quick Answer&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Choose Zod&lt;/strong&gt; if you're using TypeScript and want your schema to &lt;em&gt;be&lt;/em&gt; your type — no writing an interface separately and hoping it stays in sync.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Choose Yup&lt;/strong&gt; if you're maintaining an existing Formik-based codebase, or your team is more comfortable with its &lt;code&gt;.shape()&lt;/code&gt; API and mature async validation methods.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For any brand-new TypeScript project in 2026, Zod is the safer long-term default — it's what most modern tools (React Hook Form, tRPC, Next.js Server Action patterns) assume you're using. Now let's get into why.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-is-schema-validation-exactly-&quot;&gt;What Is Schema Validation, Exactly?&lt;/h3&gt;
&lt;p&gt;Before comparing the two, a quick beginner-friendly definition: a &lt;strong&gt;schema&lt;/strong&gt; is just a description of what your data &lt;em&gt;should&lt;/em&gt; look like — &quot;this field is a string,&quot; &quot;this field is a number between 1 and 100,&quot; &quot;this field is a valid email.&quot; A &lt;strong&gt;validation library&lt;/strong&gt; takes that schema and checks real, incoming data (a form submission, an API request body) against it, telling you exactly what's wrong if it doesn't match.&lt;/p&gt;
&lt;p&gt;Without one, you end up writing manual checks like this everywhere:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;if (typeof data.email !== &quot;string&quot; || !data.email.includes(&quot;@&quot;)) {
  throw new Error(&quot;Invalid email&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Multiply that across every field, every form, every API route, and it gets messy fast — inconsistent error messages, duplicated logic, and no single source of truth for what &quot;valid&quot; even means. Zod and Yup both solve this by letting you define the rules once and reuse them everywhere.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;zod-typescript-first-validation&quot;&gt;Zod: TypeScript-First Validation&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://zod.dev&quot;&gt;Zod&lt;/a&gt; was built specifically for TypeScript projects. Its core idea: you write one schema, and Zod derives both the runtime validator &lt;em&gt;and&lt;/em&gt; the TypeScript type from it — there's no second place to keep in sync.&lt;/p&gt;
&lt;h4 id=&quot;installing-zod&quot;&gt;Installing Zod&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install zod
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;a-basic-zod-schema&quot;&gt;A Basic Zod Schema&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// lib/validators/user-schema.ts
import { z } from &quot;zod&quot;;

export const userSchema = z.object({
  name: z.string().min(2, &quot;Name must be at least 2 characters&quot;),
  email: z.email(&quot;Please enter a valid email address&quot;),
  age: z.number().int().positive().optional(),
  website: z.url().optional(),
});

// The type is derived directly from the schema — never written twice
export type User = z.infer&amp;lt;typeof userSchema&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; &lt;code&gt;z.object({...})&lt;/code&gt; describes the shape. &lt;code&gt;z.email()&lt;/code&gt; and &lt;code&gt;z.url()&lt;/code&gt; are Zod's built-in format validators (as of Zod v4, these live as top-level helpers rather than chained &lt;code&gt;.email()&lt;/code&gt; string methods, though the chained form still works). &lt;code&gt;z.infer&amp;lt;typeof userSchema&amp;gt;&lt;/code&gt; pulls a real TypeScript type straight out of the schema — if you add a field to the schema, the &lt;code&gt;User&lt;/code&gt; type updates automatically, with zero manual work.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; This is Zod's single biggest selling point. You will never end up with a TypeScript interface that's quietly out of sync with your actual validation rules, because there's only one definition.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;validating-data-with-zod&quot;&gt;Validating Data with Zod&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// Somewhere handling a form submission or API request
const result = userSchema.safeParse({
  name: &quot;Ali&quot;,
  email: &quot;not-an-email&quot;,
});

if (!result.success) {
  console.log(result.error.flatten().fieldErrors);
  // { email: [&quot;Please enter a valid email address&quot;] }
} else {
  // result.data is fully typed as `User`
  console.log(result.data.name);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; &lt;code&gt;safeParse()&lt;/code&gt; never throws — it returns a &lt;code&gt;{ success: true, data }&lt;/code&gt; or &lt;code&gt;{ success: false, error }&lt;/code&gt; object, so you don't need a &lt;code&gt;try/catch&lt;/code&gt; block for normal validation flow. &lt;code&gt;error.flatten().fieldErrors&lt;/code&gt; gives you a clean, per-field map of error messages, perfect for showing next to form inputs.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; Using &lt;code&gt;.parse()&lt;/code&gt; instead of &lt;code&gt;.safeParse()&lt;/code&gt; in a code path where invalid data is expected (like a form submission). &lt;code&gt;.parse()&lt;/code&gt; &lt;em&gt;throws&lt;/em&gt; on failure, which means you need a &lt;code&gt;try/catch&lt;/code&gt; everywhere — &lt;code&gt;.safeParse()&lt;/code&gt; is almost always the better default for user input.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;zod-in-a-next-js-server-action&quot;&gt;Zod in a Next.js Server Action&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// actions/create-user.ts
&quot;use server&quot;;

import { userSchema } from &quot;@/lib/validators/user-schema&quot;;

export async function createUser(prevState: unknown, formData: FormData) {
  const result = userSchema.safeParse({
    name: formData.get(&quot;name&quot;),
    email: formData.get(&quot;email&quot;),
  });

  if (!result.success) {
    return { errors: result.error.flatten().fieldErrors };
  }

  // result.data is typed and safe to use here
  // await db.user.create({ data: result.data });

  return { success: true };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the exact pattern you'll see across most modern Next.js codebases — validate raw &lt;code&gt;FormData&lt;/code&gt; on the server, never trust the client, and let the schema do the type narrowing for you.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;yup-the-established-forms-favorite&quot;&gt;Yup: The Established Forms Favorite&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/jquense/yup&quot;&gt;Yup&lt;/a&gt; predates the current TypeScript-first wave of tooling. It grew up alongside &lt;strong&gt;Formik&lt;/strong&gt; and is still deeply embedded in a lot of React form codebases, particularly ones started before 2022.&lt;/p&gt;
&lt;h4 id=&quot;installing-yup&quot;&gt;Installing Yup&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install yup
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;a-basic-yup-schema&quot;&gt;A Basic Yup Schema&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// lib/validators/user-schema.ts
import * as yup from &quot;yup&quot;;

export const userSchema = yup.object({
  name: yup.string().min(2, &quot;Name must be at least 2 characters&quot;).required(),
  email: yup.string().email(&quot;Please enter a valid email address&quot;).required(),
  age: yup.number().integer().positive(),
  website: yup.string().url(),
});

// Yup's type inference — functional, but less precise than Zod's
export type User = yup.InferType&amp;lt;typeof userSchema&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; the shape looks similar to Zod at a glance, but notice &lt;code&gt;.required()&lt;/code&gt; — in Yup, fields are &lt;strong&gt;optional by default&lt;/strong&gt; unless you explicitly mark them required, which is the opposite of Zod's default (Zod fields are required unless you call &lt;code&gt;.optional()&lt;/code&gt;). This trips up a lot of developers switching between the two.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; Forgetting &lt;code&gt;.required()&lt;/code&gt; on a Yup field and assuming it behaves like Zod. Yup schemas silently allow &lt;code&gt;undefined&lt;/code&gt; on any field you don't explicitly mark required — this is one of the most common Yup-related bugs in production forms.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;validating-data-with-yup&quot;&gt;Validating Data with Yup&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;try {
  const validData = await userSchema.validate(
    { name: &quot;Ali&quot;, email: &quot;not-an-email&quot; },
    { abortEarly: false }
  );
  console.log(validData);
} catch (err) {
  if (err instanceof yup.ValidationError) {
    console.log(err.errors); // [&quot;Please enter a valid email address&quot;]
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; Yup's &lt;code&gt;.validate()&lt;/code&gt; is &lt;strong&gt;async by default&lt;/strong&gt; and returns a Promise — this is a real difference from Zod, where &lt;code&gt;safeParse&lt;/code&gt; is synchronous unless you specifically opt into &lt;code&gt;safeParseAsync&lt;/code&gt;. &lt;code&gt;abortEarly: false&lt;/code&gt; tells Yup to collect every validation error instead of stopping at the first one. For a version that never throws, Yup also offers &lt;code&gt;validateSync()&lt;/code&gt; with a &lt;code&gt;try/catch&lt;/code&gt;, or you can check &lt;code&gt;.isValid()&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;yup-in-a-next-js-server-action&quot;&gt;Yup in a Next.js Server Action&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;// actions/create-user.ts
&quot;use server&quot;;

import { userSchema } from &quot;@/lib/validators/user-schema&quot;;
import { ValidationError } from &quot;yup&quot;;

export async function createUser(prevState: unknown, formData: FormData) {
  try {
    const data = await userSchema.validate(
      {
        name: formData.get(&quot;name&quot;),
        email: formData.get(&quot;email&quot;),
      },
      { abortEarly: false }
    );

    // await db.user.create({ data });
    return { success: true };
  } catch (err) {
    if (err instanceof ValidationError) {
      const fieldErrors: Record&amp;lt;string, string[]&amp;gt; = {};
      for (const e of err.inner) {
        if (e.path) fieldErrors[e.path] = [...(fieldErrors[e.path] ?? []), e.message];
      }
      return { errors: fieldErrors };
    }
    throw err;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice this requires a &lt;code&gt;try/catch&lt;/code&gt; and manually reshaping &lt;code&gt;err.inner&lt;/code&gt; into a field-keyed object — Zod's &lt;code&gt;flatten().fieldErrors&lt;/code&gt; gives you that shape for free.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;zod-vs-yup-side-by-side&quot;&gt;Zod vs Yup: Side-by-Side&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Zod &lt;/th&gt;&lt;th&gt;Yup&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TypeScript inference&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Automatic, precise (&lt;code&gt;z.infer&lt;/code&gt;) &lt;/td&gt;&lt;td&gt;Functional but looser (&lt;code&gt;InferType&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Default field behavior&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Required by default &lt;/td&gt;&lt;td&gt;Optional by default&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Validation style&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Sync by default (&lt;code&gt;safeParse&lt;/code&gt;), async available &lt;/td&gt;&lt;td&gt;Async by default (&lt;code&gt;.validate()&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Error shape&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Structured &lt;code&gt;ZodError&lt;/code&gt; with &lt;code&gt;.flatten()&lt;/code&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;ValidationError&lt;/code&gt; with &lt;code&gt;.inner&lt;/code&gt; array&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Bundle size (gzipped)&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Zod is slightly larger, but the difference &amp;lt;br/&amp;gt; is usually too small to matter for real &amp;lt;br/&amp;gt; applications. &lt;/td&gt;&lt;td&gt;Slightly smaller&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;React Hook Form support&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;✅ via &lt;code&gt;@hookform/resolvers/zod&lt;/code&gt; &lt;/td&gt;&lt;td&gt;✅ via &lt;code&gt;@hookform/resolvers/yup&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Ecosystem fit&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;tRPC, modern Next.js patterns, Server Actions &lt;/td&gt;&lt;td&gt;Formik, legacy React form codebases&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Learning curve&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Slightly more API surface &lt;/td&gt;&lt;td&gt;Simpler, more forgiving for JS-first teams&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Best for&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;New TypeScript projects &lt;/td&gt;&lt;td&gt;Existing Formik/Yup codebases&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; Bundle size differences here are small enough that they shouldn't be your deciding factor for most apps — a few KB gzipped rarely matters next to your actual app code and images.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;using-either-one-with-react-hook-form&quot;&gt;Using Either One with React Hook Form&lt;/h3&gt;
&lt;p&gt;This is where a lot of real-world decisions actually get made, so it's worth showing both side by side. Both integrate through the same &lt;code&gt;@hookform/resolvers&lt;/code&gt; package.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;npm install react-hook-form @hookform/resolvers
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;With Zod:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&quot;use client&quot;;

import { useForm } from &quot;react-hook-form&quot;;
import { zodResolver } from &quot;@hookform/resolvers/zod&quot;;
import { z } from &quot;zod&quot;;

const formSchema = z.object({
  email: z.email(),
  password: z.string().min(8, &quot;Password must be at least 8 characters&quot;),
});

type FormValues = z.infer&amp;lt;typeof formSchema&amp;gt;;

export function LoginForm() {
  const { register, handleSubmit, formState: { errors } } = useForm&amp;lt;FormValues&amp;gt;({
    resolver: zodResolver(formSchema),
  });

  const onSubmit = (data: FormValues) =&amp;gt; console.log(data);

  return (
    &amp;lt;form onSubmit={handleSubmit(onSubmit)}&amp;gt;
      &amp;lt;input {...register(&quot;email&quot;)} /&amp;gt;
      {errors.email &amp;amp;&amp;amp; &amp;lt;p&amp;gt;{errors.email.message}&amp;lt;/p&amp;gt;}

      &amp;lt;input type=&quot;password&quot; {...register(&quot;password&quot;)} /&amp;gt;
      {errors.password &amp;amp;&amp;amp; &amp;lt;p&amp;gt;{errors.password.message}&amp;lt;/p&amp;gt;}

      &amp;lt;button type=&quot;submit&quot;&amp;gt;Log in&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;With Yup:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-tsx&quot;&gt;&quot;use client&quot;;

import { useForm } from &quot;react-hook-form&quot;;
import { yupResolver } from &quot;@hookform/resolvers/yup&quot;;
import * as yup from &quot;yup&quot;;

const formSchema = yup.object({
  email: yup.string().email().required(),
  password: yup.string().min(8, &quot;Password must be at least 8 characters&quot;).required(),
});

type FormValues = yup.InferType&amp;lt;typeof formSchema&amp;gt;;

export function LoginForm() {
  const { register, handleSubmit, formState: { errors } } = useForm&amp;lt;FormValues&amp;gt;({
    resolver: yupResolver(formSchema),
  });

  const onSubmit = (data: FormValues) =&amp;gt; console.log(data);

  return (
    &amp;lt;form onSubmit={handleSubmit(onSubmit)}&amp;gt;
      &amp;lt;input {...register(&quot;email&quot;)} /&amp;gt;
      {errors.email &amp;amp;&amp;amp; &amp;lt;p&amp;gt;{errors.email.message}&amp;lt;/p&amp;gt;}

      &amp;lt;input type=&quot;password&quot; {...register(&quot;password&quot;)} /&amp;gt;
      {errors.password &amp;amp;&amp;amp; &amp;lt;p&amp;gt;{errors.password.message}&amp;lt;/p&amp;gt;}

      &amp;lt;button type=&quot;submit&quot;&amp;gt;Log in&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's different:&lt;/strong&gt; almost nothing at the React Hook Form layer — swap the resolver, swap the schema syntax, and everything else stays identical. This is exactly why the &quot;which one&quot; decision usually comes down to TypeScript ergonomics and team familiarity rather than form-library compatibility, since both are equally well supported.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;async-validation-where-yup-still-has-an-edge&quot;&gt;Async Validation: Where Yup Still Has an Edge&lt;/h3&gt;
&lt;p&gt;If you need to check something against a server mid-validation — &quot;is this username already taken?&quot; — Yup's &lt;code&gt;.test()&lt;/code&gt; method has had mature async support for years:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const signupSchema = yup.object({
  username: yup.string().test(
    &quot;unique-username&quot;,
    &quot;This username is already taken&quot;,
    async (value) =&amp;gt; {
      if (!value) return true;
      const res = await fetch(`/api/check-username?u=${value}`);
      const { available } = await res.json();
      return available;
    }
  ),
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Zod supports async refinements too, using &lt;code&gt;.refine()&lt;/code&gt; with an async function and &lt;code&gt;safeParseAsync()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;const signupSchema = z.object({
  username: z.string(),
}).refine(
  async (data) =&amp;gt; {
    const res = await fetch(`/api/check-username?u=${data.username}`);
    const { available } = await res.json();
    return available;
  },
  { message: &quot;This username is already taken&quot;, path: [&quot;username&quot;] }
);

// must use safeParseAsync, not safeParse, when the schema has async refinements
const result = await signupSchema.safeParseAsync({ username: &quot;ali&quot; });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What's happening here:&lt;/strong&gt; both libraries can do this — Yup's API was simply designed around async validation from the start, so it reads slightly more naturally. Zod requires you to remember to swap &lt;code&gt;safeParse&lt;/code&gt; for &lt;code&gt;safeParseAsync&lt;/code&gt; whenever an async &lt;code&gt;.refine()&lt;/code&gt; is in play, which is an easy thing to forget.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ &lt;strong&gt;Common Mistake:&lt;/strong&gt; Calling &lt;code&gt;safeParse()&lt;/code&gt; (not &lt;code&gt;safeParseAsync()&lt;/code&gt;) on a Zod schema with an async &lt;code&gt;.refine()&lt;/code&gt;. It won't throw — it'll just resolve the refinement incorrectly, since Zod can't await inside a synchronous parse. Always match &lt;code&gt;safeParseAsync&lt;/code&gt; to async refinements.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id=&quot;migrating-from-yup-to-zod-if-you-re-considering-it-&quot;&gt;Migrating from Yup to Zod (If You're Considering It)&lt;/h3&gt;
&lt;p&gt;If you're weighing a migration, here's the honest advice: &lt;strong&gt;don't rewrite a working Yup codebase just to switch libraries.&lt;/strong&gt; The type-safety gains are real, but they're not worth the regression risk on schemas that already work in production. Reach for Zod on &lt;strong&gt;new&lt;/strong&gt; features or &lt;strong&gt;new&lt;/strong&gt; projects instead, and let old Yup schemas retire naturally as you touch that code for other reasons.&lt;/p&gt;
&lt;p&gt;If you are migrating a specific schema, the field-by-field mapping is usually mechanical:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Yup &lt;/th&gt;&lt;th&gt;Zod&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;yup.string().required()&lt;/code&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;z.string()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;yup.string().optional()&lt;/code&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;z.string().optional()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;yup.string().email()&lt;/code&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;z.email()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;yup.number().integer()&lt;/code&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;z.number().int()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;yup.object().shape({...})&lt;/code&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;z.object({...})&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;yup.InferType&amp;lt;typeof schema&amp;gt;&lt;/code&gt; &lt;/td&gt;&lt;td&gt;&lt;code&gt;z.infer&amp;lt;typeof schema&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;frequently-asked-questions&quot;&gt;Frequently Asked Questions&lt;/h3&gt;
&lt;h4 id=&quot;can-i-use-zod-without-typescript-&quot;&gt;Can I use Zod without TypeScript?&lt;/h4&gt;
&lt;p&gt;Yes, Zod works fine in plain JavaScript — but you lose its single biggest advantage, since type inference only matters if you have TypeScript to infer &lt;em&gt;into&lt;/em&gt;. If your project is JavaScript-only, Zod and Yup are much closer in practical value, and team familiarity should decide it.&lt;/p&gt;
&lt;h4 id=&quot;is-zod-always-faster-than-yup-&quot;&gt;Is Zod always faster than Yup?&lt;/h4&gt;
&lt;p&gt;Not necessarily, and it depends heavily on the shape of your schema. For most typical form-sized payloads, both validate in well under a millisecond, so raw performance differences almost never matter in practice — TypeScript ergonomics and API fit are the more meaningful factors.&lt;/p&gt;
&lt;h4 id=&quot;do-i-need-to-rewrite-my-formik-forms-to-use-zod-&quot;&gt;Do I need to rewrite my Formik forms to use Zod?&lt;/h4&gt;
&lt;p&gt;No. Formik and Yup are still a perfectly fine, actively maintained combination for existing codebases. Only reach for a migration if you're already refactoring that form layer for other reasons.&lt;/p&gt;
&lt;h4 id=&quot;which-one-works-better-with-trpc-&quot;&gt;Which one works better with tRPC?&lt;/h4&gt;
&lt;p&gt;Zod, by a wide margin — tRPC's input/output validation is built with Zod's type inference in mind, and most tRPC examples and starter templates assume Zod. Yup can technically be adapted, but it's fighting the grain.&lt;/p&gt;
&lt;h4 id=&quot;can-i-use-both-zod-and-yup-in-the-same-project-&quot;&gt;Can I use both Zod and Yup in the same project?&lt;/h4&gt;
&lt;p&gt;Technically yes, but it's not something to do on purpose. If you're migrating incrementally, it's fine to have both installed temporarily — just avoid mixing them within the same feature or form, since their default behaviors (required vs. optional fields, sync vs. async) differ enough to cause confusing bugs.&lt;/p&gt;
&lt;h4 id=&quot;does-zod-support-transforming-data-not-just-validating-it-&quot;&gt;Does Zod support transforming data, not just validating it?&lt;/h4&gt;
&lt;p&gt;Yes — &lt;code&gt;.transform()&lt;/code&gt; lets you reshape data as part of validation, like converting a string date into a &lt;code&gt;Date&lt;/code&gt; object. Yup supports this too, through &lt;code&gt;.transform()&lt;/code&gt; on its schemas. Both are equally capable here.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h3&gt;
&lt;p&gt;Zod and Yup solve the exact same problem — turning &quot;hope the data is right&quot; into &quot;know the data is right&quot; — but they were built for different eras of the JavaScript ecosystem. Zod's schema-is-the-type approach is what modern TypeScript tooling expects in 2026, and it's the right default for anything new you're building. Yup remains a completely legitimate choice if you're maintaining an existing Formik-based app, and there's no urgency to rip it out just because a newer library exists.&lt;/p&gt;
&lt;p&gt;If you're starting a project today: reach for Zod, pair it with &lt;code&gt;@hookform/resolvers/zod&lt;/code&gt; for your forms, and use &lt;code&gt;.safeParse()&lt;/code&gt; on the server inside every Server Action or API route that touches user input — never trust that client-side validation alone is enough.&lt;/p&gt;
&lt;h3 id=&quot;try-this-free-developer-tool&quot;&gt;Try This Free Developer Tool&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://devstacked.tech/tools/zod-schema-generator&quot;&gt;Zod Schema Generator&lt;/a&gt; — paste a JSON sample or a TypeScript interface and get a production-ready Zod schema instantly, complete with smart field-name inference, a live validator, and ready-to-use React Hook Form, API Route, and Server Action output.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;continue-learning&quot;&gt;Continue Learning&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://devstacked.tech/blog/role-based-authentication-nextjs-16&quot;&gt;Role-Based Access Control (RBAC) in Next.js 16 (2026 Beginner's Guide)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://devstacked.tech/blog/nextjs-16-route-handlers&quot;&gt;Route Handlers Explained in Next.js 16 (Beginner's Guide)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://devstacked.tech/blog/nextjs-16-supabase-todo-app&quot;&gt;Build a Todo App with Next.js 16 and Supabase (2026 Guide)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/25116/zod-vs-yup-in-2026-which-validation-library-should-you-use</guid>
<pubDate>Sat, 22 Aug 2026 04:00:34 +0000</pubDate>
</item>
<item>
<title>Asking the user for input until they give a valid response java</title>
<link>https://coderlegion.com/19581/asking-the-user-for-input-until-they-give-a-valid-response-java</link>
<description>&lt;div&gt;&lt;p&gt;
As a Java developer, you will often find yourself in situations where you need to ask the user for input and validate it before moving forward in your program. Whether it's asking for a number within a certain range, a valid email address, or any other type of input, it's essential to ensure that the user's input is valid before proceeding.In this article, we will explore &lt;span style=&quot;color: #FF04FC;&quot;&gt;how to repeatedly ask the user for input until they give a valid response using Java&lt;/span&gt;. We will look at examples of how to accomplish this task using while loops, the &lt;span style=&quot;color: #FF04FC;&quot;&gt;Scanner&lt;/span&gt; class, and regular expressions. Whether you're a beginner or an experienced Java developer, this article will provide you with the tools you need to ensure that your program only receives valid input from the user. So let's dive in and learn how to ask the user for input until they give a valid response in Java!
&lt;/p&gt;&lt;/div&gt;&lt;hr&gt;
&lt;div id=&quot;toc-div&quot;&gt;
&lt;h3&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;&lt;strong&gt; Table of Contents:&lt;a id=&quot;toc-toogle&quot; class=&quot;open&quot;&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div id=&quot;toc-list&quot;&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#the-scanner-class&quot;&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;The Scanner class&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#examples-of-input-validation&quot;&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Examples of input validation&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#a-simple-guessing-game&quot;&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;A simple guessing game&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#conclusion&quot;&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Conclusion&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#references&quot;&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;References&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div&gt;&lt;h3&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;The Scanner class&lt;/span&gt;&lt;a id=&quot;the-scanner-class&quot; class=&quot;custom_anchor&quot;&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;The &lt;span style=&quot;color: #FF04FC;&quot;&gt;Scanner&lt;/span&gt; class in Java is used to read input from various sources, such as the keyboard, files, and network sockets. Some of the useful methods it contains are:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;nextLine()&lt;/code&gt;&lt;/span&gt;: Reads the next line of input as a String. Example usage:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Scanner scanner = new Scanner(System.in);
System.out.println(&quot;Enter your name:&quot;);
String name = scanner.nextLine();
System.out.println(&quot;Hello, &quot; + name + &quot;!&quot;);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;nextInt()&lt;/code&gt;&lt;/span&gt;: Reads the next token of input as an int. Example usage&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Scanner scanner = new Scanner(System.in);
System.out.println(&quot;Enter an integer:&quot;);
int num = scanner.nextInt();
System.out.println(&quot;You entered: &quot; + num);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;nextDouble()&lt;/code&gt;&lt;/span&gt;: Reads the next token of input as a double. Example usage:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Scanner scanner = new Scanner(System.in);
System.out.println(&quot;Enter a decimal number:&quot;);
double num = scanner.nextDouble();
System.out.println(&quot;You entered: &quot; + num);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;nextBoolean()&lt;/code&gt;&lt;/span&gt;: Reads the next token of input as a boolean. Example usage:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Scanner scanner = new Scanner(System.in);
System.out.println(&quot;Are you a student? (true/false)&quot;);
boolean isStudent = scanner.nextBoolean();
System.out.println(&quot;You are a student: &quot; + isStudent);
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;hasNext()&lt;/code&gt;&lt;/span&gt;: Returns true if the scanner has another token in its input. Example usage:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
    System.out.println(scanner.next());
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;hasNextLine()&lt;/code&gt;&lt;/span&gt;: Returns true if the scanner has another line of input. Example usage:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
    System.out.println(scanner.nextLine());
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;next()&lt;/code&gt;&lt;/span&gt;: Reads the next token of input as a String. Example usage:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Scanner scanner = new Scanner(&quot;Hello, world!&quot;);
System.out.println(scanner.next()); // Output: &quot;Hello,&quot;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;useDelimiter(String pattern)&lt;/code&gt;&lt;/span&gt;: Specifies a delimiter to be used by the scanner to separate input tokens. Example usage:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Scanner scanner = new Scanner(&quot;Hello, world!&quot;);
scanner.useDelimiter(&quot; &quot;);
System.out.println(scanner.next()); // Output: &quot;Hello,&quot;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;close()&lt;/code&gt;&lt;/span&gt;: Closes the scanner and releases any resources associated with it. Example usage:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Scanner scanner = new Scanner(System.in);
// Do some scanning here...
scanner.close();
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;div-purple&quot;&gt;
&lt;span class=&quot;alert-header&quot;&gt;Note &lt;/span&gt;
&lt;span class=&quot;alert-body&quot;&gt;
It is important to note that when a &lt;span style=&quot;color: #FF04FC;&quot;&gt;Scanner&lt;/span&gt; is closed, it can no longer be used, and attempting to do so will result in an &lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;IllegalStateException&lt;/code&gt;&lt;/span&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Examples of input validation&lt;/span&gt;&lt;a id=&quot;examples-of-input-validation&quot; class=&quot;custom_anchor&quot;&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;In Java, you can use a &lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;while&lt;/code&gt;&lt;/span&gt; loop to repeatedly ask the user for input until they give a valid response. You can use the Scanner class to read input from the user and check if it is valid using an if statement. Here is an example of how you might ask the user for an integer input and check if it is within a certain range:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int input;
        while (true) {
            System.out.println(&quot;Enter an integer between 1 and 10:&quot;);
            input = scanner.nextInt();
            if (input &amp;gt;= 1 &amp;amp;&amp;amp; input &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Another example of asking user for input and validating it until a valid input is given is for a string input, such as an email address:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String email;
        final String EMAIL_REGEX = &quot;^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}$&quot;;
        
        while (true) {
            System.out.println(&quot;Enter an email address:&quot;);
            email = scanner.nextLine();
            Pattern pattern = Pattern.compile(EMAIL_REGEX);
            Matcher matcher = pattern.matcher(email);
            if(matcher.matches()){
                break;
            }
            System.out.println(&quot;Invalid email. Please try again.&quot;);
        }
        System.out.println(&quot;Thank you for entering a valid email.&quot;);
    }
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note in the above example we used a regular expression to validate the email address, which is a powerful tool for validating different inputs.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;A simple guessing game&lt;/span&gt;&lt;a id=&quot;a-simple-guessing-game&quot; class=&quot;custom_anchor&quot;&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;In this section, we are going to create a simple guessing game to illustrate a practical approach of using input validation.&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;import java.util.Scanner;

public class GuessingGame {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int secretNumber = (int) (Math.random() * 100) + 1; // Generates a random number between 1 and 100
        int guess;

        System.out.println(&quot;I'm thinking of a number between 1 and 100. Can you guess what it is?&quot;);
        do {
            while (!scanner.hasNextInt()) {
                System.out.println(&quot;Invalid input. Please enter a number:&quot;);
                scanner.next();
            }
            guess = scanner.nextInt();
            if (guess &amp;lt; secretNumber) {
                System.out.println(&quot;Too low. Try again:&quot;);
            } else if (guess &amp;gt; secretNumber) {
                System.out.println(&quot;Too high. Try again:&quot;);
            }
        } while (guess != secretNumber);

        System.out.println(&quot;Congratulations! You guessed the number!&quot;);
        scanner.close();
    }
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;In this example, the program generates a random number between &lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;1&lt;/code&gt;&lt;/span&gt; and &lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;100&lt;/code&gt;&lt;/span&gt;, and then prompts the user to guess what the number is. The program uses a &lt;span style=&quot;color: #FF04FC;&quot;&gt;do-while&lt;/span&gt; loop to repeatedly ask the user for input until they guess the correct number. The &lt;span style=&quot;color: #FF04FC;&quot;&gt;&lt;code&gt;scanner.hasNextInt()&lt;/code&gt;&lt;/span&gt; method is used to check if the user's input is a valid integer, and if not, the program prompts the user to enter a valid number. Once the user enters the correct number, the loop exits, and the program prints a message congratulating the user for guessing the number.
&lt;div class=&quot;div-green&quot;&gt;
&lt;span class=&quot;alert-header&quot;&gt;Note &lt;/span&gt;
&lt;span class=&quot;alert-body&quot;&gt;
It is important to close the scanner object after you have finished using it to release the associated resources and avoid memory leaks&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;Conclusion&lt;/span&gt;&lt;a id=&quot;conclusion&quot; class=&quot;custom_anchor&quot;&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;In conclusion, asking the user for input and validating it is an essential task for any Java developer. By using while loops, the Scanner class, and regular expressions, you can &lt;span style=&quot;color: #FF04FC;&quot;&gt;repeatedly ask the user for input until they give a valid response&lt;/span&gt;. The examples provided in this article demonstrate how to accomplish this task for both integer and string input, but the principles can be applied to any type of input. It's important to note that validation of user input is a crucial step in ensuring the integrity of your program and protecting it from potential errors or malicious attacks. By following the techniques discussed in this article, you'll be well on your way to creating robust and secure Java programs that only accept valid input from the user.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;h3&gt;&lt;span style=&quot;font-family:arial,helvetica,sans-serif;&quot;&gt;References&lt;/span&gt;&lt;a id=&quot;references&quot; class=&quot;custom_anchor&quot;&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;The Java Scanner class documentation: https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/Scanner.html&lt;/li&gt;&lt;li&gt;Oracle's Java tutorial on regular expressions: https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/regex/Pattern.html&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/19581/asking-the-user-for-input-until-they-give-a-valid-response-java</guid>
<pubDate>Wed, 03 Jun 2026 12:26:01 +0000</pubDate>
</item>
<item>
<title>Why did I create vue-uform</title>
<link>https://coderlegion.com/4887/why-did-i-create-vue-uform</link>
<description>&lt;p&gt;In Vue, we already have the very convenient v-model syntax sugar. It handles two essential things for us:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When a JavaScript variable has a value, it fills the input field.&lt;/li&gt;
&lt;li&gt;When the input changes, the new value is passed back to JavaScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s basically what v-model does under the hood.&lt;/p&gt;
&lt;p&gt;So why redefine two-way binding?&lt;/p&gt;
&lt;p&gt;The reason is that I’ve been exploring a new approach to form validation. I believe the next generation of Vue form validators should be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Component-driven – the form behavior is powered by components, not configuration.&lt;/li&gt;
&lt;li&gt;Style-agnostic – no built-in styling, leaving developers free to define layouts.&lt;/li&gt;
&lt;li&gt;Flexible with UI libraries – should work seamlessly with input components from libraries like Naive UI, Element Plus, or even fully custom ones.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What existing validators do&lt;/p&gt;
&lt;p&gt;When I looked at existing solutions, I found a common pattern: each form field usually comes with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A label&lt;/li&gt;
&lt;li&gt;An input&lt;/li&gt;
&lt;li&gt;A help message&lt;/li&gt;
&lt;li&gt;An error message (shown when validation fails)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some libraries solve this by bundling their own input components and tightly integrating them with validation. While this works, it reduces flexibility.&lt;/p&gt;
&lt;p&gt;I wanted something different: a validator that lets developers use their own UI components, while still handling value binding and validation logic cleanly.&lt;/p&gt;
&lt;p&gt;The idea: u-field component&lt;/p&gt;
&lt;p&gt;To achieve this, I introduced the idea of a u-field component.&lt;br&gt;
You can put any input component into its slot.&lt;/p&gt;
&lt;p&gt;The u-field exposes two key bindings to its slot:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;value&lt;/strong&gt; passes the form data down to the input.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;update&lt;/strong&gt; sends the new input value back up to the form.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This makes synchronization possible, and sets the stage for validation.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-vue&quot;&gt;&amp;lt;template&amp;gt;
  &amp;lt;u-field v-slot=&quot;{ value, update }&quot;&amp;gt;
    &amp;lt;input :value=&quot;value&quot; @input=&quot;($event) =&amp;gt; update($event.target.value)&quot; /&amp;gt;
  &amp;lt;/u-field&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Why not just v-model?&lt;/p&gt;
&lt;p&gt;Looking at Vue’s official docs, this is exactly the kind of code v-model was meant to simplify.&lt;br&gt;
But when binding with parent components (not just local state), we need another kind of syntax sugar.&lt;/p&gt;
&lt;p&gt;So, inspired by vue-macros, I created a Vite plugin to introduce a new directive: &lt;code&gt;f-model&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;f-model&lt;/code&gt;, the example above becomes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-vue&quot;&gt;&amp;lt;u-field v-slot=&quot;{ value, update }&quot;&amp;gt;
  &amp;lt;input f-model /&amp;gt;
&amp;lt;/u-field&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Beyond text inputs&lt;/p&gt;
&lt;p&gt;Of course, text inputs are the simplest case.&lt;br&gt;
For other components like radio buttons, checkboxes, or selects, special handling is still needed.&lt;/p&gt;
&lt;p&gt;For third-party components, it’s straightforward:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With a regular input:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-vue&quot;&gt;&amp;lt;input f-model /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;With Naive UI’s n-input (which uses v-model:value):&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-vue&quot;&gt;&amp;lt;n-input f-model:value /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/4887/why-did-i-create-vue-uform</guid>
<pubDate>Thu, 21 Aug 2025 02:07:44 +0000</pubDate>
</item>
<item>
<title>I built vue-uform – a unstyled, component-driven form validation library for Vue 3</title>
<link>https://coderlegion.com/4803/i-built-vue-uform-a-unstyled-component-driven-form-validation-library-for-vue-3</link>
<description>&lt;h2 id=&quot;hey-everyone&quot;&gt;Hey everyone&lt;/h2&gt;
&lt;p&gt;I’ve been working on a Vue 3 form library called &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/tu6ge/vue-uform&quot;&gt;vue-uform&lt;/a&gt;, and I think it might be useful for folks who want &lt;em&gt;flexible&lt;/em&gt;, &lt;em&gt;unstyled&lt;/em&gt;, &lt;em&gt;component-driven&lt;/em&gt; form validation without the boilerplate.&lt;/p&gt;
&lt;h2 id=&quot;why-i-built-it&quot;&gt;Why I built it&lt;/h2&gt;
&lt;p&gt;Most form libraries either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Come with a bunch of built-in styles that don’t match your design system, or&lt;/li&gt;
&lt;li&gt;Require too much JS/TS setup for simple forms.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;vue-uform&lt;/em&gt; takes a different approach:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No built-in styles – you have full control over HTML &amp;amp; CSS.&lt;/li&gt;
&lt;li&gt;Treats components as first-class citizens – validation, data flow, and UI are all component-based.&lt;/li&gt;
&lt;li&gt;Works with any UI library (Element Plus, Naive UI, etc.).&lt;/li&gt;
&lt;li&gt;Supports built-in &amp;amp; custom validation rules (inspired by FormKit).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;quick-example&quot;&gt;Quick Example&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-vue&quot;&gt;&amp;lt;script setup&amp;gt;
const formValues = { username: '', password: '' }

function doLogin(data) {
  console.log(data)
}
&amp;lt;/script&amp;gt;
&amp;lt;template&amp;gt;
  &amp;lt;u-form :values=&quot;formValues&quot; @submit=&quot;doLogin&quot;&amp;gt;
    &amp;lt;u-field name=&quot;username&quot; label=&quot;Username&quot; validation=&quot;required&quot; v-slot=&quot;{ value, update }&quot;&amp;gt;
      &amp;lt;input f-model /&amp;gt;
    &amp;lt;/u-field&amp;gt;

    &amp;lt;u-field name=&quot;password&quot; label=&quot;Password&quot; validation=&quot;required|min:6&quot; v-slot=&quot;{ value, update }&quot;&amp;gt;
      &amp;lt;input type=&quot;password&quot; f-model /&amp;gt;
    &amp;lt;/u-field&amp;gt;

    &amp;lt;u-submit&amp;gt;Login&amp;lt;/u-submit&amp;gt;
  &amp;lt;/u-form&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt;That f-model directive is provided by a small Vite plugin – it’s like v-model but tailored for form fields.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;-built-in-validation-rules-include-&quot;&gt;✅ Built-in validation rules include:&lt;/h2&gt;
&lt;p&gt;required, number, email, between, starts_with, url, and more – you can also add your own custom rules with parameters&lt;/p&gt;
&lt;p&gt;Example custom rule:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script setup lang=&quot;ts&quot;&amp;gt;
function isfruit(node: FieldNode): boolean | string {
  const { value } = node;
  if (value.value != &quot;apple&quot; &amp;amp;&amp;amp; value.value != &quot;banana&quot;) {
    return &quot;this value is not apple or banana&quot;;
  }
  return true;
}
&amp;lt;/script&amp;gt;
&amp;lt;template&amp;gt;
    &amp;lt;u-field
      name=&quot;fruit&quot;
      label=&quot;Fruit&quot;
      help=&quot;please input a fruit&quot;
      :rules=&quot;{ isfruit }&quot;
      validation=&quot;required|isfruit&quot;
      v-slot=&quot;{ value, update }&quot;
    &amp;gt;
      &amp;lt;input f-model /&amp;gt;
    &amp;lt;/u-field&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pnpm install vue-uform
pnpm install @vue-uform/vite-plugin -D
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;links&quot;&gt;Links&lt;/h2&gt;
&lt;p&gt;GitHub: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/tu6ge/vue-uform&quot;&gt;https://github.com/tu6ge/vue-uform&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;StackBlitz: &lt;a rel=&quot;nofollow&quot; href=&quot;https://stackblitz.com/~/github.com/tu6ge/vue-uform-example&quot;&gt;https://stackblitz.com/~/github.com/tu6ge/vue-uform-example&lt;/a&gt;&lt;/p&gt;
</description>
<category>vue.js</category>
<guid isPermaLink="true">https://coderlegion.com/4803/i-built-vue-uform-a-unstyled-component-driven-form-validation-library-for-vue-3</guid>
<pubDate>Mon, 18 Aug 2025 20:25:28 +0000</pubDate>
</item>
</channel>
</rss>