-
-
Notifications
You must be signed in to change notification settings - Fork 94
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
55d37d0
commit 7e50536
Showing
9 changed files
with
477 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { posix } from "../deps/path.ts"; | ||
|
||
import type { Middleware } from "../core/server.ts"; | ||
|
||
interface RouterParams { | ||
request: Request; | ||
[key: string]: unknown; | ||
} | ||
|
||
type RouteHandler<T = RouterParams> = ( | ||
params: T, | ||
) => Response | Promise<Response>; | ||
|
||
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE"; | ||
|
||
interface RouteDefinition { | ||
method: HTTPMethod; | ||
pattern: URLPattern; | ||
handler: RouteHandler; | ||
} | ||
|
||
export interface Options { | ||
basePath?: string; | ||
strict?: boolean; | ||
} | ||
|
||
const baseURL = "http://localhost/"; | ||
|
||
export default class Router { | ||
routes: RouteDefinition[] = []; | ||
basePath: string; | ||
strict: boolean; | ||
|
||
constructor(options?: Options) { | ||
this.basePath = options?.basePath ?? "/"; | ||
this.strict = options?.strict ?? true; | ||
} | ||
|
||
add(method: HTTPMethod, pattern: string, handler: RouteHandler) { | ||
pattern = posix.join("/", this.basePath, pattern); | ||
|
||
if (!this.strict) { | ||
pattern += "{/}?"; | ||
} | ||
|
||
this.routes.push({ | ||
method, | ||
pattern: new URLPattern(pattern, baseURL), | ||
handler, | ||
}); | ||
} | ||
|
||
get(pattern: string, handler: RouteHandler) { | ||
this.add("GET", pattern, handler); | ||
} | ||
|
||
post(pattern: string, handler: RouteHandler) { | ||
this.add("POST", pattern, handler); | ||
} | ||
|
||
put(pattern: string, handler: RouteHandler) { | ||
this.add("PUT", pattern, handler); | ||
} | ||
|
||
delete(pattern: string, handler: RouteHandler) { | ||
this.add("DELETE", pattern, handler); | ||
} | ||
|
||
async exec(request: Request): Promise<Response | undefined> { | ||
for (const { method, pattern, handler } of this.routes) { | ||
if (request.method !== method) { | ||
continue; | ||
} | ||
|
||
const url = new URL(request.url); | ||
const result = pattern.exec({ | ||
pathname: url.pathname, | ||
baseURL, | ||
}); | ||
|
||
if (result) { | ||
const data = { ...result.pathname?.groups, request }; | ||
return await handler(data); | ||
} | ||
} | ||
} | ||
|
||
middleware(): Middleware { | ||
return async (request, next) => { | ||
const response = await this.exec(request); | ||
|
||
if (response) { | ||
return response; | ||
} | ||
|
||
return await next(request); | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
export const snapshot = {}; | ||
|
||
snapshot[`simple routes 1`] = ` | ||
{ | ||
body: "Hello World from GET", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://localhost/hello", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`simple routes 2`] = ` | ||
{ | ||
body: "Hello World from GET", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://example.com/hello", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`simple routes 3`] = ` | ||
{ | ||
body: "Hello World from POST", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "POST", | ||
request: "http://localhost/hello", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`simple routes 4`] = ` | ||
{ | ||
body: "Hello World from POST", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "POST", | ||
request: "http://example.com:1234/hello", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`simple routes 5`] = ` | ||
{ | ||
body: "Hello World from PUT", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "PUT", | ||
request: "http://localhost/hello", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`simple routes 6`] = ` | ||
{ | ||
body: "Hello World from DELETE", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "DELETE", | ||
request: "http://localhost/hello", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`simple routes with base path 1`] = ` | ||
{ | ||
body: "Not Found", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://localhost/hello", | ||
status: 404, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`simple routes with base path 2`] = ` | ||
{ | ||
body: "Hello World from GET", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://example.com/api/hello", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`simple routes with base path 3`] = ` | ||
{ | ||
body: "Hello World from GET", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://example.com:1234/api/hello", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`routes with parameters 1`] = ` | ||
{ | ||
body: "Not Found", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://localhost/hello", | ||
status: 404, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`routes with parameters 2`] = ` | ||
{ | ||
body: "Hello oscar", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://localhost/hello/oscar", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`routes with parameters 3`] = ` | ||
{ | ||
body: "Not Found", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://localhost/hello/oscar/", | ||
status: 404, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`routes with parameters and strict = false 1`] = ` | ||
{ | ||
body: "Not Found", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://localhost/hello", | ||
status: 404, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`routes with parameters and strict = false 2`] = ` | ||
{ | ||
body: "Hello oscar / null", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://localhost/hello/oscar", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`routes with parameters and strict = false 3`] = ` | ||
{ | ||
body: "Hello oscar / null", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://localhost/hello/oscar/", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`routes with parameters and strict = false 4`] = ` | ||
{ | ||
body: "Hello oscar / foo", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://localhost/hello/oscar/?query=foo", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; | ||
|
||
snapshot[`routes with parameters and strict = false 5`] = ` | ||
{ | ||
body: "Hello oscar / foo", | ||
headers: { | ||
"content-type": "text/plain;charset=UTF-8", | ||
}, | ||
method: "GET", | ||
request: "http://localhost/hello/oscar?query=foo", | ||
status: 200, | ||
statusText: "", | ||
} | ||
`; |
Oops, something went wrong.