Create http wrapper

This commit is contained in:
Guilherme Werner
2024-01-02 08:17:25 -03:00
parent 81cabdd26c
commit 3bc20c99b9
6 changed files with 220 additions and 142 deletions

View File

@ -1,6 +1,6 @@
// Copyright (c) Tribufu. All Rights Reserved. // Copyright (c) Tribufu. All Rights Reserved.
import { HeaderMap } from "./http"; import { HeaderMap, TribufuHttp } from "./http";
import { JavaScriptRuntime } from "./node"; import { JavaScriptRuntime } from "./node";
import { TribufuApiOptions } from "./options"; import { TribufuApiOptions } from "./options";
import { TribufuBot } from "./bot"; import { TribufuBot } from "./bot";
@ -24,39 +24,17 @@ import snakecaseKeys from "snakecase-keys";
* - A client give you read and write access to the Tribufu API as a client application. * - A client give you read and write access to the Tribufu API as a client application.
*/ */
export class TribufuApi { export class TribufuApi {
protected readonly http: TribufuHttp;
protected readonly options: TribufuApiOptions; protected readonly options: TribufuApiOptions;
protected readonly http: AxiosInstance;
constructor(options?: TribufuApiOptions | null) { constructor(options?: TribufuApiOptions | null) {
this.options = options || {}; this.options = options || {};
let http = axios.create({ this.http = new TribufuHttp({
baseURL: TribufuApi.getBaseUrl(), baseUrl: TribufuApi.getBaseUrl(),
headers: TribufuApi.defaultHeaders(), headers: TribufuApi.defaultHeaders(),
logEnabled: TribufuApi.debugEnabled(),
}); });
http.interceptors.request.use((req) => {
if (TribufuApi.debugEnabled()) {
console.log(`(TribufuApi) ${req.method?.toUpperCase()} ${req.baseURL}${req.url}`);
}
const contentType = req.headers["Content-Type"];
if (req.data && (contentType === "application/json" || contentType === "application/x-www-form-urlencoded")) {
req.data = snakecaseKeys(req.data);
}
return req;
});
http.interceptors.response.use((res) => {
if (res.data) {
res.data = camelcaseKeys(res.data);
}
return res;
});
this.http = http;
} }
/** /**
@ -235,90 +213,6 @@ export class TribufuApi {
return headers; return headers;
} }
/**
* Get a resource from the Tribufu API.
* @returns T | null
*/
protected async get<T>(path: string, headers?: HeaderMap | null): Promise<T | null> {
try {
const requestHeaders = headers || this.getHeaders();
const response = await this.http.get(path, { headers: requestHeaders });
if (response.status !== 200) {
return null;
}
return response.data as T;
} catch (error) {
return null;
}
}
/**
* Create a resource to the Tribufu API.
* @param path
* @param body
* @param headers
* @returns T | null
*/
protected async post<S, T>(path: string, body: S, headers?: HeaderMap | null): Promise<T | null> {
try {
const requestHeaders = headers || this.getHeaders();
const response = await this.http.post(path, body, { headers: requestHeaders });
if (response.status !== 200) {
return null;
}
return response.data as T;
} catch (error) {
return null;
}
}
/**
* Update a resource on the Tribufu API.
* @param path
* @param body
* @param headers
* @returns T | null
*/
protected async put<S, T>(path: string, body: S, headers?: HeaderMap | null): Promise<T | null> {
try {
const requestHeaders = headers || this.getHeaders();
const response = await this.http.put(path, body, { headers: requestHeaders });
if (response.status !== 200) {
return null;
}
return response.data as T;
} catch (error) {
return null;
}
}
/**
* Delete a resource from the Tribufu API.
* @param path
* @param headers
* @returns T | null
*/
protected async delete<T>(path: string, headers?: HeaderMap | null): Promise<T | null> {
try {
const requestHeaders = headers || this.getHeaders();
const response = await this.http.delete(path, { headers: requestHeaders });
if (response.status !== 200) {
return null;
}
return response.data as T;
} catch (error) {
return null;
}
}
/** /**
* Get games from the Tribufu API. * Get games from the Tribufu API.
* @param page * @param page
@ -326,7 +220,7 @@ export class TribufuApi {
*/ */
public async getGames(page: number = 1): Promise<any[]> { public async getGames(page: number = 1): Promise<any[]> {
const headers = this.getHeaders(); const headers = this.getHeaders();
const responseBody = await this.get<any[]>(`/v1/packages?page=${page}`, headers); const responseBody = await this.http.get<any[]>(`/v1/packages?page=${page}`, headers);
if (!responseBody) { if (!responseBody) {
return []; return [];
@ -342,7 +236,7 @@ export class TribufuApi {
*/ */
public async getGameyId(id: string): Promise<any | null> { public async getGameyId(id: string): Promise<any | null> {
const headers = this.getHeaders(); const headers = this.getHeaders();
const responseBody = await this.get<any>(`/v1/packages/${id}`, headers); const responseBody = await this.http.get<any>(`/v1/packages/${id}`, headers);
if (!responseBody) { if (!responseBody) {
return null; return null;
@ -358,7 +252,7 @@ export class TribufuApi {
*/ */
public async getServers(page: number = 1): Promise<any[]> { public async getServers(page: number = 1): Promise<any[]> {
const headers = this.getHeaders(); const headers = this.getHeaders();
const responseBody = await this.get<any[]>(`/v1/servers?page=${page}`, headers); const responseBody = await this.http.get<any[]>(`/v1/servers?page=${page}`, headers);
if (!responseBody) { if (!responseBody) {
return []; return [];
@ -387,7 +281,7 @@ export class TribufuApi {
*/ */
public async getServerById(id: string): Promise<any> { public async getServerById(id: string): Promise<any> {
const headers = this.getHeaders() const headers = this.getHeaders()
const responseBody = await this.get<any>(`/v1/servers/${id}`, headers); const responseBody = await this.http.get<any>(`/v1/servers/${id}`, headers);
if (!responseBody) { if (!responseBody) {
return null; return null;
@ -403,7 +297,7 @@ export class TribufuApi {
*/ */
public async getServerByAddress(address: string): Promise<any> { public async getServerByAddress(address: string): Promise<any> {
const headers = this.getHeaders(); const headers = this.getHeaders();
const responseBody = await this.get(`/v1/servers/address/${address}`, headers); const responseBody = await this.http.get(`/v1/servers/address/${address}`, headers);
if (!responseBody) { if (!responseBody) {
return null; return null;

View File

@ -251,7 +251,7 @@ export class TribufuClient extends TribufuApi {
const url = `/v1/oauth2/introspect`; const url = `/v1/oauth2/introspect`;
const headers = this.getOAuthHeaders(); const headers = this.getOAuthHeaders();
const responseBody = await this.post<OAuth2IntrospectionRequest, OAuth2IntrospectionResponse>(url, requestBody, headers); const responseBody = await this.http.post<OAuth2IntrospectionRequest, OAuth2IntrospectionResponse>(url, requestBody, headers);
if (!responseBody) { if (!responseBody) {
return null; return null;
@ -276,7 +276,7 @@ export class TribufuClient extends TribufuApi {
const url = `/v1/oauth2/revoke`; const url = `/v1/oauth2/revoke`;
const headers = this.getOAuthHeaders(); const headers = this.getOAuthHeaders();
const responseBody = await this.post<OAuth2IntrospectionRequest, OAuth2IntrospectionResponse>(url, requestBody, headers); const responseBody = await this.http.post<OAuth2IntrospectionRequest, OAuth2IntrospectionResponse>(url, requestBody, headers);
if (!responseBody) { if (!responseBody) {
return false; return false;
@ -324,7 +324,7 @@ export class TribufuClient extends TribufuApi {
const params = subjectKey && subjectValue ? `?${subjectKey}=${subjectValue}` : ""; const params = subjectKey && subjectValue ? `?${subjectKey}=${subjectValue}` : "";
const url = `/v1/oauth2/token${params}`; const url = `/v1/oauth2/token${params}`;
const headers = this.getOAuthHeaders(); const headers = this.getOAuthHeaders();
const responseBody = await this.post<OAuth2TokenRequest, OAuth2TokenResponse>(url, requestBody, headers); const responseBody = await this.http.post<OAuth2TokenRequest, OAuth2TokenResponse>(url, requestBody, headers);
if (!responseBody) { if (!responseBody) {
return null; return null;
@ -338,19 +338,17 @@ export class TribufuClient extends TribufuApi {
* @returns User | null * @returns User | null
*/ */
public async getUserInfo(): Promise<User | null> { public async getUserInfo(): Promise<User | null> {
if (!this.options.refreshToken) { if (!this.options.accessToken) {
return null; return null;
} }
const headers = this.getHeaders(); const headers = this.getHeaders();
const response = await this.http.get(`/v1/oauth2/userinfo`, { headers }); const responseBody = await this.http.get<User>(`/v1/oauth2/userinfo`, headers);
if (response.status !== 200) { if (!responseBody) {
return null; return null;
} }
const user = response.data as User; return responseBody;
return user;
} }
} }

View File

@ -1,17 +0,0 @@
// Copyright (c) Tribufu. All Rights Reserved.
export type HeaderMap = {
[key: string]: string
};
export type CookieMap = {
[key: string]: string;
};
export interface ErrorResponse {
error: string;
};
export interface MessageResponse {
message: string;
};

192
src/http/index.ts Normal file
View File

@ -0,0 +1,192 @@
// Copyright (c) Tribufu. All Rights Reserved.
import axios, { AxiosInstance } from "axios";
import camelcaseKeys from "camelcase-keys";
import snakecaseKeys from "snakecase-keys";
export type HeaderMap = {
[key: string]: string
};
export type CookieMap = {
[key: string]: string;
};
export interface ErrorResponse {
error: string;
};
export interface MessageResponse {
message: string;
};
export interface TribufuHttpOptions {
baseUrl?: string | null;
headers?: HeaderMap;
logEnabled?: boolean;
logTarget?: string;
};
/**
* Tribufu Http
*
* Helper class to make HTTP requests to the Tribufu API.
*/
export class TribufuHttp {
private readonly inner: AxiosInstance;
protected readonly options: TribufuHttpOptions;
constructor(options?: TribufuHttpOptions | null) {
const defaultOptions = TribufuHttp.defaultOptions();
this.options = {
baseUrl: options?.baseUrl || defaultOptions.baseUrl,
headers: options?.headers || defaultOptions.headers,
logEnabled: options?.logEnabled || defaultOptions.logEnabled,
logTarget: options?.logTarget || defaultOptions.logTarget,
};
const inner = axios.create({
baseURL: this.options?.baseUrl || undefined,
headers: this.options?.headers || undefined,
});
inner.interceptors.request.use((req) => {
if (this.options.logEnabled ?? false) {
console.log(`(${this.options.logTarget}) ${req.method?.toUpperCase()} ${req.baseURL}${req.url}`);
}
const contentType = req.headers["Content-Type"];
if (req.data && (contentType === "application/json" || contentType === "application/x-www-form-urlencoded")) {
req.data = snakecaseKeys(req.data);
}
return req;
});
inner.interceptors.response.use((res) => {
if (res.data) {
res.data = camelcaseKeys(res.data);
}
return res;
});
this.inner = inner;
}
private static defaultOptions(): TribufuHttpOptions {
return {
baseUrl: null,
headers: {},
logEnabled: false,
logTarget: "TribufuHttp",
};
};
/**
* Get a resource from the Tribufu API.
* @returns T | null
*/
public async get<T>(path: string, headers?: HeaderMap | null): Promise<T | null> {
try {
const requestHeaders = headers || this.options.headers;
const response = await this.inner.get(path, { headers: requestHeaders });
if (response.status !== 200) {
return null;
}
return response.data as T;
} catch (error) {
return null;
}
}
/**
* Create a resource to the Tribufu API.
* @param path
* @param body
* @param headers
* @returns T | null
*/
public async post<S, T>(path: string, body: S, headers?: HeaderMap | null): Promise<T | null> {
try {
const requestHeaders = headers || this.options.headers;
const response = await this.inner.post(path, body, { headers: requestHeaders });
if (response.status !== 200) {
return null;
}
return response.data as T;
} catch (error) {
return null;
}
}
/**
* Update a resource on the Tribufu API.
* @param path
* @param body
* @param headers
* @returns T | null
*/
public async put<S, T>(path: string, body: S, headers?: HeaderMap | null): Promise<T | null> {
try {
const requestHeaders = headers || this.options.headers;
const response = await this.inner.put(path, body, { headers: requestHeaders });
if (response.status !== 200) {
return null;
}
return response.data as T;
} catch (error) {
return null;
}
}
/**
* Patch a resource on the Tribufu API.
* @param path
* @param body
* @param headers
* @returns T | null
*/
public async patch<S, T>(path: string, body: S, headers?: HeaderMap | null): Promise<T | null> {
try {
const requestHeaders = headers || this.options.headers;
const response = await this.inner.patch(path, body, { headers: requestHeaders });
if (response.status !== 200) {
return null;
}
return response.data as T;
} catch (error) {
return null;
}
}
/**
* Delete a resource from the Tribufu API.
* @param path
* @param headers
* @returns T | null
*/
public async delete<T>(path: string, headers?: HeaderMap | null): Promise<T | null> {
try {
const requestHeaders = headers || this.options.headers;
const response = await this.inner.delete(path, { headers: requestHeaders });
if (response.status !== 200) {
return null;
}
return response.data as T;
} catch (error) {
return null;
}
}
}

11
src/socket/index.ts Normal file
View File

@ -0,0 +1,11 @@
// Copyright (c) Tribufu. All Rights Reserved.
/**
* Tribufu Socket
*
* Helper class to connect to the Tribufu Socket API.
*/
export class TribufuSocket {
constructor() {
}
}