I wrote my server backend in PHP. Now I want to create the communication between frontend (typescript) and backend.
I would like to receive a standardized response for each of my API requests. Accordingly, each response from my server is structured like this:
type Response<T> = {
status: boolean,
statusCode: number | null,
statusText: string | null,
statusDetails: string | null,
data: T | null
};
Important: Since not all API requests return data (e.g. login and logout), the key data can also be null.
If data is available, it should be of generic type T. This type depends on the API request. Example:
type ApiInitData = {
user: {
online: boolean | null,
name: string | null,
userGroupName: string | null,
language: string | null,
decimals: number | null,
},
language: {
supportedLanguages: string[];
defaultLanguage: string
}
}
So if the API request was successful, I want to get an object of type Response<ApiInitData>. In this case the key data in Response<T> is not null of course.
My goal is to use a Typescript function that returns a Promise. In the .then of the Promise I want to control the further processing (e.g. display error message).
Example:
Api.login(username, password).then((response) => {
if(response.status === true){
// Ok
}else{
// Some error has occurred.
console.log(response.statusCode);
console.log(response.statusText);
}
});
When an error occurs, the Promise should be forced into the Response<null> type so that a standardized object is always returned in the end.
This code snippet is my attempt:
//
// Example for login
//
static login = (username: string, password: string) => {
const data = {
'api': 'login',
'username': username,
'password': password
};
return this.request<Response<null>>(data);
}
//
// Example for init data
//
static getInitData = () => {
const data = {
'api': 'getInitializationData'
};
return this.request<Response<ApiInitData | null>>(data);
}
//
// Standard request function for all API requests.
//
static request = <T>(data: object, options: RequestInit = {}, url: string | null = null) => {
const requestOptions = this.prepareRequest(data, options, url);
return fetch(requestOptions.url, requestOptions.options)
.then((response) => {
if (response.ok) {
return response.json() as Promise<T>;
} else {
const result: Response<null> = {
status: false,
statusCode: response.status,
statusText: response.statusText,
statusDetails: null,
data: null,
}
return new Promise<Response<null>>((resolve) => { resolve(result) });
}
}).catch((error) => {
const result: Response<null> = {
status: false,
statusCode: 503,
statusText: error,
statusDetails: null,
data: null,
}
return new Promise<Response<null>>((resolve) => { resolve(result) });
});
}
The typescript compiler throws this error message: The argument of type "(response: Response) => Promise | Promise<Response>" cannot be assigned to the parameter of type "(value: Response) => T | PromiseLike". (line 4 of my request function).
I've no idea how to fix it. So I've two questions:
- How can I fix the error ?
- Is my approach used a common solution to this problem? Or is a completely different approach currently recommended here?