Skip to Content

Call Your API

The SDK from the last chapter is just TypeScript — anything that imports TypeScript can use it. This chapter walks through three real consumption patterns: a Node script, a React component, and an error case.


1. Set up the connection

Every SDK call takes an IConnection as its first argument. Build it once:

connection.ts
import { IConnection } from "@my-app/api"; // or "../api" export const connection: IConnection = { host: "http://localhost:37001", };

Add headers when you need auth:

const authed: IConnection = { ...connection, headers: { Authorization: `Bearer ${token}` }, };

IConnection is a plain object. You can build it from environment variables, swap it per test, or wrap it in a custom hook — there is no global state.


2. A Node script

Drop this in a scripts/ directory and run it with npx ttsx scripts/probe.ts. (ttsx is the Nestia toolchain’s TypeScript runner — think ts-node or tsx, but with Nestia’s transformer applied. If you prefer, run npx ttsc to compile first and then node scripts/probe.js.)

scripts/probe.ts
import api from "@my-app/api"; import { connection } from "../connection"; const main = async () => { const created = await api.functional.articles.create(connection, { title: "Hello SDK", body: "First article via the generated client.", }); console.log("Created:", created.id); const read = await api.functional.articles.at(connection, created.id); console.log("Read back:", read.title); }; main().catch(console.error);

Try changing title: "no" (too short). TypeScript will not complain — the length is a runtime tag — but the server will return a 400 and the SDK throws an HttpError. We will handle that in section 4.


3. A React component

The exact same import works in a Vite / Next.js / React Native client:

src/CreateArticleForm.tsx
import api from "@my-app/api"; import { useState } from "react"; import { connection } from "./connection"; export const CreateArticleForm = () => { const [title, setTitle] = useState(""); const [body, setBody] = useState(""); const [out, setOut] = useState<string | null>(null); const submit = async () => { const article = await api.functional.articles.create(connection, { title, body, }); setOut(article.id); }; return ( <form onSubmit={(e) => { e.preventDefault(); void submit(); }}> <input value={title} onChange={(e) => setTitle(e.target.value)} /> <textarea value={body} onChange={(e) => setBody(e.target.value)} /> <button>Create</button> {out && <p>Created: {out}</p>} </form> ); };

What you get for free:

  • Autocomplete on article.id, article.title, etc.
  • Rename refactors that follow through from server to client. Rename IArticle.title on the server, run npx nestia sdk, and the frontend stops compiling at the exact line that needs to change.
  • No URL strings. No Content-Type headers. No JSON.stringify. The SDK does it all.

Bundling the SDK for the browser? TypeScript compilers handle the SDK directly with no special config. If you do not call typia.assert in your frontend code, you don’t even need a Nestia plugin in your bundler. If you do, install @ttsc/unplugin — see Setup → Bundlers.


4. Handle errors

The SDK throws HttpError for any non-2xx response:

import api, { HttpError } from "@my-app/api"; try { await api.functional.articles.create(connection, { title: "no", // too short body: "", }); } catch (e) { if (e instanceof HttpError) { console.log(e.status); // 400 console.log(await e.toJSON()); // { path: "$input.title", expected: "...", value: "no" } } else { throw e; } }

Advanced: typed error responses. For richer error handling — e.g. a 400 that returns a validation DTO and a 403 that returns a permission DTO, each fully typed — flip propagate: true in nestia.config.ts. The SDK then returns a { success, status, data } discriminated union instead of throwing, so the client can branch on the status code with type narrowing. See SDK → Propagation Mode when you’re ready.


5. What you’ve earned

The frontend talks to the backend with the same types the backend stores. A breaking change in a DTO is now a compile error, not a 2 a.m. Slack thread. That is the point of the whole exercise.


Next

Two more generators are waiting: Generate Swagger for an OpenAPI document, then Auto E2E Tests for a free regression suite.

Last updated on