@curveball/kernel
Version:
Curveball is a framework writting in Typescript for Node.js
151 lines • 4.52 kB
JavaScript
import Accepts from 'accepts';
import * as url from 'node:url';
import { is, parsePrefer } from './header-helpers.js';
import { Headers } from './headers.js';
/**
* This interface represents an incoming server request.
*/
export class Request {
constructor(method, requestTarget, origin) {
this.method = method;
this.requestTarget = requestTarget;
this.headers = new Headers();
this.origin = origin;
}
/**
* List of HTTP Headers
*/
headers;
/**
* path-part of the request.
*
* For example /hello/world
*/
get path() {
return url.parse(this.requestTarget).pathname;
}
/**
* Sets the request path
*/
set path(value) {
this.requestTarget = value;
}
/**
* HTTP method
*
* For example: GET
*/
method;
/**
* The request target.
*
* This contains the literal value after the HTTP method in the request.
* So for:
*
* GET /foo HTTP/1.1
*
* This would contain '/foo'. In many cases this is the same as the 'path'
* property, but there's 3 other forms in the HTTP specificatio. Here's the
* different formats:
*
* * origin-form - This is the most common. Example: /foo.
* * absolute-form - Clients might sent an entire path. Also used by proxies.
* Example: https://example.org/foo
* * authority-form - Used by the CONNECT method. Example: example.org:1212
* * asterisk-form - Used by the OPTIONS method. Example: *
*
* In most cases users will want to use the 'path' property instead. only use
* this if you know what you're doing.
*
* @see {@link https://tools.ietf.org/html/rfc7230#section-5.3}
*/
requestTarget;
/**
* Contains a parsed, stored representation of the body. It's up to
* middlewares to do the actual parsing.
*/
body;
/**
* This object contains parsed query parameters.
*/
get query() {
return url.parse(this.requestTarget, true).query;
}
/**
* Returns the value of the Content-Type header, with any additional
* parameters such as charset= removed.
*
* If there was no Content-Type header, an empty string will be returned.
*/
get type() {
const type = this.headers.get('content-type');
if (!type) {
return '';
}
return type.split(';')[0];
}
/**
* accepts is used for negotation the Content-Type with a client.
*
* You can pass a content-type, or an array of content-types.
* The Content-Types you provide are a list of types your application
* supports.
*
* This function will then return the best possible type based on the Accept
* header.
*
* If no compatible types are found, this function returns null.
*/
accepts(...types) {
const mockRequestObj = {
headers: {
accept: this.headers.get('Accept')
}
};
// @ts-expect-error The types for the Accept package are probably not 100% correct for ESM.
const result = new Accepts(mockRequestObj).type(types);
return result === false ? null : result;
}
/**
* This method will return true or false if a Request or Response has a
* Content-Type header that matches the argument.
*
* For example, if the Content-Type header has the value: application/hal+json,
* then the arguments will all return true:
*
* * application/hal+json
* * application/json
* * hal+json
* * json
* * application/*
*/
is(type) {
return is(this, type);
}
prefer(preference) {
const prefer = parsePrefer(this.headers.get('Prefer'));
const val = prefer[preference];
if (val === undefined) {
return false;
}
return val;
}
/**
* Returns the absolute url for this request.
*
* This may not always be correct, because it's based on a best guess.
* If you have a reverse proxy in front of your curveball server, you may
* need to provide a 'origin' argument when constructing the server.
*/
get absoluteUrl() {
return this.origin + this.requestTarget;
}
/**
* Public base URL
*
* This will be used to determine the absoluteUrl
*/
origin;
}
export default Request;
//# sourceMappingURL=request.js.map