Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Roads is a simple web framework. It's similar to Express.js, but has some very i
- [Parsing request bodies](#parsing-request-bodies)
- [Parse Body Context](#parse-body-context)
- [Remove trailing slash](#remove-trailing-slash)
- [Basic router](#basic-router)
- [Router](#router)
- [applyMiddleware(road: *Road*)](#applymiddlewareroad-road)
- [addRoute(method: *string*, path: *string*, fn: *function*)](#addroutemethod-string-path-string-fn-function)
- [addRouteFile(filePath: *string*, prefix?: *string*)](#addroutefilefilepath-string-prefix-string)
Expand Down Expand Up @@ -547,8 +547,8 @@ var road = new Road();
road.use(RemoveTrailingSlashMiddleware.middleware);
```

## Basic router
This is a basic router middleware for roads. It allows you to easily attach functionality to HTTP methods and paths.
## Router
This is a Router middleware for roads. It allows you to easily attach functionality to HTTP methods and paths.

Here's how you use it.

Expand Down
3 changes: 2 additions & 1 deletion example/ts/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
public/*
public/*
types/*
4 changes: 2 additions & 2 deletions example/ts/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* This file is an example of using roads router in the client
*/

import { Road, RoadsPJAX, ParseBodyMiddleware, BasicRouterMiddleware, CookieMiddleware, Request } from 'roads';
import { Road, RoadsPJAX, ParseBodyMiddleware, RouterMiddleware, CookieMiddleware, Request } from 'roads';
import applyPublicRotues from './routes/applyPublicRoutes';
import emptyTo404 from './middleware/emptyTo404';

Expand All @@ -25,7 +25,7 @@ road.use(ParseBodyMiddleware.middleware);
road.use(CookieMiddleware.buildClientMiddleware(document));
pjax.register();
pjax.registerAdditionalElement(document.getElementById('home') as HTMLAnchorElement);
const router = new BasicRouterMiddleware.BasicRouter(road);
const router = new RouterMiddleware.Router(road);
applyPublicRotues(router);

const testRequest = new Request(false, 'localhost', 8081);
Expand Down
10 changes: 5 additions & 5 deletions example/ts/src/routes/applyPrivateRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import * as fs from 'fs';
import { CookieContext } from 'roads/types/middleware/cookieMiddleware';
import { StoreValsContext } from 'roads/types/middleware/storeVals';
import { BasicRouterMiddleware, Response } from 'roads';
import { RouterMiddleware, Response } from 'roads';
const TITLE_KEY = 'page-title';

/**
Expand All @@ -19,8 +19,8 @@ const TITLE_KEY = 'page-title';
*
* @param {SimpleRouter} router - The router that the routes will be added to
*/
export default function applyPrivateRotues(router: BasicRouterMiddleware.BasicRouter): void {
router.addRoute('GET', '/private', async function (this: CookieContext & StoreValsContext) {
export default function applyPrivateRotues(router: RouterMiddleware.Router<StoreValsContext>): void {
router.addRoute<CookieContext>('GET', '/private', async function () {
this.storeVal(TITLE_KEY, 'Private Resource');
this.setCookie('private_cookie', 'foo', {
httpOnly: true
Expand All @@ -36,13 +36,13 @@ export default function applyPrivateRotues(router: BasicRouterMiddleware.BasicRo
<a href="/" data-roads="link">home</a>!<br />`);
});

router.addRoute('GET', '/privateJSON', async function (this: StoreValsContext, ) {
router.addRoute('GET', '/privateJSON', async function () {
this.storeVal('ignoreLayout', true);
return new Response(JSON.stringify({'private-success': true}));
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars
router.addRoute('GET', 'client.js', async function (this: StoreValsContext, url, body, headers) {
router.addRoute('GET', 'client.js', async function (url, body, headers) {
this.storeVal('ignoreLayout', true);
// In the real world the body of the response should be created from a template engine.
return new Response(fs.readFileSync(`${__dirname }/../../../public/client.js`).toString('utf-8'), 200, {
Expand Down
10 changes: 5 additions & 5 deletions example/ts/src/routes/applyPublicRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* This file is an example of how to assign some public routes to a roads server
*/

import { Response, BasicRouterMiddleware } from 'roads';
import { Response, RouterMiddleware } from 'roads';
const TITLE_KEY = 'page-title';

import { ParseBodyContext } from 'roads/types/middleware/parseBody';
Expand All @@ -24,8 +24,8 @@ interface ExampleRequestBody {
*
* @param {SimpleRouter} router - The router that the routes will be added to
*/
export default function applyPublicRotues(router: BasicRouterMiddleware.BasicRouter): void {
router.addRoute('GET', '/', async function (this: StoreValsContext) {
export default function applyPublicRotues(router: RouterMiddleware.Router<StoreValsContext>): void {
router.addRoute('GET', '/', async function () {
this.storeVal(TITLE_KEY, 'Root Resource');

// In the real world the body of the response should be created from a template engine.
Expand All @@ -39,7 +39,7 @@ export default function applyPublicRotues(router: BasicRouterMiddleware.BasicRou
});
});

router.addRoute('GET', '/public', async function (this: StoreValsContext & CookieContext) {
router.addRoute<CookieContext>('GET', '/public', async function () {
this.storeVal(TITLE_KEY, 'Public Resource');
console.log('Here are all cookies accessible to this code: ', this.getCookies());
console.log('Cookies are not set until you access the private route.');
Expand All @@ -59,7 +59,7 @@ export default function applyPublicRotues(router: BasicRouterMiddleware.BasicRou
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars
router.addRoute('POST', '/postdata', async function (this: ParseBodyContext<ExampleRequestBody>, url, body, headers) {
router.addRoute<ParseBodyContext<ExampleRequestBody>>('POST', '/postdata', async function (url, body, headers) {
console.log(`You sent the message:${this.body?.message}`);
this.ignore_layout = true;
return new Response('', 302, { location: '/public' });
Expand Down
4 changes: 2 additions & 2 deletions example/ts/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { Road, Response, RemoveTrailingSlashMiddleware, CookieMiddleware,
StoreValsMiddleware, ParseBodyMiddleware, BasicRouterMiddleware } from 'roads';
StoreValsMiddleware, ParseBodyMiddleware, RouterMiddleware } from 'roads';

import { Server } from 'roads-server';
import addLayout from './middleware/addLayout';
Expand All @@ -28,7 +28,7 @@ road.use(StoreValsMiddleware.middleware);
road.use(addLayout);
road.use(ParseBodyMiddleware.middleware);

const router = new BasicRouterMiddleware.BasicRouter(road);
const router = new RouterMiddleware.Router(road);
applyPublicRotues(router);
applyPrivateRoutes(router);
road.use(emptyTo404);
Expand Down
8 changes: 0 additions & 8 deletions example/ts/types/build.d.ts

This file was deleted.

9 changes: 0 additions & 9 deletions example/ts/types/buildClient.d.ts

This file was deleted.

8 changes: 0 additions & 8 deletions example/ts/types/client.d.ts

This file was deleted.

22 changes: 0 additions & 22 deletions example/ts/types/middleware/addLayout.d.ts

This file was deleted.

19 changes: 0 additions & 19 deletions example/ts/types/middleware/emptyTo404.d.ts

This file was deleted.

16 changes: 0 additions & 16 deletions example/ts/types/routes/applyPrivateRoutes.d.ts

This file was deleted.

16 changes: 0 additions & 16 deletions example/ts/types/routes/applyPublicRoutes.d.ts

This file was deleted.

8 changes: 0 additions & 8 deletions example/ts/types/server.d.ts

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "roads",
"version": "8.0.0-alpha.1",
"version": "8.0.0-alpha.2",
"author": {
"name": "Aaron Hedges",
"email": "aaron@dashron.com",
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ export * as ParseBodyMiddleware from './middleware/parseBody';
export * as RerouteMiddleware from './middleware/reroute';
export * as StoreValsMiddleware from './middleware/storeVals';
export * as ModifiedSinceMiddleware from './middleware/modifiedSince';
export * as BasicRouterMiddleware from './middleware/basicRouter';
export * as RouterMiddleware from './middleware/router';
42 changes: 22 additions & 20 deletions src/middleware/basicRouter.ts → src/middleware/router.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/**
* basicRouter.ts
* router.ts
* Copyright(c) 2021 Aaron Hedges <aaron@dashron.com>
* MIT Licensed
*
* This is a basic router middleware for roads.
* This is a router middleware for roads.
* It allows you to easily attach functionality to HTTP methods and paths.
*/

Expand All @@ -15,7 +15,7 @@ import { NextCallback, RequestChain } from '../core/requestChain';


export interface Route<ContextType extends Context> {
(this: ContextType, method: string, path: BasicRouterURL, body: string,
(this: ContextType, method: string, path: RouterURL, body: string,
headers: IncomingHeaders, next: NextCallback): Promise<Response>
}

Expand All @@ -25,14 +25,14 @@ interface RouteDetails {
method: string
}

export interface BasicRouterURL extends ReturnType<typeof parse> {
export interface RouterURL extends ReturnType<typeof parse> {
args?: Record<string, string | number>
}
/**
* This is a basic router middleware for roads.
* You can assign functions to url paths, and those paths can have some very basic variable templating
* This is a router middleware for roads.
* You can assign functions to url paths, and those paths can have variable templating
*
* Templating is basic. Each URI is considered to be a series of "path parts" separated by slashes.
* There are only a couple of template options. Each URI is considered to be a series of "path parts" separated by slashes.
* If a path part starts with a #, it is assumed to be a numeric variable. Non-numbers will not match this route
* If a path part starts with a $, it is considered to be an alphanumeric variabe.
* All non-slash values will match this route.
Expand All @@ -43,13 +43,13 @@ export interface BasicRouterURL extends ReturnType<typeof parse> {
* /users/#user_id will match /users/12345, not /users/abcde. If a request is made to /users/12345
* the route's requestUrl object will contain { args: {user_id: 12345}} along with all other url object values
*
* @name BasicRouter
* @name Router
*/
export class BasicRouter {
export class Router<RouterContextType extends Context> {
protected _routes: RouteDetails[];

/**
* @param {Road} [road] - The road that will receive the BasicRouter middleware
* @param {Road} [road] - The road that will receive the Router middleware
*/
constructor (road?: Road) {
this._routes = [];
Expand All @@ -63,15 +63,15 @@ export class BasicRouter {
* If you don't provide a road to the SimpleRouter constructor, your routes will not be executed.
* If you have reason not to assign the road off the bat, you can assign it later with this function.
*
* @param {Road} road - The road that will receive the BasicRouter middleware
* @param {Road} road - The road that will receive the Router middleware
*/
applyMiddleware (road: Road): void {
// We need to alias because "this" for the middleware function must
// be the this applied by road.use, not the BasicRouter
// be the this applied by road.use, not the Router
// eslint-disable-next-line @typescript-eslint/no-this-alias
const _self = this;

// We do this to ensure we have access to the BasicRouter once we lose this due to road's context
// We do this to ensure we have access to the Router once we lose this due to road's context
road.use((function (request_method, request_url, request_body, request_headers, next) {
return _self._middleware.call(this, _self._routes, request_method, request_url,
request_body, request_headers, next);
Expand All @@ -82,7 +82,7 @@ export class BasicRouter {
* This is where you want to write the majority of your webservice. The `fn` parameter should contain
* the actions you want to perform when a certain `path` and HTTP `method` are accessed via the `road` object.
*
* The path supports a very basic templating system. The values inbetween each slash can be interpreted
* The path supports a templating system. The values inbetween each slash can be interpreted
* in one of three ways
* - If a path part starts with a #, it is assumed to be a numeric variable. Non-numbers will not match this route
* - If a path part starts with a $, it is considered to be an alphanumeric variabe. All non-slash values
Expand All @@ -99,8 +99,10 @@ export class BasicRouter {
* @param {(string|array)} paths - One or many URL paths that will trigger the provided function
* @param {function} fn - The function containing all of your route logic
*/
addRoute<ContextType extends Context> (
method: string, paths: string | string[], fn: Route<ContextType> | Route<ContextType>[]
addRoute<RouteContextType extends Context> (
method: string,
paths: string | string[],
fn: Route<RouterContextType & RouteContextType> | Route<RouterContextType & RouteContextType>[]
): void {
if (!Array.isArray(paths)) {
paths = [paths];
Expand Down Expand Up @@ -201,7 +203,7 @@ export class BasicRouter {
/**
* Checks to see if the route matches the request, and if true assigns any applicable url variables and returns the route
*
* @param {object} route - Route object from this basic router class
* @param {object} route - Route object from this router class
* @param {object} route.method - HTTP method associated with this route
* @param {object} route.path - HTTP path associated with this route
* @param {object} request_url - Parsed HTTP request url
Expand Down Expand Up @@ -240,14 +242,14 @@ function compareRouteAndApplyArgs (route: {method: string, path: string}, reques
}

// TODO: get rid of this `as`
applyArg(request_url as BasicRouterURL, template_part.substring(1), Number(actual_part));
applyArg(request_url as RouterURL, template_part.substring(1), Number(actual_part));
continue;
}

if (template_part[0] === '$') {
// $ templates accept any non-slash alphanumeric character
// TODO: get rid of this `as`
applyArg(request_url as BasicRouterURL, template_part.substring(1), String(actual_part));
applyArg(request_url as RouterURL, template_part.substring(1), String(actual_part));
// Continue so that
continue;
}
Expand All @@ -270,7 +272,7 @@ function compareRouteAndApplyArgs (route: {method: string, path: string}, reques
* @param {string} template_part - The template variable
* @param {*} actual_part - The url value
*/
function applyArg(request_url: BasicRouterURL, template_part: string, actual_part: string | number): void {
function applyArg(request_url: RouterURL, template_part: string, actual_part: string | number): void {
if (typeof(request_url.args) === 'undefined') {
request_url.args = {};
}
Expand Down
Loading
Loading