Skip to content

Commit b413186

Browse files
committed
feat(route): new routing system using controllers routes function
1 parent 43ff98a commit b413186

File tree

2 files changed

+90
-68
lines changed

2 files changed

+90
-68
lines changed

model.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ module.exports = db => class Model {
3232
return Object.assign(obj, { _id, created });
3333
}
3434

35-
static async createTable() {
35+
static async init() {
3636
await db.query(`
3737
create table if not exists ${this.config().table} (
3838
id text primary key not null,
@@ -82,6 +82,9 @@ module.exports = db => class Model {
8282
}
8383

8484
static async read(id) {
85+
if (!isString(id)) {
86+
id = id._id;
87+
}
8588
let result = await db.query(`
8689
select ${JSONB}
8790
from ${this.config().table}
@@ -102,6 +105,10 @@ module.exports = db => class Model {
102105
`, [this._id, JSON.stringify(this)]);
103106
return this;
104107
}
108+
static async update(obj) {
109+
let instance = this.read(obj);
110+
return instance.update(obj);
111+
}
105112

106113
static async delete(id) {
107114
return db.query(`

route.js

Lines changed: 82 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,78 +2,93 @@
22

33
let path = require('path');
44
let error = require('./error');
5+
let { isFunction, isString } = require('./util');
56

6-
const METHODS = [
7-
'all', 'checkout', 'copy', 'delete', 'get', 'head', 'lock', 'merge',
8-
'mkactivity', 'mkcol', 'move', 'm-search', 'notify', 'options', 'patch', 'post',
9-
'purge', 'put', 'report', 'search', 'subscribe', 'trace', 'unlock', 'unsubscribe',
10-
];
7+
const METHODS = ['get', 'post', 'put', 'delete'];
118

12-
// module.exports = {
13-
// scope: {
14-
// profileController,
15-
// },
16-
// async test() {
17-
// await this.profileController.getCurrentUser();
18-
// },
19-
// };
20-
21-
// let router = api('profile', profileController);
22-
//
23-
// router.get('login', async ctx => {
24-
// await auth.test(ctx);
25-
// return ctx.getProfile(ctx.req.body);
26-
// });
27-
28-
// let route = require('begin-server/route');
29-
// let express = require('express');
30-
// let app = express();
31-
// let api = route(app, 'v1');
32-
33-
// api();
34-
// api('profile');
35-
// api(profileController);
36-
// api('profile', profileController);
37-
38-
module.exports = (app, root = '') => Object.assign((base, controller = {}) => {
39-
if (typeof base !== 'string') {
40-
controller = base;
41-
base = '';
9+
module.exports = (app, options = {}) => controller => {
10+
if (!isFunction(controller.routes)) {
11+
return;
4212
}
43-
base = path.join('/', root, base);
44-
return METHODS.reduce((out, method) => {
45-
out[method] = (endpoint, cb) => {
46-
if (typeof endpoint !== 'string') {
47-
cb = endpoint;
48-
endpoint = '';
49-
}
50-
endpoint = path.join(base, endpoint);
51-
app[method](endpoint, async (req, res) => {
52-
let bind = details => {
53-
let bound = Object.create(details);
54-
if (bound.scope) {
55-
Object.entries(bound.scope).forEach(([key, value]) => {
56-
bound[key] = bind(value);
57-
});
58-
}
59-
return Object.assign(bound, { req, res });
60-
};
61-
try {
62-
res.json(await cb(bind(controller)));
63-
} catch (e) {
64-
let status = e.status || 500;
65-
res.status(status);
66-
let apiError = { error: error.ERROR_CODES.serverError.message };
67-
if (!error.isError(e) || status === 500) {
68-
// TODO: support different log handler or error handler
69-
console.error(e);
70-
} else {
71-
apiError.error = e.message;
72-
}
73-
res.json(apiError);
13+
let {
14+
root = '',
15+
onError = console.error,
16+
beforeEach = () => {},
17+
} = options;
18+
let base = root;
19+
// Proxy methods in `app` with functions that take `(endpoint, callback)`
20+
let api = (...apiArgs) => {
21+
let set = ({ resType = 'json' } = {}) => {
22+
let handler = method => (endpoint, cb) => {
23+
let interceptor = beforeEach(...apiArgs);
24+
if (!isString(endpoint)) {
25+
cb = endpoint;
26+
endpoint = '';
7427
}
28+
endpoint = path.join(base, endpoint);
29+
// register the endpoint to `app` and maintain the callback arguments
30+
app[method](endpoint, async (req, res) => {
31+
let bind = details => {
32+
let bound = Object.create(details);
33+
if (bound.scope) {
34+
Object.entries(bound.scope).forEach(([key, value]) => {
35+
bound[key] = bind(value);
36+
});
37+
}
38+
return Object.assign(bound, { req, res });
39+
};
40+
try {
41+
// first try running the beforeEach function
42+
await interceptor(req, res);
43+
let out = await cb(req, res)(bind(controller));
44+
if (resType) {
45+
res[resType](out);
46+
}
47+
} catch (e) {
48+
let status = e.status || 500;
49+
res.status(status);
50+
let apiError = { error: error.ERROR_CODES.serverError.message };
51+
if (!error.isError(e) || status === 500) {
52+
onError(e);
53+
} else {
54+
apiError.error = e.message;
55+
}
56+
res.json(apiError);
57+
}
58+
});
59+
};
60+
return METHODS.reduce((out, method) => {
61+
out[method] = handler(method);
62+
return out;
63+
}, {
64+
other(method, ...args) {
65+
return handler(method)(...args);
66+
},
7567
});
7668
};
69+
return Object.assign(set(), { set });
70+
};
71+
72+
// create new functions with names derrived from the controller
73+
let scope = Object.entries(controller).reduce((out, [key, fn]) => {
74+
// Each derrived function returns a new function that expects the scope to bind to.
75+
out[key] = (...args) => ctx => fn.call(ctx, ...args);
7776
return out;
7877
}, {});
79-
}, { error });
78+
79+
let apiArg = Object.assign(api, api(), {
80+
// A function to change the base route for this instance of `api`
81+
path(route) {
82+
base = path.join('/', root, route);
83+
},
84+
});
85+
86+
let optionsArg = Object.assign({}, options, {
87+
root,
88+
onError,
89+
beforeEach,
90+
noRes: { resType: false },
91+
});
92+
93+
controller.routes.call(scope, apiArg, optionsArg);
94+
};

0 commit comments

Comments
 (0)