import { HTTPRequest } from "./http-request"; import { StatusCode } from "./types"; export class HTTPResponse { status: StatusCode; statusText: string; data: T; headers: Record; request: HTTPRequest; constructor() { this.headers = {}; } static fromRaw(response: HTTPResponse) { const newResponse = new HTTPResponse(); Object.assign(newResponse, response); return response; } /** * Decomposes a response, creating an exact copy of the current response, * but with a new data value. The data can be provided directly as is, or it * can be generated through a callback function which receives the current * response data as an argument. * * ```ts * const response = await http.get("/products"); * * // direct value * const products = response.data; * const firstProduct = response.decompose(products[0]); * // callback transformer * const secondProduct = response.decompose((products) => products[1]); * // callback transformer with destructuring * const secondProduct = response.decompose(([product]) => product); * ``` * @param value */ decompose(value: K): HTTPResponse; decompose(transformFn: (response: T) => K): HTTPResponse; decompose(transformFnOrVal: K | ((response: T) => K)): HTTPResponse { const value = getDecompositionValue(this.data, transformFnOrVal); return new HTTPResponseBuilder() .status(this.status) .statusText(this.statusText) .headers(this.headers) .request(this.request) .data(value) .build() as HTTPResponse; } } function getDecompositionValue(data: unknown, transformFn: unknown): T { return typeof transformFn === "function" ? transformFn(data) : transformFn; } export class HTTPResponseBuilder { #response = new HTTPResponse(); static create() { return new HTTPResponseBuilder(); } derive() { return HTTPResponseBuilder.create() .data(this.#response.data) .headers(this.#response.headers) .request(this.#response.request) .status(this.#response.status) .statusText(this.#response.statusText); } status(code: StatusCode) { this.#response.status = code; return this; } statusText(text: string) { this.#response.statusText = text; return this; } data(data: T) { this.#response.data = data; return this; } headers(dict: Record) { this.#response.headers = dict; return this; } header(name: string, value: string) { this.#response.headers[name] = value; return this; } request(request: HTTPRequest) { this.#response.request = request; return this; } build() { return this.#response; } }