Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ A versatile, type-safe API client designed for TypeScript applications. It simpl
- **Authorization Support**: Automatically includes authorization tokens in requests.
- **Customizable Unauthorized Access Handling**: Executes a callback function when encountering a 401 Unauthorized response, allowing for custom reaction strategies such as redirecting to a login page.
- **Simplified API Requests**: Offers methods for common HTTP requests (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`) with a straightforward, promise-based API.
- **Flexible Response Handling**: Allows specifying the `responseType` for requests, enabling direct handling of blobs, JSON, and other formats.

## Installation

Expand Down Expand Up @@ -46,7 +47,7 @@ Use the `ApiKitClient` instance to make API requests. Here are some examples:

### Fetching Data

Fetch a list of resources:
Fetch a list of resources specifying the expected response type:

```ts
interface User {
Expand All @@ -68,6 +69,14 @@ ApiKitClient.getOne<User>('/users/1')
.catch(error => console.error(error));
```

Fetch a blob data:

```ts
ApiKitClient.get<Blob>('/download', { responseType: 'blob' })
.then(response => console.log(response.data)) // Expected to be of type Blob
.catch(error => console.error(error));
```

Fetch a paginated resource:

```ts
Expand All @@ -86,7 +95,7 @@ const newUser: User = {
email: 'john@example.com',
};

ApiKitClient.post<User>('/users', newUser)
ApiKitClient.post<User>('/users', newUser, { responseType: 'json' }) // by default is json, so you don't need to explicitly set it unless you need a different type (like 'blob', 'document', 'arraybuffer', or 'text').
.then(response => console.log(response.data)) // Expected to be of type User
.catch(error => console.error(error));
```
Expand Down
50 changes: 34 additions & 16 deletions src/ApiKitClient.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import axios, { AxiosInstance, AxiosResponse, AxiosError } from 'axios';
import axios, { AxiosInstance, AxiosResponse, AxiosError, AxiosRequestConfig } from 'axios';
import { PaginatedResponse } from './types';

type UnauthorizationCallback = () => void;
type AuthTokenCallback = () => Promise<string>;
type Options = {
responseType?: AxiosRequestConfig['responseType'],
params?: URLSearchParams
}

export class ApiKitClient {
private static instance: AxiosInstance;
Expand Down Expand Up @@ -41,38 +45,52 @@ export class ApiKitClient {
}
}

public static async get<T>(endpoint: string, params?: URLSearchParams): Promise<AxiosResponse<T>> {
private static createConfig(options?: Options): AxiosRequestConfig {
return {
responseType: options?.responseType,
params: options?.params
};
}

public static async get<T>(endpoint: string, options?: Options): Promise<AxiosResponse<T>> {
this.checkInitialization();
return this.instance!.get<T>(endpoint, { params });
const config = this.createConfig(options);
return this.instance!.get<T>(endpoint, config);
}
public static async getOne<T>(endpoint: string, params?: URLSearchParams): Promise<AxiosResponse<T>> {

public static async getOne<T>(endpoint: string, options?: Options): Promise<AxiosResponse<T>> {
this.checkInitialization();
return this.instance!.get<T>(endpoint, { params });
const config = this.createConfig(options);
return this.instance!.get<T>(endpoint, config);
}

public static async getPaginated<T>(endpoint: string, params?: URLSearchParams): Promise<AxiosResponse<PaginatedResponse<T>>> {
public static async getPaginated<T>(endpoint: string, options?: Options): Promise<AxiosResponse<PaginatedResponse<T>>> {
this.checkInitialization();
return this.instance!.get<PaginatedResponse<T>>(endpoint, { params });
const config = this.createConfig(options);
return this.instance!.get<PaginatedResponse<T>>(endpoint, config);
}

public static async post<T>(endpoint: string, data: T): Promise<AxiosResponse<T>> {
public static async post<T>(endpoint: string, data: T, options?: Options): Promise<AxiosResponse<T>> {
this.checkInitialization();
return this.instance!.post<T>(endpoint, data);
const config = this.createConfig(options);
return this.instance!.post<T>(endpoint, data, config);
}

public static async put<T>(endpoint: string, data: T): Promise<AxiosResponse<T>> {
public static async put<T>(endpoint: string, data: T, options?: Options): Promise<AxiosResponse<T>> {
this.checkInitialization();
return this.instance!.put<T>(endpoint, data);
const config = this.createConfig(options);
return this.instance!.put<T>(endpoint, data, config);
}

public static async patch<T>(endpoint: string, data: T): Promise<AxiosResponse<T>> {
public static async patch<T>(endpoint: string, data: T, options?: Options): Promise<AxiosResponse<T>> {
this.checkInitialization();
return this.instance!.patch<T>(endpoint, data);
const config = this.createConfig(options);
return this.instance!.patch<T>(endpoint, data, config);
}

public static async delete<T>(endpoint: string): Promise<AxiosResponse<T>> {
public static async delete<T>(endpoint: string, options?: Options): Promise<AxiosResponse<T>> {
this.checkInitialization();
return this.instance!.delete<T>(endpoint);
const config = this.createConfig(options);
return this.instance!.delete<T>(endpoint, config);
}
}