Tillitsdone
down Scroll to discover

Building a Type-Safe API Client with TypeScript

Learn how to create a robust, type-safe API client in TypeScript that ensures runtime validation, proper error handling, and seamless integration with your application's type system.
thumbnail

Building a Type-Safe API Client with TypeScript

A futuristic mechanical circuit board maze with intricate paths made of glowing neon yellow and electric blue traces viewed directly from above in a perfect top-down perspective depicting complexity and connection. High-quality ultra-realistic cinematic 8K UHD high resolution sharp and detail

Ever found yourself wrestling with API calls in TypeScript, never quite sure if you’re handling the responses correctly? You’re not alone. Today, we’ll dive into creating a robust, type-safe API client that’ll make your development experience smoother and more reliable.

The Problem with Traditional API Clients

Let’s be honest - we’ve all been there. You’re making API calls using fetch or axios, crossing your fingers that the response matches what you expect. Maybe you’ve even encountered that dreaded runtime error when the API response doesn’t quite match your types. It’s frustrating, time-consuming, and exactly what we’re going to fix.

Abstract 3D geometric shapes floating in space featuring sage green and pine green crystalline structures interconnected by glowing lines captured from a 45-degree angle perspective. High-quality ultra-realistic cinematic 8K UHD high resolution sharp and detail

Building Our Type-Safe Foundation

First, let’s create a foundation that ensures type safety from the ground up. We’ll start by defining our API response types:

interface ApiResponse\<T\> {
data: T;
status: number;
message: string;
}
interface User {
id: number;
name: string;
email: string;
}

Now, here’s where it gets interesting. Instead of creating a simple client, we’ll build one that validates our types at runtime:

class TypeSafeApiClient {
private baseUrl: string;
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}
async get\<T\>(path: string, validator: (data: unknown) => data is T): Promise<ApiResponse\<T\>> {
const response = await fetch(`${this.baseUrl}${path}`);
const json = await response.json();
if (!validator(json.data)) {
throw new Error('Response validation failed');
}
return json;
}
}

Robotic arms assembling a complex mechanical structure with bright neon green and metallic components shot from a dramatic low angle perspective. High-quality ultra-realistic cinematic 8K UHD high resolution sharp and detail

Implementing Runtime Type Checking

The real magic happens when we combine our type-safe client with runtime type checking. Here’s how we can implement it using a validation library:

import { z } from 'zod';
const userSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
});
const apiClient = new TypeSafeApiClient('https://api.example.com');
// Type-safe API call
const getUser = async (id: number) => {
return apiClient.get<User>(
`/users/${id}`,
userSchema.parse
);
};

Advanced Features and Error Handling

Let’s take it a step further by adding proper error handling and response type inference:

type ApiErrorResponse = {
error: string;
code: number;
};
class TypeSafeApiError extends Error {
constructor(public response: ApiErrorResponse) {
super(response.error);
}
}
// Enhanced client method
async request\<T\>(
method: string,
path: string,
validator: (data: unknown) => data is T,
body?: unknown
): Promise\<T\> {
try {
const response = await fetch(`${this.baseUrl}${path}`, {
method,
body: body ? JSON.stringify(body) : undefined,
headers: {
'Content-Type': 'application/json',
},
});
const json = await response.json();
if (!response.ok) {
throw new TypeSafeApiError(json);
}
if (!validator(json)) {
throw new Error('Response validation failed');
}
return json;
} catch (error) {
if (error instanceof TypeSafeApiError) {
throw error;
}
throw new Error('Network error');
}
}

When to Use This Pattern

This pattern shines when you’re building large-scale applications where type safety is crucial. It’s particularly valuable when:

  • Working with complex API responses
  • Dealing with frequently changing API contracts
  • Building applications with strict type safety requirements
  • Collaborating in large teams where type safety helps prevent bugs

Conclusion

Building a type-safe API client isn’t just about adding types - it’s about creating a robust system that catches errors early and makes your development experience more enjoyable. By combining TypeScript’s static typing with runtime validation, we’ve created a powerful pattern that will help you build more reliable applications.

A clay sculpture abstract representation of interconnected geometric forms in bright yellow and metallic gold tones arranged in a spiral pattern photographed from a bird's eye view. High-quality ultra-realistic cinematic 8K UHD high resolution sharp and detail

Remember, type safety isn’t just about catching errors - it’s about building confidence in your code and making your development process smoother and more efficient.

icons/code-outline.svg Typescript Blogs
Superset of JavaScript adding static types for improved code quality and maintainability.
icons/logo-tid.svg

Talk with CEO

Ready to bring your web/app to life or boost your team with expert Thai developers?
Contact us today to discuss your needs, and let’s create tailored solutions to achieve your goals. We’re here to help at every step!
🖐️ Contact us
Let's keep in Touch
Thank you for your interest in Tillitsdone! Whether you have a question about our services, want to discuss a potential project, or simply want to say hello, we're here and ready to assist you.
We'll be right here with you every step of the way.
Contact Information
rick@tillitsdone.com+66824564755
Find All the Ways to Get in Touch with Tillitsdone - We're Just a Click, Call, or Message Away. We'll Be Right Here, Ready to Respond and Start a Conversation About Your Needs.
Address
9 Phahonyothin Rd, Khlong Nueng, Khlong Luang District, Pathum Thani, Bangkok Thailand
Visit Tillitsdone at Our Physical Location - We'd Love to Welcome You to Our Creative Space. We'll Be Right Here, Ready to Show You Around and Discuss Your Ideas in Person.
Social media
Connect with Tillitsdone on Various Social Platforms - Stay Updated and Engage with Our Latest Projects and Insights. We'll Be Right Here, Sharing Our Journey and Ready to Interact with You.
We anticipate your communication and look forward to discussing how we can contribute to your business's success.
We'll be here, prepared to commence this promising collaboration.
Frequently Asked Questions
Explore frequently asked questions about our products and services.
Whether you're curious about features, warranties, or shopping policies, we provide comprehensive answers to assist you.