Skip to content

Commit 39bccde

Browse files
committed
Auto generate resource routes.
1 parent 7700c7c commit 39bccde

File tree

2 files changed

+76
-26
lines changed

2 files changed

+76
-26
lines changed

README.md

+40-7
Original file line numberDiff line numberDiff line change
@@ -65,29 +65,35 @@ Each route will need a couple things:
6565

6666
The layout of each route will be in the following format:
6767

68-
* `['{verb} {url}', '{controller}#{action}']`
68+
```
69+
['{verb} {url}', '({controller}#){action}' || [{subroutes}]]
70+
```
71+
6972
* **verb**
70-
* `get`, `post`, `put`, or `delete`
73+
* `get`, `post`, `patch`, `put`, or `delete`
7174
* **url**
7275
* URL end point that begins at root (leading `/` is optional)
7376
* URLs are allowed to have parameters defined denoted using a colon (`:`)
7477
* Example: `users/:id`
75-
* **controller**
76-
* The controller name is the prefix of the file it is defined in. For example you would use `users` for the controller `app/controllers/users_controller.js`
78+
* **controller** (optional)
79+
* The controller name is the prefix of the file it is defined in. e.g. `users` for `app/controllers/users_controller.js`
80+
* May be omitted to set the controller name to the first part of the route **url**. e.g. `users` for `['get users/all', 'getAll']`
7781
* **action**
78-
* This is the name of the function to call defined in the controller.
82+
* This is the name of the method to call defined in the controller.
83+
* **subroutes**
84+
* Subroutes may be defined instead of a controller and action.
7985

8086
There are a couple ways to define how routes work:
8187

82-
1. All inline:
88+
1. Inline:
8389

8490
```javascript
8591
module.exports = [
8692
['get users/all', 'users#getAll']
8793
]
8894
```
8995

90-
1. Nested:
96+
1. With subroutes:
9197

9298
```javascript
9399
module.exports = [
@@ -109,6 +115,33 @@ There are a couple ways to define how routes work:
109115
]
110116
```
111117

118+
1. [With `resources` verb](#resources):
119+
120+
```javascript
121+
module.exports = [
122+
['resources users']
123+
]
124+
```
125+
126+
#### Resources
127+
128+
Auto generate resource routes with the `['resources {name}']` route format.
129+
130+
The **name** of the resource must be a single word.
131+
132+
The following routes will be generated:
133+
134+
```javascript
135+
[{name}, [
136+
[`get /`, 'fetchAll'],
137+
[`get /:id`, 'fetch'],
138+
[`post /`, 'create'],
139+
[`patch /:id`, 'update'],
140+
[`put /:id`, 'replace'],
141+
[`delete /:id`, 'destroy']
142+
]]
143+
```
144+
112145
### Controllers
113146

114147
Controllers are used to define the actions to take place on each request.

lib/routing/buildRoutes.js

+36-19
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,20 @@ _.each(glob.sync(`${process.cwd()}/${controllerPath}/*`), file => {
2222
controllers[name] = new Controller
2323
})
2424

25-
let buildRoute = (router, path, to, root) => {
26-
// A route path must contain an action method and url.
27-
if(!/.+ .+/.test(path))
28-
throw new Error('An action method AND url must be specified.')
29-
let [method, url] = path.split(' ')
25+
let genResourceRoutes = root => {
26+
return [
27+
[root, [
28+
[`get /`, 'fetchAll'],
29+
[`get /:id`, 'fetch'],
30+
[`post /`, 'create'],
31+
[`patch /:id`, 'update'],
32+
[`put /:id`, 'replace'],
33+
[`delete /:id`, 'destroy']
34+
]]
35+
]
36+
}
3037

38+
let buildRoute = (router, verb, url, to, root) => {
3139
// Check how action function is referenced.
3240
let cName, action
3341
if(/.+#.+/.test(to))
@@ -79,50 +87,59 @@ let buildRoute = (router, path, to, root) => {
7987
}
8088

8189
// Check the existance of the action method. Else return error response.
82-
let mainAction = controller[action].bind(controller)
90+
let mainAction = controller[action]
8391
if(mainAction) {
84-
mainAction(req, res)
92+
mainAction.call(controller, req, res)
8593
} else {
8694
jsonProxy('Action does not exist.').status(404)
8795
}
8896
})
89-
router[method].apply(router, args)
97+
router[verb].apply(router, args)
9098
}
91-
let buildRoutes = (routes, router, root) => {
99+
let buildRoutes = (router, routes, root) => {
92100
// Loop each route defined.
93101
// NOTE: Routes must be defined in an array for proper initilizaion order.
94102
_.each(routes, route => {
95-
// Each route must contain a path/URL to execute at and an action function/subroutes.
96103
let [ path, toAction ] = route
97-
if(!toAction)
98-
throw new Error('No action function is defined for a route. Please check proper route definitions.')
99104

100105
// If `toAction` is an Array, expect it to be subroutes.
101106
if(Array.isArray(toAction)) {
102107
let baseRoot
103108
if(root) {
104109
baseRoot = root
105110
} else {
106-
// Make sure that the root path for subroutes does not contain spaces.
107-
if(/.+ .+/.test(path))
108-
throw new Error('Routes that contain subroutes must not have a root path with spaces.')
111+
if(!/^\w+$/.test(path))
112+
throw new Error('Routes that contain subroutes must only be described by a single word.')
109113
baseRoot = path
110114
}
111115

112116
// Build subroutes.
113117
let subRouter = Router({mergeParams: true})
114-
buildRoutes(toAction, subRouter, baseRoot)
118+
buildRoutes(subRouter, toAction, baseRoot)
115119

116120
// Attach subrouter to parent router.
117121
router.use(`/${path}`, subRouter)
118122
} else {
119-
// Build single route.
120-
buildRoute(router, path, toAction, root)
123+
let [ verb, url ] = path.split(' ')
124+
125+
if(verb === 'resources') {
126+
if(!/^\w+$/.test(url))
127+
throw new Error(`Resource routes must only be described by a single word. ("${url}")`)
128+
129+
// Build all resource routes.
130+
buildRoutes(router, genResourceRoutes(url), root)
131+
} else {
132+
if(!toAction)
133+
throw new Error(`No action method or subroutes are defined for route "${path}". Please check proper route definitions.`)
134+
135+
// Build single route.
136+
buildRoute(router, verb, url, toAction, root)
137+
}
121138
}
122139
})
123140
}
124141
// Initilize routes.
125-
buildRoutes(routes, mainRouter)
142+
buildRoutes(mainRouter, routes)
126143

127144
module.exports = mainRouter
128145

0 commit comments

Comments
 (0)