Skip to content

Instantly share code, notes, and snippets.

@voodooattack
Last active August 29, 2015 14:27
Show Gist options
  • Save voodooattack/e43babb5e9fe971f57b5 to your computer and use it in GitHub Desktop.
Save voodooattack/e43babb5e9fe971f57b5 to your computer and use it in GitHub Desktop.
restify: Generate isomorphic Marty.js services for baucis controllers.
Marty.HttpStateSource.removeHook('parseJSON');
Marty.HttpStateSource.addHook({
id: 'CSRF',
priority: 1,
before(req) { req.headers['CSRF-Token'] = /* ... obtain a csrf token from somewhere in your application ... */ }
});
class Application extends Marty.Application {
constructor(options = {}) {
super(options);
if (this.req)
this.register(restify(this.req.models.User));
else
this.register(restify('User', '/api');
}
...
/* somewhere on the client or the server */
app.UserActions.create({
firstName: 'Abdullah',
lastName: 'Ali',
email: 'example@example.com',
password: 'test'
});
import Marty from 'marty';
export default function(model, url) {
function generateConstants() {
return Marty.createConstants(['INDEX', 'GET', 'CREATE', 'UPDATE', 'DELETE']);
}
function generateActions(endpoint, constants) {
return class Actions extends Marty.ActionCreators {
displayName = endpoint + 'Actions';
index() {
this.dispatch(constants.INDEX_STARTING);
return this.app[endpoint + 'Api'].index().then(
(result) => this.dispatch(constants.INDEX_DONE, result)
).catch(
(err) => this.dispatch(constants.INDEX_FAILED, { error: err })
);
}
get(id) {
this.dispatch(constants.GET_STARTING, id);
return this.app[endpoint + 'Api'].get(id).then(
(result) => this.dispatch(constants.GET_DONE, id, result)
).catch(
(err) => this.dispatch(constants.GET_FAILED, id, { error: err })
);
}
create(data) {
this.dispatch(constants.CREATE_STARTING, data);
return this.app[endpoint + 'Api'].create(data).then(
(result) => this.dispatch(constants.CREATE_DONE, result.id || result._id, result)
).catch(
(err) => this.dispatch(constants.CREATE_FAILED, null, { error: err })
);
}
update(id, data) {
this.dispatch(constants.UPDATE_STARTING, id, data);
return this.app[endpoint + 'Api'].update(id, data).then(
(result) => this.dispatch(constants.UPDATE_DONE, id, result)
).catch(
(err) => this.dispatch(constants.UPDATE_FAILED, id, { error: err })
);
}
delete(id) {
this.dispatch(constants.DELETE_STARTING, id);
return this.app[endpoint + 'Api'].delete(id).then(
(result) => this.dispatch(constants.DELETE_DONE, id, result)
).catch(
(err) => this.dispatch(constants.DELETE_FAILED, id, { error: err })
);
}
}
}
function generateStore(endpoint, constants) {
return class Store extends Marty.Store {
displayName = endpoint + 'Store';
constructor(options) {
super(options);
this.state = { };
this.handlers = {
receive: [constants.GET_DONE, constants.CREATE_DONE, constants.UPDATE_DONE],
remove: [constants.DELETE_DONE]
};
}
receive(id, item) {
this.setState({ [id]: item });
}
remove(id) {
delete this.state[id];
this.hasChanged();
}
index() {
let api = this.app[endpoint + 'Api'];
return api.index.apply(api, arguments);
}
get(id) {
return this.fetch({
id,
locally() {
return this.state[id];
},
remotely() {
return this.app[endpoint + 'Api'].get(id);
}
})
}
};
}
function generateApi(endpoint, url, model) {
if (model)
return class ServerApi extends Marty.StateSource {
displayName = endpoint + 'Api';
index(query) {
return model.find(query).exec();
}
get(id) {
return model.findById(id).exec();
}
create(data) {
return model.create(data);
}
update(id, data) {
return model.findByIdAndUpdate(id, data).exec();
}
delete(id) {
return model.findByIdAndRemove(id).exec();
}
};
else
return class ClientApi extends Marty.HttpStateSource {
displayName = endpoint + 'Api';
index(query) {
return super.get({
url: url + '/' + endpoint.toLowerCase() + 's',
query
}).then(res => {
if (res.ok)
return res.json();
return res.json().then(result => { throw result; });
});
}
get(id) {
return super.get({
url: url + '/' + endpoint.toLowerCase() + 's/' + id
}).then(res => {
if (res.ok)
return res.json();
return res.json().then(result => { throw result; });
});
}
create(data) {
return super.post({
url: url + '/' + endpoint.toLowerCase() + 's',
body: data
}).then(res => {
if (res.ok)
return res.json();
return res.json().then(result => { throw result; });
});
}
update(id, data) {
return super.put({
url: url + '/' + endpoint.toLowerCase() + 's/' + id,
body: data
}).then(res => {
if (res.ok)
return res.json();
return res.json().then(result => { throw result; });
});
}
delete(id) {
return super.delete({
url: url + '/' + endpoint.toLowerCase() + 's/' + id
}).then(res => {
if (res.ok)
return res.json();
return res.json().then(result => { throw result; });
});
}
};
}
let endpoint = typeof model == 'string' ? model : model.modelName;
let constants = generateConstants();
return {
[endpoint + 'Api']: generateApi(endpoint, url, typeof model == 'string' ? null : model),
[endpoint + 'Actions']: generateActions(endpoint, constants),
[endpoint + 'Store']: generateStore(endpoint, constants)
}
}
// ...
import models from './models';
let controllers = {};
for(var model in models)
if (models.hasOwnProperty(model))
controllers[model] = baucis.rest(models[model]);
app.use('/api', baucis());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment