Skip to content

Commit

Permalink
Merge pull request #169 from sebringrose/http-shorthand
Browse files Browse the repository at this point in the history
Http shorthand
  • Loading branch information
sejori committed Apr 27, 2023
2 parents ced5cf1 + 1fdafe9 commit f26cb2e
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 65 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,19 +83,22 @@ server.listen(7777, () => console.log("Peko server started - let's go!"));

PR to add your project 🙌

### [iiisun.art](https://iiisun.art) - artistic storefront [source](https://github.com/sebringrose/third-sun/blob/main/server.ts)
### [iiisun.art](https://iiisun.art) - artistic storefront
- **Stack:** React, ImageMagick_deno
- **Features:** CI resized-image precaching, Gelato & Stripe integrations, Parallax CSS
- **Note:** [lit-html](https://marketplace.visualstudio.com/items?itemName=bierner.lit-html) and [es6-string-css](https://marketplace.visualstudio.com/items?itemName=bashmish.es6-string-css) VS Code extensions recommended.
- [source](https://github.com/sebringrose/third-sun/blob/main/server.ts)

### [shineponics.org](https://shineponics.org) - smart-farming PaaS [source](https://github.com/shine-systems/shineponics/blob/main/server.ts)
### [shineponics.org](https://shineponics.org) - smart-farming PaaS
- **Stack:** React, Google Cloud Platform
- **Features:** Google Sheet analytics, GCP email list, Markdown rendering
- **Note:** [lit-html](https://marketplace.visualstudio.com/items?itemName=bierner.lit-html) and [es6-string-css](https://marketplace.visualstudio.com/items?itemName=bashmish.es6-string-css) VS Code extensions recommended.
- [source](https://github.com/shine-systems/shineponics/blob/main/server.ts)

### [peko-auth.deno.dev](https://peko-auth.deno.dev) - basic authentication demo [source](https://github.com/sebringrose/peko/blob/main/examples/auth/app.ts)
### [peko-auth.deno.dev](https://peko-auth.deno.dev) - basic authentication demo
- **Stack:** HTML5
- **Features:** JWT-based auth
- [source](https://github.com/sebringrose/peko/blob/main/examples/auth/app.ts)

**Note:** [lit-html](https://marketplace.visualstudio.com/items?itemName=bierner.lit-html) and [es6-string-css](https://marketplace.visualstudio.com/items?itemName=bashmish.es6-string-css) VS Code extensions recommended.

<h2>Deployment</h2>

Expand Down
156 changes: 101 additions & 55 deletions lib/utils/Router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,62 +23,108 @@ export class Router {
* @param route: Route | Route["path"]
* @param arg2?: Partial<Route> | Middleware | Middleware[],
* @param arg3?: Handler
* @returns number - Router.length
* @returns route: Route - added route object
*/
addRoute(route: Route): number
addRoute(route: Route["path"], data: Handler | Partial<Route>): number
addRoute(route: Route["path"], middleware: Middleware | Middleware[], handler: Handler): number
addRoute(
arg1: Route | Route["path"],
arg2?: Partial<Route> | Middleware | Middleware[],
arg3?: Handler
): number {
const routeObj: Partial<Route> = typeof arg1 !== "string"
? arg1
: arguments.length === 2
? typeof arg2 === "function"
? { path: arg1, handler: arg2 as Handler }
: { path: arg1, ...arg2 as Partial<Route> }
: { path: arg1, middleware: arg2 as Middleware | Middleware[], handler: arg3 }

if (this.routes.find(existing => existing.path === routeObj.path)) {
throw new Error(`Route with path ${routeObj.path} already exists!`)
}

return this.routes.push(Router.applyDefaults(routeObj))
}

/**
* Add Routes
* @param routes: Route[] - middleware can be Middlewares or Middleware
* @returns number - routes.length
*/
addRoutes(routes: Route[]): number {
routes.forEach(route => this.addRoute(route))
return this.routes.length
}

/**
* Remove Route from Peko server
* @param route: Route["path"] of route to remove
* @returns
*/
removeRoute(route: Route["path"]): number {
const routeToRemove = this.routes.find(r => r.path === route)
if (routeToRemove) {
this.routes.splice(this.routes.indexOf(routeToRemove), 1)
}

return this.routes.length
addRoute(route: Route): Route
addRoute(route: Route["path"], data: Handler | Partial<Route>): Route
addRoute(route: Route["path"], middleware: Middleware | Middleware[], handler: Handler): Route
addRoute(
arg1: Route | Route["path"],
arg2?: Partial<Route> | Middleware | Middleware[],
arg3?: Handler
): Route {
const routeObj: Partial<Route> = typeof arg1 !== "string"
? arg1
: arguments.length === 2
? typeof arg2 === "function"
? { path: arg1, handler: arg2 as Handler }
: { path: arg1, ...arg2 as Partial<Route> }
: { path: arg1, middleware: arg2 as Middleware | Middleware[], handler: arg3 }

if (this.routes.find(existing => existing.path === routeObj.path)) {
throw new Error(`Route with path ${routeObj.path} already exists!`)
}

/**
* Remove Routes
* @param routes: Route["path"] of routes to remove
* @returns
*/
removeRoutes(routes: Route["path"][]): number {
routes.forEach(route => this.removeRoute(route))
return this.routes.length

const fullRoute = Router.applyDefaults(routeObj)
this.routes.push(fullRoute)

return fullRoute
}
/**
* Add Route with method "GET" (same as default addRoute behaviour)
* @returns route: Route - added route object
*/
get: typeof this.addRoute = function() {
// @ts-ignore supply overload args
const newRoute = this.addRoute(...arguments)
newRoute.method = "GET"
return newRoute
}

/**
* Add Route with method "POST"
* @returns route: Route - added route object
*/
post: typeof this.addRoute = function() {
// @ts-ignore supply overload args
const newRoute = this.addRoute(...arguments)
newRoute.method = "POST"
return newRoute
}

/**
* Add Route with method "PUT"
* @returns route: Route - added route object
*/
put: typeof this.addRoute = function() {
// @ts-ignore supply overload args
const newRoute = this.addRoute(...arguments)
newRoute.method = "PUT"
return newRoute
}

/**
* Add Route with method "DELETE"
* @returns route: Route - added route object
*/
delete: typeof this.addRoute = function() {
// @ts-ignore supply overload args
const newRoute = this.addRoute(...arguments)
newRoute.method = "DELETE"
return newRoute
}

/**
* Add Routes
* @param routes: Route[] - middleware can be Middlewares or Middleware
* @returns number - routes.length
*/
addRoutes(routes: Route[]): number {
routes.forEach(route => this.addRoute(route))
return this.routes.length
}

/**
* Remove Route from Peko server
* @param route: Route["path"] of route to remove
* @returns
*/
removeRoute(route: Route["path"]): number {
const routeToRemove = this.routes.find(r => r.path === route)
if (routeToRemove) {
this.routes.splice(this.routes.indexOf(routeToRemove), 1)
}

return this.routes.length
}

/**
* Remove Routes
* @param routes: Route["path"] of routes to remove
* @returns
*/
removeRoutes(routes: Route["path"][]): number {
routes.forEach(route => this.removeRoute(route))
return this.routes.length
}
}
4 changes: 2 additions & 2 deletions tests/server_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ Deno.test("SERVER", async (t) => {
server.addRoute({ path: "/route", handler: testHandler })
server.addRoute("/anotherRoute", { handler: testHandler })
server.addRoute("/anotherNotherRoute", testHandler)
const routesLength = server.addRoute("/anotherNotherNotherRoute", testMiddleware2, testHandler)
server.addRoute("/anotherNotherNotherRoute", testMiddleware2, testHandler)

assert(routesLength === 4 && server.routes.length === 4)
assert(server.routes.length === 4)

const request = new Request("http://localhost:7777/route")
const anotherRequest = new Request("http://localhost:7777/anotherRoute")
Expand Down
33 changes: 30 additions & 3 deletions tests/utils/Router_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import {
testHandler,
} from "../mocks/middleware.ts"

Deno.test("SERVER", async (t) => {
Deno.test("ROUTER", async (t) => {
const router = new Router()

await t.step("routes added with full route and string arg options", () => {
router.addRoute({ path: "/route", handler: testHandler })
router.addRoute("/anotherRoute", { handler: testHandler })
router.addRoute("/anotherNotherRoute", testHandler)
const routesLength = router.addRoute("/anotherNotherNotherRoute", testMiddleware1, testHandler)
const finalRoute = router.addRoute("/anotherNotherNotherRoute", testMiddleware1, testHandler)

assert(routesLength === 4 && router.routes.length === 4)
assert(finalRoute.path === "/anotherNotherNotherRoute" && router.routes.length === 4)
})

await t.step("routes removed", () => {
Expand Down Expand Up @@ -43,4 +43,31 @@ Deno.test("SERVER", async (t) => {
assert(!aRouter.routes.find(route => route.path === "/route"))
assert(aRouter.routes.length === 2)
})

await t.step ("http shorthand methods work correctly", () => {
const router = new Router()

const getRoute = router.get({
path: "/get",
handler: () => new Response("GET")
})
const postRoute = router.post({
path: "/post",
handler: () => new Response("POST")
})
const putRoute =router.put({
path: "/put",
handler: () => new Response("PUT")
})
const deleteRoute = router.delete({
path: "/delete",
handler: () => new Response("DELETE")
})

assert(router.routes.length === 4)
assert(getRoute.method === "GET")
assert(postRoute.method === "POST")
assert(putRoute.method === "PUT")
assert(deleteRoute.method === "DELETE")
})
})

0 comments on commit f26cb2e

Please sign in to comment.