Improvements in REST API

This commit is contained in:
vjrj 2018-06-15 06:39:09 +02:00
parent d980a31c05
commit 7c8f7874a9
2 changed files with 300 additions and 288 deletions

View file

@ -31,8 +31,8 @@ function defaultFailParams(e) {
} }
function checkAuthToken(token) { function checkAuthToken(token) {
if (token !== Meteor.settings.private.internalApiToken) { if (!Meteor.settings.private.internalApiToken || token !== Meteor.settings.private.internalApiToken) {
const message = `Unauthorized auth token '${token}' in REST API`; const message = 'Unauthorized auth token in REST API';
console.warn(message); console.warn(message);
return restivusError(401, message); return restivusError(401, message);
} }
@ -45,18 +45,20 @@ function checkLatLonDist(km, lat, lng) {
check(km, NumberBetween(0, Meteor.isDevelopment ? 1000 : 100)); check(km, NumberBetween(0, Meteor.isDevelopment ? 1000 : 100));
} }
if (!Meteor.settings.private.internalApiToken) {
console.warn('Meteor.settings.private.internalApiToken is not configured so we don\'t enable our REST API');
} else {
// export // export
const apiV1 = new Restivus({ const apiV1 = new Restivus({
useDefaultAuth: true, useDefaultAuth: true,
apiPath: 'api', apiPath: 'api',
version: 'v1', version: 'v1',
prettyJson: true prettyJson: true
}); });
// Generates: POST on /api/users and GET, DELETE /api/users/:id for // Generates: POST on /api/users and GET, DELETE /api/users/:id for
// Meteor.users collection // Meteor.users collection
/* apiV1.addCollection(Meteor.users, { /* apiV1.addCollection(Meteor.users, {
* excludedEndpoints: ['getAll', 'put', 'delete', 'patch', 'get'], * excludedEndpoints: ['getAll', 'put', 'delete', 'patch', 'get'],
* routeOptions: { * routeOptions: {
* authRequired: true * authRequired: true
@ -71,7 +73,7 @@ const apiV1 = new Restivus({
* } * }
* }); */ * }); */
apiV1.addCollection(Fires, { apiV1.addCollection(Fires, {
excludedEndpoints: ['put', 'post', 'patch', 'delete'], excludedEndpoints: ['put', 'post', 'patch', 'delete'],
// excludedEndpoints: ['getAll', 'put', 'post', 'patch', 'delete'], // excludedEndpoints: ['getAll', 'put', 'post', 'patch', 'delete'],
routeOptions: { routeOptions: {
@ -84,37 +86,37 @@ apiV1.addCollection(Fires, {
} }
} }
} }
}); });
// Maps to: /api/v1/status/last-fire-check // Maps to: /api/v1/status/last-fire-check
apiV1.addRoute('status/last-fire-check', { authRequired: false }, { apiV1.addRoute('status/last-fire-check', { authRequired: false }, {
get: function get() { get: function get() {
return SiteSettings.findOne({ name: 'last-fire-check' }); return SiteSettings.findOne({ name: 'last-fire-check' });
} }
}); });
// Maps to: /api/v1/status/last-fire-detected // Maps to: /api/v1/status/last-fire-detected
apiV1.addRoute('status/last-fire-detected', { authRequired: false }, { apiV1.addRoute('status/last-fire-detected', { authRequired: false }, {
get: function get() { get: function get() {
return ActiveFiresCollection.findOne({}, { sort: { when: -1 } }); return ActiveFiresCollection.findOne({}, { sort: { when: -1 } });
} }
}); });
// Maps to: /api/v1/status/active-fires-count // Maps to: /api/v1/status/active-fires-count
apiV1.addRoute('status/active-fires-count', { authRequired: false }, { apiV1.addRoute('status/active-fires-count', { authRequired: false }, {
get: function get() { get: function get() {
return { total: ActiveFiresCollection.find({}).count() }; return { total: ActiveFiresCollection.find({}).count() };
} }
}); });
// Maps to: /api/v1/status/uptime // Maps to: /api/v1/status/uptime
apiV1.addRoute('status/uptime', { authRequired: false }, { apiV1.addRoute('status/uptime', { authRequired: false }, {
get: function get() { get: function get() {
return { ms: new Date() - uptime }; return { ms: new Date() - uptime };
} }
}); });
function getFires(route, full) { function getFires(route, full) {
const lat = Number(route.urlParams.lat); const lat = Number(route.urlParams.lat);
const lng = Number(route.urlParams.lng); const lng = Number(route.urlParams.lng);
const km = Number(route.urlParams.km); const km = Number(route.urlParams.km);
@ -173,29 +175,29 @@ function getFires(route, full) {
return { return {
total: 0, real: 0, fires: [], falsePos: [], industries: [] total: 0, real: 0, fires: [], falsePos: [], industries: []
}; };
} }
// Maps to: /api/v1/fires-in/:lat/:lng/:km // Maps to: /api/v1/fires-in/:lat/:lng/:km
// 100 km max // 100 km max
// Ex: http://127.0.0.1:3000/api/v1/fires-in/token/38.736946/-9.142685/100 // Ex: http://127.0.0.1:3000/api/v1/fires-in/token/38.736946/-9.142685/100
apiV1.addRoute('fires-in/:token/:lat/:lng/:km', { authRequired: false }, { apiV1.addRoute('fires-in/:token/:lat/:lng/:km', { authRequired: false }, {
get: function get() { get: function get() {
return getFires(this, false); return getFires(this, false);
} }
}); });
apiV1.addRoute('fires-in-full/:token/:lat/:lng/:km', { authRequired: false }, { apiV1.addRoute('fires-in-full/:token/:lat/:lng/:km', { authRequired: false }, {
get: function get() { get: function get() {
return getFires(this, true); return getFires(this, true);
} }
}); });
// Add mobile user: // Add mobile user:
// curl -X POST http://localhost:3000/api/v1/users/mobile -d "token: thisAppAutToken" -d "mobileToken: user-mobile-firebase-token" // curl -X POST http://localhost:3000/api/v1/users/mobile -d "token: thisAppAutToken" -d "mobileToken: user-mobile-firebase-token"
// Response: // Response:
// //
// https://docs.meteor.com/api/passwords.html#Accounts-createUser // https://docs.meteor.com/api/passwords.html#Accounts-createUser
apiV1.addRoute('mobile/users', { authRequired: false }, { apiV1.addRoute('mobile/users', { authRequired: false }, {
post: function post() { post: function post() {
const { token, mobileToken, lang } = this.bodyParams; const { token, mobileToken, lang } = this.bodyParams;
try { try {
@ -211,14 +213,22 @@ apiV1.addRoute('mobile/users', { authRequired: false }, {
let username; let username;
const already = Meteor.users.find({ fireBaseToken: mobileToken });
if (already.count() > 1) {
return restivusError(500, 'Unexpected error in REST call: several users with that mobile token?');
} else if (already.count() === 1) {
username = already.fetch()[0].username;
} else {
do { do {
username = Random.id(15); username = Random.id(15);
} while (Meteor.users.find({ username }).count() !== 0); } while (Meteor.users.find({ username }).count() !== 0);
}
// FIXME check valid lang // FIXME check valid lang
const now = new Date(); const now = new Date();
// Accounts.createUser({ username: mobileToken, lang: 'FIXME' profile: {} });
const result = Meteor.users.upsert({ const result = Meteor.users.upsert({
fireBaseToken: mobileToken fireBaseToken: mobileToken
}, { }, {
@ -232,27 +242,30 @@ apiV1.addRoute('mobile/users', { authRequired: false }, {
} }
}); });
if (debug) { if (debug) {
console.log(this.bodyParams); console.log(this.bodyParams);
console.log(this.urlParams); console.log(this.urlParams);
console.log(this.queryParams); console.log(this.queryParams);
} }
const newUser = Meteor.users.findOne({ username }); const upsertUser = Meteor.users.findOne({ username });
if (debug) console.log(upsertUser);
return jsend.success({ return jsend.success({
upsertResult: result, upsertResult: result,
username, username,
userId: newUser._id, userId: upsertUser._id,
lang: newUser.lang, lang: upsertUser.lang,
mobileToken: newUser.fireBaseToken mobileToken: upsertUser.fireBaseToken
}); });
} }
}); });
// max sitance: 100km // max sitance: 100km
apiV1.addRoute('mobile/subscriptions', { authRequired: false }, { apiV1.addRoute('mobile/subscriptions', { authRequired: false }, {
post: function post() { post: function post() {
const { const {
token, token,
@ -320,9 +333,9 @@ apiV1.addRoute('mobile/subscriptions', { authRequired: false }, {
return jsend.success({}); return jsend.success({});
} }
}); });
apiV1.addRoute('mobile/subscriptions/all', { authRequired: false }, { apiV1.addRoute('mobile/subscriptions/all', { authRequired: false }, {
get: function get() { get: function get() {
const { token, mobileToken } = this.bodyParams; const { token, mobileToken } = this.bodyParams;
try { try {
@ -363,4 +376,5 @@ apiV1.addRoute('mobile/subscriptions/all', { authRequired: false }, {
return jsend.success({ count: toRemove }); return jsend.success({ count: toRemove });
} }
}); });
}

View file

@ -270,9 +270,8 @@ describe('basic api v1 returns', () => {
}); });
it('should del all mobile user subscriptions', async (done) => { it('should del all mobile user subscriptions', async (done) => {
// Add two // Add subs
addSubs(() => {}); addSubs(() => {
addSubs(() => {});
HTTP.del(url('api/v1/mobile/subscriptions/all'), { HTTP.del(url('api/v1/mobile/subscriptions/all'), {
data: { data: {
token, token,
@ -284,10 +283,9 @@ describe('basic api v1 returns', () => {
const jsendResult = result.data; const jsendResult = result.data;
chai.expect(jsendResult.status).equal('success'); chai.expect(jsendResult.status).equal('success');
chai.expect(typeof jsendResult.data.count).to.equal('number'); chai.expect(typeof jsendResult.data.count).to.equal('number');
chai.expect(jsendResult.data.count).to.equal(2); chai.expect(jsendResult.data.count).to.equal(1);
done(); done();
}); });
}); });
});
// TODO remove all subs
}); });