Skip to content

Latest commit

 

History

History
72 lines (58 loc) · 1.9 KB

validation.md

File metadata and controls

72 lines (58 loc) · 1.9 KB

Response validation with Validator functions

Updated on 5/04/2024 for simpler-fetch@v11.0.0

You can write validation functions to do runtime response validation.

import { sf } from "simpler-fetch";

async function callAPI() {
  // Expected response type from the API service
  type Todo = {
    userId: number;
    id: number;
    title: string;
    completed: boolean;
  };

  const validator = (obj: any): obj is Todo =>
    typeof obj.userId === "number" &&
    typeof obj.id === "number" &&
    typeof obj.title === "string" &&
    typeof obj.completed === "boolean";

  const [err, res] = await sf
    .useOnce("https://jsonplaceholder.typicode.com/todos/1")
    .GET()
    .runJSON<Todo>(validator);

  if (err !== null) {
    console.error(err);
  } else if (res.ok) {
    // Compile time type safe AND runtime validated data structure
    console.log(res.data.id);
  }
}

callAPI();

Although this is fine, this is not the recommended way since it can be quite error prone. Imagine a situation where the type predicate just returns true regardless. This will make your runtime validation useless.

import { sf } from "simpler-fetch";

async function callAPI() {
  // Expected response type from the API service
  type Todo = {
    userId: number;
    id: number;
    title: string;
    completed: boolean;
  };

  // Returns true no matter what!
  const validator = (obj: any): obj is Todo => true;

  const [err, res] = await sf
    .useOnce("https://jsonplaceholder.typicode.com/todos/1")
    .GET()
    .runJSON<Todo>(validator);

  if (err !== null) {
    console.error(err);
  } else if (res.ok) {
    // Compile time type safe AND runtime validated data structure
    console.log(res.data.id);
  }
}

callAPI();

Therefore, this way of handwriting validation functions is not recommended. Instead use a validation library like Zod. See docs on using Zod instead.