Skip to content

Basic Usage

Learn how to create a client with HTTP delegate, define typed methods, and make HTTP requests.

Type Definitions

First, define the types for your API responses:

typescript
interface User {
  id: number;
  name: string;
  username: string;
  email: string;
  address: {
    street: string;
    suite: string;
    city: string;
    zipcode: string;
    geo: {
      lat: string;
      lng: string;
    };
  };
  phone: string;
  website: string;
  company: {
    name: string;
    catchPhrase: string;
    bs: string;
  };
}

interface Post {
  userId: number;
  id: number;
  title: string;
  body: string;
}

interface Comment {
  postId: number;
  id: number;
  name: string;
  email: string;
  body: string;
}

type CreatePost = Omit<Post, 'id'>;

Client Setup

Create a Universal Client with HTTP delegate and typed methods:

typescript
import { universalClient, withDelegate, withMethods } from 'universal-client';

const client = universalClient(
  withDelegate({ type: 'http', impl: 'fetch' }),
  withMethods(({ delegate }) => ({
    // User operations
    getUser: (id: number) => delegate.get<User>(`https://jsonplaceholder.typicode.com/users/${id}`),
    getAllUsers: () => delegate.get<User[]>('https://jsonplaceholder.typicode.com/users'),

    // Post operations
    getPost: (id: number) => delegate.get<Post>(`https://jsonplaceholder.typicode.com/posts/${id}`),
    getAllPosts: () => delegate.get<Post[]>('https://jsonplaceholder.typicode.com/posts'),
    createPost: (data: CreatePost) => delegate.post<Post>('https://jsonplaceholder.typicode.com/posts', data),
    updatePost: (id: number, data: Post) => delegate.put<Post>(`https://jsonplaceholder.typicode.com/posts/${id}`, data),
    deletePost: (id: number) => delegate.delete<void>(`https://jsonplaceholder.typicode.com/posts/${id}`),

    // Comment operations
    getPostComments: (postId: number) => delegate.get<Comment[]>(`https://jsonplaceholder.typicode.com/posts/${postId}/comments`),
  })),
);

Using Different HTTP Implementations

The Universal Client supports three HTTP implementations:

1. Fetch (Default, Browser Native)

typescript
const client = universalClient(
  withDelegate({ type: 'http', impl: 'fetch' }),
  withMethods(({ delegate }) => ({
    getUser: (id: number) => delegate.get<User>(`/users/${id}`),
  })),
);

2. Axios (Install separately: npm install axios)

typescript
const client = universalClient(
  withDelegate({ type: 'http', impl: 'axios' }),
  withMethods(({ delegate }) => ({
    getUser: (id: number) => delegate.get<User>(`/users/${id}`),
  })),
);

3. Better-Fetch (Install separately: npm install @better-fetch/fetch)

typescript
const client = universalClient(
  withDelegate({ type: 'http', impl: 'better-fetch' }),
  withMethods(({ delegate }) => ({
    getUser: (id: number) => delegate.get<User>(`/users/${id}`),
  })),
);

Usage Examples

Fetching a Single User

typescript
async function fetchUser(): Promise<void> {
  try {
    const user = await client.getUser(1);
    console.log('User:', {
      id: user.id,
      name: user.name,
      email: user.email,
      company: user.company.name
    });
  } catch (error) {
    console.error('Error fetching user:', error);
  }
}

Fetching Multiple Users

typescript
async function fetchAllUsers(): Promise<void> {
  try {
    const users = await client.getAllUsers();
    console.log(`Fetched ${users.length} users`);

    users.slice(0, 3).forEach(user => {
      console.log(`- ${user.name} (${user.email})`);
    });
  } catch (error) {
    console.error('Error fetching users:', error);
  }
}

Creating a New Post

typescript
async function createNewPost(): Promise<void> {
  try {
    const postData: CreatePost = {
      title: 'My New Post',
      body: 'This is the content of my new post created with Universal Client!',
      userId: 1
    };

    const newPost = await client.createPost(postData);

    console.log('Created post:', {
      id: newPost.id,
      title: newPost.title
    });
  } catch (error) {
    console.error('Error creating post:', error);
  }
}

Updating a Post

typescript
async function updateExistingPost(postId: number): Promise<void> {
  try {
    const updatedData: Post = {
      id: postId,
      userId: 1,
      title: 'Updated Post Title',
      body: 'This is the updated content!'
    };

    const updatedPost = await client.updatePost(postId, updatedData);

    console.log('Updated post:', {
      id: updatedPost.id,
      title: updatedPost.title
    });
  } catch (error) {
    console.error('Error updating post:', error);
  }
}

Fetching Comments

typescript
async function fetchPostComments(): Promise<void> {
  try {
    const comments = await client.getPostComments(1);

    console.log(`Found ${comments.length} comments`);

    if (comments.length > 0) {
      const firstComment = comments[0];
      console.log('First comment:', {
        id: firstComment.id,
        name: firstComment.name,
        email: firstComment.email,
        body: firstComment.body.substring(0, 50) + '...'
      });
    }
  } catch (error) {
    console.error('Error fetching comments:', error);
  }
}

Using with Environment Management

For managing multiple environments (dev, staging, prod):

typescript
import { universalClient, withDelegate, withEnvironments, withMethods } from 'universal-client';

const client = universalClient(
  withDelegate({ type: 'http', impl: 'fetch' }),
  withEnvironments({
    name: 'delegate',
    environments: {
      development: 'http://localhost:3000',
      staging: 'https://staging-api.example.com',
      production: 'https://api.example.com'
    },
    default: 'development'
  }),
  withMethods(({ delegate }) => ({
    getUser: (id: number) => delegate.get<User>(`/users/${id}`),
    getAllUsers: () => delegate.get<User[]>('/users'),
  })),
);

// Switch environment
client.environments.setEnvironment('production');

// Make request (will use production URL)
const user = await client.getUser(1);

Error Handling

typescript
async function fetchWithErrorHandling(): Promise<User | null> {
  try {
    return await client.getUser(1);
  } catch (error) {
    if (error instanceof Error) {
      console.error('Network error:', error.message);
    } else {
      console.error('Unknown error:', error);
    }
    return null;
  }
}

Released under the MIT License.