diff --git a/README.md b/README.md index 1e1f435..9cbb311 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Zur Verfügung gestellt werden Requests mit den benötigten Models, Types und En Der WebApiClient realisiert den automatischen refresh von Zugangs-Tokens. -Beispiele:\ +Beispiele: 1. Verwendung des Clients: ``` ts import { WebApiClient, AdminRequests } from "@ff-admin/webapi-client" @@ -15,7 +15,10 @@ let myClient = new WebApiClient({ serverAdress: "", webapiToken: "" }); - +myClient.initialize() // asynchrone Funktion - muss vollständig ausgeführt sein, bevor irgendwelche Anfragen gestellt werden +``` +2. Nutzung der Requests +```ts let data = AdminRequests.MemberRequests.getAllMembers(myClient) .then((res) => { console.log(res) @@ -49,12 +52,24 @@ AdminRequests.MemberRequests.updateMember(myClient, { .then(() => {}) .catch(() => {}); ``` - -2. Zugriff auf Typen, Models und Enums: +3. Zugriff auf Typen, Models und Enums: ``` ts import { AdminModels, AdminTypes, AdminEnums } from "@ff-admin/webapi-client" let model: AdminModels.MemberModels.CreateMemberViewModel; let type: AdminTypes.DynamicQueries.DynamicQueryStructure let enum = AdminEnums.NewsletterType.NewsletterConfigType.mail +``` +4. http Events: +Es können Events wie Fehler oder Informationen direkt aus der Middleware des Clients angezapft werden. +``` ts +import { WebApiClient, AdminRequests } from "@ff-admin/webapi-client" + +let myClient = new WebApiClient({ + serverAdress: "", + webapiToken: "" +}); +myClient.initialize() + +client.httpEvents.on(<"error" | "info">, (data) => {}) ``` \ No newline at end of file diff --git a/src/clients/clientBase.ts b/src/clients/clientBase.ts index 10f313a..14934d2 100644 --- a/src/clients/clientBase.ts +++ b/src/clients/clientBase.ts @@ -12,6 +12,12 @@ export class BaseClient extends Config { return this.httpInstance.http; } + get httpEvents() { + return this.httpInstance.httpEvents; + } + + public async initialize(): Promise {} + public refreshToken(): Promise { return new Promise(async (resolve, reject) => { reject("api token refresh not implemented"); diff --git a/src/clients/webapi.client.ts b/src/clients/webapi.client.ts index 0bbcc8b..6bb0190 100644 --- a/src/clients/webapi.client.ts +++ b/src/clients/webapi.client.ts @@ -5,8 +5,8 @@ export class WebApiClient extends BaseClient { super({ serverAdress, webapiToken }); } - get http() { - return this.httpInstance.http; + public async initialize(): Promise { + await this.refreshToken(); } public refreshToken(): Promise { diff --git a/src/http.ts b/src/http.ts index 2ff9764..2b19b3e 100644 --- a/src/http.ts +++ b/src/http.ts @@ -1,9 +1,16 @@ import axios, { AxiosInstance } from "axios"; import { BaseClient } from "./clients/clientBase"; +import { EventEmitterReadonly, TypedEventEmitter } from "./utils/typedEmitter"; + +type HttpEvents = { + info: [arg1: string]; + error: [arg1: { code: string; message: string }]; +}; export default class HTTP { - public http: AxiosInstance; - private client: BaseClient; + public readonly http: AxiosInstance; + protected readonly httpEmitter: TypedEventEmitter; + protected client: BaseClient; constructor(client: BaseClient) { this.client = client; @@ -15,15 +22,20 @@ export default class HTTP { Expires: "0", }, }); + this.httpEmitter = new TypedEventEmitter(); this.setRequestInterceptor(); this.setResponseInterceptor(); } + get httpEvents(): EventEmitterReadonly { + return this.httpEmitter; + } + private setRequestInterceptor() { this.http.interceptors.request.use( (config) => { - if (config.headers && config.headers.Authorization == "") { + if (config.headers && !config.headers.Authorization) { config.headers.Authorization = `Bearer ${this.client.accessToken}`; } @@ -53,11 +65,16 @@ export default class HTTP { return await this.client .refreshToken() .then(() => { + this.httpEmitter.emit("info", "successfully refreshed token"); return this.http(originalRequest); }) .catch(() => {}); } + this.httpEmitter.emit("error", { + code: error.code, + message: error.message, + }); return Promise.reject(error); } ); diff --git a/src/utils/typedEmitter.ts b/src/utils/typedEmitter.ts new file mode 100644 index 0000000..6fee8df --- /dev/null +++ b/src/utils/typedEmitter.ts @@ -0,0 +1,26 @@ +import EventEmitter = require("node:events"); + +export interface EventEmitterReadonly> { + on(eventName: TEventName, handler: (...eventArg: TEvents[TEventName]) => void): void; + off(eventName: TEventName, handler: (...eventArg: TEvents[TEventName]) => void): void; +} + +export interface EventEmitterFull> extends EventEmitterReadonly { + emit(eventName: TEventName, ...eventArg: TEvents[TEventName]): void; +} + +export class TypedEventEmitter> implements EventEmitterFull { + private emitter = new EventEmitter(); + + emit(eventName: TEventName, ...eventArg: TEvents[TEventName]) { + this.emitter.emit(eventName, ...(eventArg as [])); + } + + on(eventName: TEventName, handler: (...eventArg: TEvents[TEventName]) => void) { + this.emitter.on(eventName, handler as any); + } + + off(eventName: TEventName, handler: (...eventArg: TEvents[TEventName]) => void) { + this.emitter.off(eventName, handler as any); + } +}