UNPKG

@h3ravel/http

Version:

HTTP kernel, middleware pipeline, request/response classes for H3ravel.

361 lines (353 loc) 7.91 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // src/Middleware.ts var Middleware = class { static { __name(this, "Middleware"); } }; // src/Request.ts import { getQuery, getRouterParams, readBody } from "h3"; import { safeDot } from "@h3ravel/support"; var Request = class { static { __name(this, "Request"); } app; /** * Gets route parameters. * @returns An object containing route parameters. */ params; /** * Gets query parameters. * @returns An object containing query parameters. */ query; /** * Gets the request headers. * @returns An object containing request headers. */ headers; /** * The current H3 H3Event instance */ event; constructor(event, app) { this.app = app; this.event = event; this.query = getQuery(this.event); this.params = getRouterParams(this.event); this.headers = this.event.req.headers; } /** * Get all input data (query + body). */ async all() { let data = { ...getRouterParams(this.event), ...getQuery(this.event) }; if (this.event.req.method === "POST") { data = Object.assign({}, data, Object.fromEntries((await this.event.req.formData()).entries())); } else if (this.event.req.method === "PUT") { data = Object.fromEntries(Object.entries(await readBody(this.event))); } return data; } /** * Get a single input field from query or body. */ async input(key, defaultValue) { const data = await this.all(); return data[key] ?? defaultValue; } getEvent(key) { return safeDot(this.event, key); } }; // src/Response.ts import { safeDot as safeDot2 } from "@h3ravel/support"; import { html, redirect } from "h3"; var Response = class { static { __name(this, "Response"); } app; /** * The current H3 H3Event instance */ event; statusCode = 200; headers = {}; constructor(event, app) { this.app = app; this.event = event; } /** * Set HTTP status code. */ setStatusCode(code) { this.statusCode = code; this.event.res.status = code; return this; } /** * Set a header. */ setHeader(name, value) { this.headers[name] = value; return this; } html(content) { this.applyHeaders(); return html(this.event, content); } /** * Send a JSON response. */ json(data) { this.setHeader("content-type", "application/json; charset=utf-8"); this.applyHeaders(); return data; } /** * Send plain text. */ text(data) { this.setHeader("content-type", "text/plain; charset=utf-8"); this.applyHeaders(); return data; } /** * Redirect to another URL. */ redirect(url, status = 302) { this.setStatusCode(status); return redirect(this.event, url, this.statusCode); } /** * Apply headers before sending response. */ applyHeaders() { Object.entries(this.headers).forEach(([key, value]) => { this.event.res.headers.set(key, value); }); } getEvent(key) { return safeDot2(this.event, key); } }; // src/Contracts/HttpContract.ts import { HttpContext } from "@h3ravel/shared"; // src/Middleware/LogRequests.ts var LogRequests = class extends Middleware { static { __name(this, "LogRequests"); } async handle({ request }, next) { const url = request.getEvent("url"); console.log(`[${request.getEvent("method")}] ${url.pathname + url.search}`); return next(); } }; // src/Providers/HttpServiceProvider.ts import { H3, serve } from "h3"; import { ServiceProvider } from "@h3ravel/core"; var HttpServiceProvider = class extends ServiceProvider { static { __name(this, "HttpServiceProvider"); } static priority = 998; register() { this.app.singleton("http.app", () => { return new H3(); }); this.app.singleton("http.serve", () => serve); } }; // src/Resources/JsonResource.ts var JsonResource = class { static { __name(this, "JsonResource"); } event; /** * The request instance */ request; /** * The response instance */ response; /** * The data to send to the client */ resource; /** * The final response data object */ body = { data: {} }; /** * Flag to track if response should be sent automatically */ shouldSend = false; /** * Flag to track if response has been sent */ responseSent = false; /** * @param req The request instance * @param res The response instance * @param rsc The data to send to the client */ constructor(event, rsc) { this.event = event; this.request = event.req; this.response = event.res; this.resource = rsc; for (const key of Object.keys(rsc)) { if (!(key in this)) { Object.defineProperty(this, key, { enumerable: true, configurable: true, get: () => this.resource[key], set: (value) => { this.resource[key] = value; } }); } } } /** * Return the data in the expected format * * @returns */ data() { return this.resource; } /** * Build the response object * @returns this */ json() { this.shouldSend = true; this.response.status = 200; const resource = this.data(); let data = Array.isArray(resource) ? [ ...resource ] : { ...resource }; if (typeof data.data !== "undefined") { data = data.data; } if (!Array.isArray(resource)) { delete data.pagination; } this.body = { data }; if (!Array.isArray(resource) && resource.pagination) { const meta = this.body.meta ?? {}; meta.pagination = resource.pagination; this.body.meta = meta; } if (this.resource.pagination && !this.body.meta?.pagination) { const meta = this.body.meta ?? {}; meta.pagination = this.resource.pagination; this.body.meta = meta; } return this; } /** * Add context data to the response object * @param data Context data * @returns this */ additional(data) { this.shouldSend = true; delete data.data; delete data.pagination; this.body = { ...this.body, ...data }; return this; } /** * Send the output to the client * @returns this */ send() { this.shouldSend = false; if (!this.responseSent) { this.#send(); } return this; } /** * Set the status code for this response * @param code Status code * @returns this */ status(code) { this.response.status = code; return this; } /** * Private method to send the response */ #send() { if (!this.responseSent) { this.event.context.this.response.json(this.body); this.responseSent = true; } } /** * Check if send should be triggered automatically */ checkSend() { if (this.shouldSend && !this.responseSent) { this.#send(); } } }; // src/Resources/ApiResource.ts function ApiResource(instance) { return new Proxy(instance, { get(target, prop, receiver) { const value = Reflect.get(target, prop, receiver); if (typeof value === "function") { if (prop === "json" || prop === "additional") { return (...args) => { const result = value.apply(target, args); setImmediate(() => target["checkSend"]()); return result; }; } else if (prop === "send") { return (...args) => { target["shouldSend"] = false; return value.apply(target, args); }; } } return value; } }); } __name(ApiResource, "ApiResource"); export { ApiResource, HttpContext, HttpServiceProvider, JsonResource, LogRequests, Middleware, Request, Response }; //# sourceMappingURL=index.js.map