Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@e22m4u/js-trie-router

Package Overview
Dependencies
Maintainers
0
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@e22m4u/js-trie-router - npm Package Compare versions

Comparing version 0.0.1 to 0.0.2

src/utils/get-request-pathname.d.ts

2

package.json
{
"name": "@e22m4u/js-trie-router",
"version": "0.0.1",
"version": "0.0.2",
"description": "Trie-based router for Node.js",

@@ -5,0 +5,0 @@ "type": "module",

@@ -9,3 +9,3 @@ ## @e22m4u/js-trie-router

- Parses JSON-body automatically.
- Parses a query string and the Cookie header.
- Parses a query string and a `cookie` header.
- Supports `preHandler` and `postHandler` hooks.

@@ -20,2 +20,5 @@ - Asynchronous request handler.

To load an ES-module set `"type": "module"` in the `package.json`
or use the `.mjs` extension.
## Overview

@@ -49,22 +52,33 @@

The first parameter of the `Router` handler is the `RequestContext` instance.
The first parameter of a route handler is a `RequestContext` instance.
- `container: ServiceContainer`
- `req: IncomingMessage`
- `res: ServerResponse`
- `query: ParsedQuery`
- `headers: ParsedHeaders`
- `cookie: ParsedCookie`
- `container: ServiceContainer` is an instance of the [ServiceContainer](https://npmjs.com/package/@e22m4u/js-service)
- `req: IncomingMessage` is a native request from the `http` module
- `res: ServerResponse` is a native response from the `http` module
- `params: ParsedParams` is a key-value object of path parameters
- `query: ParsedQuery` is a key-value object of a parsed query string
- `headers: ParsedHeaders` is a key-value object of request headers
- `cookie: ParsedCookie` is a key-value object of a parsed `cookie` header
- `method: string` is a request method in lower case like `get`, `post` etc.
- `path: string` is a request pathname with a query string
- `pathname: string` is a request pathname without a query string
The `RequestContext` can be destructured.
Here are possible values of RequestContext properties.
```js
router.defineRoute({
// ...
handler({req, res, query, headers, cookie}) {
console.log(req); // IncomingMessage
console.log(res); // ServerResponse
console.log(query); // {id: '10', ...}
console.log(headers); // {'cookie': 'foo=bar', ...}
console.log(cookie); // {foo: 'bar', ...}
method: 'get',
path: '/users/:id',
handler(ctx) {
// GET /users/10?include=city
// Cookie: foo=bar; baz=qux;
console.log(ctx.req); // IncomingMessage
console.log(ctx.res); // ServerResponse
console.log(ctx.params); // {id: 10}
console.log(ctx.query); // {include: 'city'}
console.log(ctx.headers); // {cookie: 'foo=bar; baz=qux;'}
console.log(ctx.cookie); // {foo: 'bar', baz: 'qux'}
console.log(ctx.method); // "get"
console.log(ctx.path); // "/users/10?include=city"
console.log(ctx.pathname); // "/users/10"
// ...

@@ -77,6 +91,6 @@ },

Return values of the `Route` handler will be sent as described below.
Return values of a route handler will be sent as described below.
| type | content-type |
|---------|--------------------------|
| value | content-type |
|-----------|--------------------------|
| `string` | text/plain |

@@ -101,4 +115,4 @@ | `number` | application/json |

If the `ServerResponse` has been sent manually, then the return
value will be ignored.
If the `ServerResponse` has been sent manually, then a return
value of the route handler will be ignored.

@@ -116,2 +130,65 @@ ```js

### Route hooks
A route definition allows you to set following hooks:
- `preHandler` is executed before a route handler.
- `postHandler` is executed after a route handler.
If the `preHandler` hook returns a value other than `undefined`
or `null`, it will be used as the server response.
```js
router.defineRoute({
// ...
preHandler(ctx) {
return 'Are you authenticated?';
},
handler(ctx) {
// the request handler will be skipped because
// the "preHandler" hook returns a non-empty value
return 'Hello world!';
},
});
```
A return value of the route handler will be passed as the second
argument to the `preHandler` hook.
```js
router.defineRoute({
// ...
handler(ctx) {
return 'Hello world!';
},
preHandler(ctx, data) {
// after the route handler
return data.toUpperCase(); // HELLO WORLD!
},
});
```
### Global hooks
A `Router` instance allows you to set following global hooks:
- `preHandler` is executed before each route handler.
- `postHandler` is executed after each route handler.
The `addHook` method of a `Router` instance accepts a hook name as the first
parameter and the hook function as the second.
```js
router.addHook('preHandler', (ctx) => {
// executes before each route handler
});
router.addHook('postHandler', (ctx, data) => {
// executes after each route handler
});
```
Similar to a route hook, if a global hook returns a value other than
`undefined` or `null`, that value will be used as the server response.
## Debug

@@ -131,4 +208,11 @@

## Contribution
- Bug fixes.
- Grammar correction.
- Documentation improvements.
- Vulnerability fixes.
## License
MIT
import {Service} from '../service.js';
import {parseCookie} from '../utils/index.js';
import {getRequestPath} from '../utils/index.js';
import {getRequestPathname} from '../utils/index.js';

@@ -27,3 +27,3 @@ /**

req.method,
getRequestPath(req),
getRequestPathname(req),
);

@@ -30,0 +30,0 @@ }

import querystring from 'querystring';
import {Service} from '../service.js';
import {getRequestPath} from '../utils/index.js';
import {getRequestPathname} from '../utils/index.js';

@@ -27,3 +27,3 @@ /**

req.method,
getRequestPath(req),
getRequestPathname(req),
);

@@ -30,0 +30,0 @@ }

@@ -43,2 +43,17 @@ import {ServerResponse} from 'http';

/**
* Method.
*/
get method(): string;
/**
* Path.
*/
get path(): string;
/**
* Pathname.
*/
get pathname(): string;
/**
* Constructor.

@@ -45,0 +60,0 @@ *

@@ -5,2 +5,3 @@ import {Errorf} from '@e22m4u/js-format';

import {ServiceContainer} from '@e22m4u/js-service';
import {getRequestPathname} from './utils/index.js';

@@ -68,2 +69,39 @@ /**

/**
* Method.
*
* @returns {string}
*/
get method() {
return this.req.method.toLowerCase();
}
/**
* Path.
*
* @returns {string}
*/
get path() {
return this.req.url;
}
/**
* Pathname.
*
* @type {string|undefined}
* @private
*/
_pathname = undefined;
/**
* Pathname.
*
* @returns {string}
*/
get pathname() {
if (this._pathname != null) return this._pathname;
this._pathname = getRequestPathname(this.req);
return this._pathname;
}
/**
* Constructor.

@@ -70,0 +108,0 @@ *

@@ -89,2 +89,46 @@ import {expect} from './chai.js';

});
describe('method', function () {
it('returns the method name in lower case', function () {
const req = createRequestMock({method: 'POST'});
const res = createResponseMock();
const cnt = new ServiceContainer();
const ctx = new RequestContext(cnt, req, res);
expect(ctx.method).to.be.eq('post');
});
});
describe('path', function () {
it('returns the request pathname with the query string', function () {
const req = createRequestMock({path: '/pathname?foo=bar'});
const res = createResponseMock();
const cnt = new ServiceContainer();
const ctx = new RequestContext(cnt, req, res);
expect(req.url).to.be.eq('/pathname?foo=bar');
expect(ctx.path).to.be.eq('/pathname?foo=bar');
});
});
describe('pathname', function () {
it('returns the request pathname without the query string', function () {
const req = createRequestMock({path: '/pathname?foo=bar'});
const res = createResponseMock();
const cnt = new ServiceContainer();
const ctx = new RequestContext(cnt, req, res);
expect(req.url).to.be.eq('/pathname?foo=bar');
expect(ctx.pathname).to.be.eq('/pathname');
});
it('sets the cache to the "_pathname" property and uses is for next accesses', function () {
const req = createRequestMock({path: '/pathname'});
const res = createResponseMock();
const cnt = new ServiceContainer();
const ctx = new RequestContext(cnt, req, res);
expect(ctx._pathname).to.be.undefined;
expect(ctx.pathname).to.be.eq('/pathname');
expect(ctx._pathname).to.be.eq('/pathname');
ctx._pathname = '/overridden';
expect(ctx.pathname).to.be.eq('/overridden');
});
});
});

@@ -5,3 +5,3 @@ import {Errorf} from '@e22m4u/js-format';

import {createDebugger} from './utils/index.js';
import {getRequestPath} from './utils/index.js';
import {getRequestPathname} from './utils/index.js';

@@ -177,3 +177,3 @@ /**

handle(context) {
const requestPath = getRequestPath(context.req);
const requestPath = getRequestPathname(context.req);
debug(

@@ -180,0 +180,0 @@ 'Invoking the Route handler for the request %s %v.',

import {inspect} from 'util';
import {Service} from '../service.js';
import getStatusMessage from 'statuses';
import {getRequestPath} from '../utils/index.js';
import {getRequestPathname} from '../utils/index.js';

@@ -64,3 +64,3 @@ /**

req.method,
getRequestPath(req),
getRequestPathname(req),
);

@@ -83,5 +83,5 @@ }

req.method,
getRequestPath(req),
getRequestPathname(req),
);
}
}

@@ -38,3 +38,3 @@ import {Service} from './service.js';

* handler(ctx) { ... }, // Request handler function.
* postHandler(ctx, data) { ... }, // The "postHandler" is executed after a route handler
* postHandler(ctx, data) { ... }, // The "postHandler" is executed after a route handler.
* });

@@ -41,0 +41,0 @@ * ```

@@ -13,3 +13,2 @@ import {Readable} from 'stream';

query?: object;
hash?: string;
cookie?: object;

@@ -16,0 +15,0 @@ headers?: object;

@@ -17,3 +17,2 @@ import {Socket} from 'net';

* query?: object;
* hash?: string;
* cookie?: object;

@@ -78,8 +77,2 @@ * headers?: object;

}
if (patch.hash != null && typeof patch.hash !== 'string')
throw new Errorf(
'The parameter "hash" of "createRequestMock" ' +
'should be a String, but %v given.',
patch.hash,
);
if (

@@ -148,3 +141,3 @@ (patch.cookie != null &&

createRequestStream(patch.secure, patch.body, patch.encoding);
req.url = createRequestUrl(patch.path || '/', patch.query, patch.hash);
req.url = createRequestUrl(patch.path || '/', patch.query);
req.headers = createRequestHeaders(

@@ -205,6 +198,5 @@ patch.host,

* @param {string|object|null|undefined} query
* @param {string|null|undefined} hash
* @returns {string}
*/
function createRequestUrl(path, query, hash) {
function createRequestUrl(path, query) {
if (typeof path !== 'string')

@@ -226,8 +218,2 @@ throw new Errorf(

}
if (hash != null && typeof hash !== 'string')
throw new Errorf(
'The parameter "hash" of "createRequestUrl" ' +
'should be a String, but %v given.',
path,
);
let url = ('/' + path).replace('//', '/');

@@ -240,4 +226,2 @@ if (typeof query === 'object') {

}
hash = (hash || '').replace('#', '');
if (hash) url += `#${hash}`;
return url;

@@ -244,0 +228,0 @@ }

@@ -131,22 +131,2 @@ import {Socket} from 'net';

it('requires the parameter "hash" to be a String', function () {
const throwable = v => () => createRequestMock({hash: v});
const error = v =>
format(
'The parameter "hash" of "createRequestMock" ' +
'should be a String, but %s given.',
v,
);
expect(throwable(10)).to.throw(error('10'));
expect(throwable(0)).to.throw(error('0'));
expect(throwable(true)).to.throw(error('true'));
expect(throwable(false)).to.throw(error('false'));
expect(throwable([])).to.throw(error('Array'));
expect(throwable({})).to.throw(error('Object'));
throwable('str')();
throwable('')();
throwable(undefined)();
throwable(null)();
});
it('requires the parameter "cookie" to be a String or Object', function () {

@@ -293,3 +273,3 @@ const throwable = v => () => createRequestMock({cookie: v});

it('uses the default path "/" without query and hash', function () {
it('uses the default path "/" without a query string', function () {
const req = createRequestMock();

@@ -382,17 +362,6 @@ expect(req.url).to.be.eq('/');

it('sets the hash value to the request url', async function () {
const req = createRequestMock({hash: 'myHash'});
expect(req.url).to.be.eq('/#myHash');
});
it('sets the hash value to the request url with the prefix "#"', async function () {
const req = createRequestMock({hash: '#myHash'});
expect(req.url).to.be.eq('/#myHash');
});
it('set parameters "path", "query" and "hash" to the request url', function () {
it('set parameters "path" and "query" to the request url', function () {
const req1 = createRequestMock({
path: 'test',
query: 'p1=foo&p2=bar',
hash: 'myHash1',
});

@@ -402,6 +371,5 @@ const req2 = createRequestMock({

query: {p1: 'baz', p2: 'qux'},
hash: '#myHash2',
});
expect(req1.url).to.be.eq('/test?p1=foo&p2=bar#myHash1');
expect(req2.url).to.be.eq('/test?p1=baz&p2=qux#myHash2');
expect(req1.url).to.be.eq('/test?p1=foo&p2=bar');
expect(req2.url).to.be.eq('/test?p1=baz&p2=qux');
});

@@ -408,0 +376,0 @@

@@ -7,3 +7,2 @@ export * from './is-promise.js';

export * from './is-response-sent.js';
export * from './get-request-path.js';
export * from './is-readable-stream.js';

@@ -13,1 +12,2 @@ export * from './is-writable-stream.js';

export * from './create-cookie-string.js';
export * from './get-request-pathname.js';

@@ -7,3 +7,2 @@ export * from './is-promise.js';

export * from './is-response-sent.js';
export * from './get-request-path.js';
export * from './is-readable-stream.js';

@@ -13,1 +12,2 @@ export * from './is-writable-stream.js';

export * from './create-cookie-string.js';
export * from './get-request-pathname.js';
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc