The Request
class, defined in src/api/request.ts, is a custom class designed to handle generic or specific asynchronous HTTP requests. It provides a set of methods and properties that allow for easy configuration and execution of requests.
-
Request Interception: The
Request
class includes ahandleRequest
method that acts as a request interceptor. This method sets default headers for the requests, specifically setting the 'Content-Type' to 'application/json' if not already set. -
Response Interception: The
Request
class includes ahandleResponse
method that acts as a response interceptor. This method processes the response from the HTTP request and returns a custom response object. The custom response object includes the original response data, a success flag, the status code, and a message. This feature allows for consistent handling of responses throughout the application. -
External statusMessage Map: The
Request
class attempts to import an external statusMessage map using theimportExternalResponseMessages
method. This map should be located in the same directory as theRequest
class and namedstatusMessage.map.ts
. This allows for custom response messages based on the status code of the HTTP response. If the import fails, theRequest
class will fallback to a smaller default map that includes a few of the most common status codes and their corresponding response messages. -
Factory Method: The
Request
class includes a staticcreate
method that acts as an asyncronous factory for creating new instances of theRequest
class. This method also initializes the instance by attempting to import the external statusMessage map asyncronously.
The Request
class provides a flexible way to handle HTTP requests. It can be used in two main ways: with dynamic configuration at runtime, or with predefined configuration. Dynamic configuration allows you to reuse the same Request
instance for different requests, while predefined configuration simplifies the code when the same request is made multiple times. The Request
class also supports extensibility, allowing you to create subclasses for specific types of requests. Here are some examples of how to use the Request
class in different scenarios:
In this example, the options are passed when calling the run
method. This allows for dynamic configuration of the request at runtime, and the possibility of recycling the Request instance for as many http requests as needed with completely different options.
import { Request } from '@/api/request'
const request = await Request.create()
const options = { url: '/user', method: 'POST', body: { name: 'John', lastname: 'Doe' } }
// Dynamic configuration at runtime
const { data, success, status, message } = await request.run(options)
In this example, the options are passed when creating the Request instance. This allows for predefined configuration of the request, thus not requiring to pass the options in runtime.
import { Request } from '@/api/request'
const options = { url: '/user', method: 'POST', body: { name: 'John', lastname: 'Doe' } }
// Predefined Request Configuration
const saveUserRequest = await Request.create(options)
const { data, success, status, message } = await saveUserRequest.run()
The Request
class can be extended to create subclasses that hold their own default configurations. This allows for the creation of specialized request handlers that can be used for specific types of HTTP requests.
To create a subclass, simply extend the Request
class and override the necessary methods or properties. For example:
import { ApiResponse, Request } from '@/api/request'
import { AxiosRequestConfig } from 'axios'
export class GetUserRequest extends Request {
private config: AxiosRequestConfig
private readonly default: AxiosRequestConfig = {
url: '/user',
method: 'POST',
withCredentials: true,
// More default values
}
constructor (options?: AxiosRequestConfig) {
super(options)
this.config = { ...this.default, ...options }
}
public static async create (options?: AxiosRequestConfig): Promise<GetUserRequest> {
const request = new GetUserRequest(options)
await request.importExternalResponseMessages()
return request
}
public async run<T = any> (config?: AxiosRequestConfig): Promise<ApiResponse<T>> {
return super.run<T>({ ...this.config, ...config })
}
}
It can then be used in this simplified way:
import { SaveUserRequest } from '@/api/user/save'
const body = { name: 'John', lastname: 'Doe' }
const saveUserRequest = await SaveUserRequest.create({ body })
const { data, success, status, message } = await saveUserRequest.run()
Alternatively:
import { SaveUserRequest } from '@/api/user/save'
const body = { name: 'John', lastname: 'Doe' }
const saveUserRequest = await SaveUserRequest.create()
const { data, success, status, message } = await saveUserRequest.run({ body })
In this example, SaveUserRequest
is a subclass of Request
that defaults to making a specific request using predefined configurations. Note that both create
and run
methods also support the options argument that can be merged to the default configuration of the subclass, allowing flexible and reusable request handling.