forked from cloudflare/templates
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request cloudflare#14 from grempe/http-verbs
Router enhancement for full set of HTTP methods. Run project prettier task.
- Loading branch information
Showing
3 changed files
with
119 additions
and
93 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
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 |
---|---|---|
@@ -1,96 +1,121 @@ | ||
/** | ||
* Conditions are helper functions that when passed a request | ||
* will return a boolean for if that request uses | ||
* that method, header, etc.. | ||
* */ | ||
const Method = method => req => req.method.toLowerCase() === method.toLowerCase() | ||
const Get = Method('get') | ||
const Post = Method('post') | ||
const Put = Method('put') | ||
const Patch = Method('patch') | ||
* Helper functions that when passed a request will return a | ||
* boolean indicating if the request uses that HTTP method, | ||
* header, host or referrer. | ||
*/ | ||
const Method = method => req => | ||
req.method.toLowerCase() === method.toLowerCase() | ||
const Connect = Method('connect') | ||
const Delete = Method('delete') | ||
const Get = Method('get') | ||
const Head = Method('head') | ||
const Options = Method('options') | ||
const Patch = Method('patch') | ||
const Post = Method('post') | ||
const Put = Method('put') | ||
const Trace = Method('trace') | ||
|
||
const Header = (header, val) => req => req.headers.get(header) === val | ||
const Host = host => Header('host', host.toLowerCase()) | ||
const Referrer = host => Header('referrer', host.toLowerCase()) | ||
|
||
const Path = regExp => req => { | ||
const url = new URL(req.url) | ||
const path = url.pathname | ||
const match = path.match(regExp) || [] | ||
return match[0] === path | ||
const url = new URL(req.url) | ||
const path = url.pathname | ||
const match = path.match(regExp) || [] | ||
return match[0] === path | ||
} | ||
|
||
/** | ||
* Router handles the logic of what handler is matched given conditions | ||
* for each request | ||
* */ | ||
* The Router handles determines which handler is matched given the | ||
* conditions present for each request. | ||
*/ | ||
class Router { | ||
constructor() { | ||
this.routes = [] | ||
} | ||
|
||
handle(conditions, handler) { | ||
this.routes.push({ | ||
conditions, | ||
handler, | ||
}) | ||
return this | ||
} | ||
|
||
get(url, handler) { | ||
return this.handle([Get, Path(url)], handler) | ||
} | ||
|
||
post(url, handler) { | ||
return this.handle([Post, Path(url)], handler) | ||
} | ||
|
||
patch(url, handler) { | ||
return this.handle([Patch, Path(url)], handler) | ||
} | ||
|
||
delete(url, handler) { | ||
return this.handle([Delete, Path(url)], handler) | ||
} | ||
|
||
all(handler) { | ||
return this.handle([], handler) | ||
} | ||
|
||
route(req) { | ||
const route = this.resolve(req) | ||
|
||
if (route) { | ||
return route.handler(req) | ||
constructor() { | ||
this.routes = [] | ||
} | ||
|
||
handle(conditions, handler) { | ||
this.routes.push({ | ||
conditions, | ||
handler, | ||
}) | ||
return this | ||
} | ||
|
||
connect(url, handler) { | ||
return this.handle([Connect, Path(url)], handler) | ||
} | ||
|
||
delete(url, handler) { | ||
return this.handle([Delete, Path(url)], handler) | ||
} | ||
|
||
get(url, handler) { | ||
return this.handle([Get, Path(url)], handler) | ||
} | ||
|
||
head(url, handler) { | ||
return this.handle([Head, Path(url)], handler) | ||
} | ||
|
||
return new Response('resource not found', { | ||
status: 404, | ||
statusText: 'not found', | ||
headers: { | ||
'content-type': 'text/plain', | ||
}, | ||
}) | ||
} | ||
|
||
// resolve returns the matching route that returns true for | ||
// all the conditions if any | ||
resolve(req) { | ||
return this.routes.find(r => { | ||
if (!r.conditions || (Array.isArray(r) && !r.conditions.length)) { | ||
return true | ||
} | ||
|
||
if (typeof r.conditions === 'function') { | ||
return r.conditions(req) | ||
} | ||
|
||
return r.conditions.every(c => c(req)) | ||
}) | ||
} | ||
options(url, handler) { | ||
return this.handle([Options, Path(url)], handler) | ||
} | ||
|
||
patch(url, handler) { | ||
return this.handle([Patch, Path(url)], handler) | ||
} | ||
|
||
post(url, handler) { | ||
return this.handle([Post, Path(url)], handler) | ||
} | ||
|
||
put(url, handler) { | ||
return this.handle([Put, Path(url)], handler) | ||
} | ||
|
||
trace(url, handler) { | ||
return this.handle([Trace, Path(url)], handler) | ||
} | ||
|
||
all(handler) { | ||
return this.handle([], handler) | ||
} | ||
|
||
route(req) { | ||
const route = this.resolve(req) | ||
|
||
if (route) { | ||
return route.handler(req) | ||
} | ||
|
||
return new Response('resource not found', { | ||
status: 404, | ||
statusText: 'not found', | ||
headers: { | ||
'content-type': 'text/plain', | ||
}, | ||
}) | ||
} | ||
|
||
/** | ||
* resolve returns the matching route for a request that returns | ||
* true for all conditions (if any). | ||
*/ | ||
resolve(req) { | ||
return this.routes.find(r => { | ||
if (!r.conditions || (Array.isArray(r) && !r.conditions.length)) { | ||
return true | ||
} | ||
|
||
if (typeof r.conditions === 'function') { | ||
return r.conditions(req) | ||
} | ||
|
||
return r.conditions.every(c => c(req)) | ||
}) | ||
} | ||
} | ||
|
||
module.exports = Router |