Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

jammin

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jammin - npm Package Compare versions

Comparing version 0.0.4 to 0.0.5

155

lib/api.js

@@ -5,14 +5,23 @@ var Async = require('async');

var BodyParser = require('body-parser');
var PathToRegexp = require('path-to-regexp');
var SwaggerBuilder = require('./swagger-builder.js');
var SELECT = '-_id -__v'
var FIELDS = {};
SELECT.split(' ').forEach(function(field) {
if (field.indexOf('-') === 0) {
FIELDS[field.substring(1)] = false;
} else {
FIELDS[field] = true;
var MONGO_FIELDS = ['_id', '__v'];
var SELECT = MONGO_FIELDS.map(function(f) {return '-' + f}).join(' ');
var removeMongoFields = function(obj) {
if (typeof obj !== 'object') return obj;
else if (Array.isArray(obj)) return obj.map(function(item) {return removeMongoFields(item)});
else {
for (key in obj) {
if (MONGO_FIELDS.indexOf(key) === -1) {
obj[key] = removeMongoFields(obj[key]);
} else {
delete obj[key];
}
}
return obj;
}
})
}

@@ -65,18 +74,50 @@ /** API **/

Definition.prototype.queryDB = function(method, many, query, body, callback) {
var self = this;
if (method === 'get') {
var find = many ? self.db.find : self.db.findOne;
find.apply(self.db, [query, SELECT]).exec(callback);
} else if (method === 'post') {
var docs = many ? body : [body];
Async.parallel(docs.map(function(doc) {
return function(callback) {
var toAdd = new self.db(doc);
toAdd.save(callback);
}
}), function(err) {
callback(err, {success: true});
})
} else if (method === 'put') {
var docs = many ? body : [body];
Async.parallel(docs.map(function(doc) {
return function(callback) {
self.db.findOneAndUpdate(query, body, {upsert: true}).select(SELECT).exec(callback);
}
}), callback);
} else if (method === 'patch') {
if (many) {
self.db.update(query, body, {multi: true}).select(SELECT).exec(function(err) {
callback(err, {success: true});
})
} else {
self.db.findOneAndUpdate(query, body, {new: true}).select(SELECT).exec(callback);
}
} else if (method === 'delete') {
var remove = many ? self.db.remove : self.db.findOneAndRemove;
remove.apply(self.db, [query]).exec(function(err, thing) {
callback(err, thing);
})
} else {
throw new Error("Unsupported method:" + method);
}
}
var getRouteFunction = function(method, many) {
// Can be called with (path[, middleware...]) or (req, res, callback);
return function() {
var self = this;
arguments = Array.prototype.slice.call(arguments);
var path = arguments[0];
var expressPath = path.replace(/{(.*)}/g, ':$1');
var middleware = arguments.splice(1);
var options = typeof middleware[0] === 'object' ? middleware.shift() : {};
options = JSON.parse(JSON.stringify(options));
self.api.swaggerBuilder.addRoute({
method: method,
path: path,
collection: self.label,
many: many
}, options.swagger);
var sendResponse = typeof arguments[0] === 'string';
var options = sendResponse && typeof arguments[1] === 'object' ? arguments[1] : {};
var dbAction = function(req, res, next) {
var method = options.upsert ? 'put' : req.method.toLowerCase();
var query = req.query;

@@ -86,42 +127,40 @@ for (key in req.params) {

}
if (method === 'get') {
var find = many ? self.db.find : self.db.findOne;
find.apply(self.db, [query, SELECT]).exec(function(err, thing) {
if (err) res.status(500).json({error: err.toString()})
else if (!thing) res.status(404).json({error: 'Not Found'})
else res.json(thing);
})
} else if (method === 'post') {
var docs = many ? req.body : [req.body];
Async.parallel(docs.map(function(doc) {
return function(callback) {
var toAdd = new self.db(doc);
toAdd.save(callback);
self.queryDB(method, many, query, req.body, function(err, thing) {
if (err) res.status(500).json({error: err.toString()});
else if (!thing) res.status(404).json({error: 'Not Found'})
else if (sendResponse && method === 'get') {
if (many) thing = thing.map(function(t) { return t.toObject({versionKey: false}) });
else thing = thing.toObject({versionKey: false});
if (options.mapItem) {
if (many) thing = thing.map(options.mapItem);
else thing = options.mapItem(thing);
}
}), function(err) {
if (err) res.status(500).json({error: err.toString()})
else res.json({success: true})
})
} else if (method === 'patch') {
if (many) {
self.db.update(query, req.body, {multi: true}).select(SELECT).exec(function(err) {
if (err) res.status(500).json({error: err.toString()});
else res.json({success: true});
})
} else {
self.db.findOneAndUpdate(query, req.body, {new: true}).select(SELECT).exec(function(err, thing) {
if (err) res.status(500).json({error: err.toString()});
else if (!thing) res.status(404).json({error: 'Not Found'});
else res.json(thing);
});
removeMongoFields(thing);
res.json(thing);
}
} else if (method === 'delete') {
var remove = many ? self.db.remove : self.db.findOneAndRemove;
remove.apply(self.db, [query]).exec(function(err, thing) {
if (err) res.status(500).json({error: err.toString()});
else if (!thing) res.status(404).json({error: 'Not Found'});
else res.json({success: true});
})
}
else if (sendResponse) res.json({success: true})
else next(thing);
})
}
// If we get (req, res, callback) instead of a path, just apply
// dbAction. Otherwise delegate to the router.
if (!sendResponse) return dbAction.apply(self, arguments);
arguments = Array.prototype.slice.call(arguments);
var expressPath = arguments[0];
var keys = [];
PathToRegexp(expressPath, keys);
var swaggerPath = expressPath;
keys.forEach(function(key) {
swaggerPath = swaggerPath.replace(':' + key.name, '{' + key.name + '}');
});
var middleware = arguments.splice(1);
if (typeof middleware[0] === 'object') middleware.shift();
if (options.swagger) options.swagger = JSON.parse(JSON.stringify(options.swagger));
self.api.swaggerBuilder.addRoute({
method: method,
path: swaggerPath,
collection: self.label,
many: many
}, options.swagger);
var firstAction = function(req, res, next) {

@@ -137,3 +176,3 @@ next();

var methods = ['get', 'patch', 'post', 'delete'];
var methods = ['get', 'patch', 'put', 'post', 'delete'];
methods.forEach(function(method) {

@@ -140,0 +179,0 @@ Definition.prototype[method] = getRouteFunction(method);

{
"name": "jammin",
"version": "0.0.4",
"version": "0.0.5",
"description": "REST API Generator using Express and Mongoose",

@@ -14,3 +14,4 @@ "main": "index.js",

"express": "^4.12.3",
"mongoose": "^4.0.1"
"mongoose": "^4.0.1",
"path-to-regexp": "^1.0.3"
},

@@ -17,0 +18,0 @@ "devDependencies": {

@@ -22,3 +22,3 @@ ## Installation

API.define('Pet', PetSchema);
API.Pet.get('/pets/{name}');
API.Pet.get('/pets/:name');
API.Pet.post('/pets');

@@ -40,3 +40,3 @@

```js
API.Pet.get('/pet/{name}');
API.Pet.get('/pet/:name);
```

@@ -61,3 +61,3 @@ Use ```getMany``` to return an array of matching documents.

```js
API.Pet.patch('/pets/{name}');
API.Pet.patch('/pets/:name);
```

@@ -72,3 +72,3 @@ Use ```patchMany``` to update every matching item in the database.

```js
API.Pet.delete('/pets/{name}');
API.Pet.delete('/pets/:name);
```

@@ -166,3 +166,3 @@ Use deleteMany to delete every matching item in the database.

// Gets a pet by id.
API.pet.get('/pets/{id}');
API.pet.get('/pets/:id);

@@ -204,3 +204,3 @@ // Gets an array of pets that match the query.

// Changes a pet.
API.pet.put('/pets/{id}', authenticateUser, ensureOwnership)
API.pet.put('/pets/:id, authenticateUser, ensureOwnership)

@@ -211,3 +211,3 @@ // Changes every pet that matches the query.

// Deletes a pet by ID.
API.pet.delete('/pets/{id}', authenticateUser, ensureOwnership);
API.pet.delete('/pets/:id, authenticateUser, ensureOwnership);

@@ -214,0 +214,0 @@ // Deletes every pet that matches the query.

@@ -35,2 +35,17 @@ {

"type": "string"
},
"vaccinations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"date": {
"type": "string",
"format": "date"
}
}
}
}

@@ -53,3 +68,3 @@ }

"paths": {
"/user": {
"/users": {
"post": {

@@ -78,2 +93,28 @@ "parameters": [

}
},
"get": {
"description": "Retrieves an array of Users",
"parameters": [
{
"name": "username",
"in": "query",
"type": "string"
},
{
"name": "password_hash",
"in": "query",
"type": "string"
}
],
"responses": {
"200": {
"description": "An array of Users",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/User"
}
}
}
}
}

@@ -104,2 +145,7 @@ },

"type": "string"
},
{
"name": "vaccinations",
"in": "query",
"type": "array"
}

@@ -147,23 +193,13 @@ ],

},
"description": "Updates a Pet",
"description": "Adds an array of Pets",
"parameters": [
{
"name": "id",
"in": "path",
"type": "number"
},
{
"name": "name",
"in": "query",
"type": "string"
},
{
"name": "owner",
"in": "query",
"type": "string"
},
{
"name": "animalType",
"in": "query",
"type": "string"
"name": "body",
"in": "body",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
}

@@ -173,6 +209,3 @@ ],

"200": {
"description": "A Pet",
"schema": {
"$ref": "#/definitions/Pet"
}
"description": "Success"
}

@@ -186,23 +219,13 @@ }

},
"description": "Removes a Pet",
"description": "Adds an array of Pets",
"parameters": [
{
"name": "id",
"in": "path",
"type": "number"
},
{
"name": "name",
"in": "query",
"type": "string"
},
{
"name": "owner",
"in": "query",
"type": "string"
},
{
"name": "animalType",
"in": "query",
"type": "string"
"name": "body",
"in": "body",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
}

@@ -240,2 +263,7 @@ ],

"type": "string"
},
{
"name": "vaccinations",
"in": "query",
"type": "array"
}

@@ -284,23 +312,13 @@ ],

},
"description": "Updates an array of Pets",
"description": "Adds an array of Pets",
"parameters": [
{
"name": "id",
"in": "query",
"type": "number"
},
{
"name": "name",
"in": "query",
"type": "string"
},
{
"name": "owner",
"in": "query",
"type": "string"
},
{
"name": "animalType",
"in": "query",
"type": "string"
"name": "body",
"in": "body",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
}

@@ -319,5 +337,51 @@ ],

},
"description": "Removes an array of Pets",
"description": "Adds an array of Pets",
"parameters": [
{
"name": "body",
"in": "body",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
}
],
"responses": {
"200": {
"description": "Success"
}
}
}
},
"/search/pets": {
"get": {
"description": "Search all pets by name",
"parameters": [
{
"name": "q",
"in": "query",
"type": "string",
"description": "Any regex"
}
],
"responses": {
"200": {
"description": "An array of Pets",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
}
}
}
},
"/pet_types": {
"get": {
"description": "Retrieves an array of Pets",
"parameters": [
{
"name": "id",

@@ -341,20 +405,7 @@ "in": "query",

"type": "string"
}
],
"responses": {
"200": {
"description": "Success"
}
}
}
},
"/search/pets": {
"get": {
"description": "Search all pets by name",
"parameters": [
},
{
"name": "q",
"name": "vaccinations",
"in": "query",
"type": "string",
"description": "Any regex"
"type": "array"
}

@@ -361,0 +412,0 @@ ],

@@ -7,2 +7,3 @@ var FS = require('fs');

module.exports.listen = function(port) {
console.log('listening: ' + port);
App.listen(port || 3000);

@@ -13,3 +14,5 @@ }

API.Pet.db.remove({}, function(err) {
if (err) throw err;
API.User.db.remove({}, function(err) {
if (err) throw err;
callback();

@@ -44,3 +47,3 @@ })

username: {type: String, required: true, unique: true, match: /^\w+$/},
password_hash: {type: String, required: true},
password_hash: {type: String, required: true, select: false}
}

@@ -52,3 +55,7 @@

owner: String,
animalType: {type: String, default: 'unknown'}
animalType: {type: String, default: 'unknown'},
vaccinations: [{
name: String,
date: Date
}]
}

@@ -60,6 +67,6 @@

};
API.User.db.findOne(query, function(err, user) {
API.User.db.findOne(query).select('+password_hash').exec(function(err, user) {
if (err) {
res.status(500).json({error: err.toString()})
} else if (!user) {
} else if (!user || !user.password_hash) {
res.status(401).json({error: "Unknown user:" + query.username});

@@ -85,3 +92,3 @@ } else if (!Hash.verify(req.headers['password'], user.password_hash)) {

// Creates a new user.
API.User.post('/user', {
API.User.post('/users', {
swagger: {

@@ -104,4 +111,7 @@ parameters: [{

// Gets all users
API.User.getMany('/users');
// Gets a pet by id.
API.Pet.get('/pets/{id}');
API.Pet.get('/pets/:id');

@@ -126,3 +136,3 @@ // Gets an array of pets that match the query.

API.Pet.post('/pets/{id}', SwaggerLogin, authenticateUser, function(req, res, next) {
API.Pet.post('/pets/:id', {upsert: true, swagger: SwaggerLogin.swagger}, authenticateUser, function(req, res, next) {
req.body.owner = req.user.username;

@@ -150,3 +160,3 @@ req.body.id = req.params.id;

// Changes a pet.
API.Pet.patch('/pets/{id}', SwaggerLogin, authenticateUser, enforceOwnership);
API.Pet.patch('/pets/:id', SwaggerLogin, authenticateUser, enforceOwnership);

@@ -157,3 +167,3 @@ // Changes every pet that matches the query.

// Deletes a pet by ID.
API.Pet.delete('/pets/{id}', SwaggerLogin, authenticateUser, enforceOwnership);
API.Pet.delete('/pets/:id', SwaggerLogin, authenticateUser, enforceOwnership);

@@ -163,4 +173,12 @@ // Deletes every pet that matches the query.

API.router.get('/pet_count', function(req, res) {
API.Pet.getMany(req, res, function(pets) {
res.json({count: pets.length})
})
})
API.Pet.getMany('/pet_types', {mapItem: function(pet) {return pet.animalType}})
API.swagger('/swagger.json');
App.use('/api', API.router);

@@ -12,3 +12,23 @@ var FS = require('fs');

var PETS = [
{id: 0, name: "Pet0", owner: USER_1.username, animalType: "dog"},
{id: 1, name: "Pet1", owner: USER_1.username, animalType: "gerbil"},
{id: 2, name: "Pet2", owner: USER_2.username, animalType: "dog"},
{id: 3, name: "Pet3", owner: USER_1.username, animalType: "cat"},
{id: 4, name: "Pet4", owner: USER_1.username, animalType: "cat"},
{id: 5, name: "Pet5", owner: USER_1.username, animalType: "unknown"}
];
PETS.forEach(function(pet) {
pet.vaccinations = [];
});
var VACCINATIONS = [{name: 'Rabies', date: '1987-09-23T00:00:00.000Z'}];
var CurrentPets = [];
var successResponse = function(expectedBody, done) {
if (!done) {
done = expectedBody;
expectedBody = {success: true};
}
return function(err, res, body) {

@@ -50,3 +70,3 @@ if (body.error) console.log(body.error);

Request.post({
url: BASE_URL + '/user',
url: BASE_URL + '/users',
body: USER_1,

@@ -57,5 +77,12 @@ json: true

it('should not show password_hash', function(done) {
Request.get({
url: BASE_URL + '/users',
json: true,
}, successResponse([{username: USER_1.username}], done))
});
it('should not allow duplicate user names', function(done) {
Request.post({
url: BASE_URL + '/user',
url: BASE_URL + '/users',
body: USER_1,

@@ -68,3 +95,3 @@ json: true

Request.post({
url: BASE_URL + '/user',
url: BASE_URL + '/users',
body: USER_2,

@@ -76,5 +103,6 @@ json: true

it('should allow new pets', function(done) {
CurrentPets.push(PETS[1]);
Request.post({
url: BASE_URL + '/pets',
body: {id: 42, name: 'Lucy'},
body: {id: 1, name: PETS[1].name, animalType: PETS[1].animalType},
headers: USER_1,

@@ -86,5 +114,6 @@ json: true

it('should allow a second pet', function(done) {
CurrentPets.push(PETS[2]);
Request.post({
url: BASE_URL + '/pets',
body: {id: 43, name: 'Goose'},
body: {id: 2, name: PETS[2].name, animalType: PETS[2].animalType},
headers: USER_2,

@@ -95,6 +124,16 @@ json: true

it('should upsert on post', function(done) {
PETS[2].name = 'Goose';
Request.post({
url: BASE_URL + '/pets/' + PETS[2].id,
body: PETS[2],
headers: USER_2,
json: true
}, successResponse(null, done))
})
it('should not allow modifications from wrong user', function(done) {
Request({
method: 'patch',
url: BASE_URL + '/pets/42',
url: BASE_URL + '/pets/1',
headers: USER_2,

@@ -106,14 +145,10 @@ json: true

it('should allow modifications to pet', function(done) {
PETS[1].name = 'Loosey';
Request({
method: 'patch',
url: BASE_URL + '/pets/42',
url: BASE_URL + '/pets/1',
headers: USER_1,
body: {name: 'Loosey'},
body: {name: PETS[1].name},
json: true
}, successResponse({
id: 42,
name: "Loosey",
animalType: "unknown",
owner: USER_1.username
}, done));
}, successResponse(done));
})

@@ -124,8 +159,5 @@

url: BASE_URL + '/search/pets',
qs: {q: 'oos'},
qs: {q: 'oose'},
json: true
}, successResponse([
{id: 42, name: "Loosey", owner: USER_1.username, animalType: "unknown"},
{id: 43, name: "Goose", owner: USER_2.username, animalType: "unknown"}
], done))
}, successResponse([PETS[1], PETS[2]], done))
})

@@ -136,3 +168,3 @@

url: BASE_URL + '/pets',
body: {id: 42, name: 'Goose'},
body: {id: 1, name: 'Goose'},
headers: USER_1,

@@ -146,3 +178,3 @@ json: true

url: BASE_URL + '/pets',
body: {id: 43, name: 'Goose'},
body: {id: 55, name: 'Goose'},
json: true

@@ -155,3 +187,3 @@ }, failResponse(401, done));

method: 'delete',
url: BASE_URL + '/pets/42',
url: BASE_URL + '/pets/1',
json: true

@@ -164,6 +196,13 @@ }, failResponse(401, done));

method: 'delete',
url: BASE_URL + '/pets/42',
url: BASE_URL + '/pets/1',
headers: USER_2,
json: true
}, failResponse(404, done)); // TODO: should return 401
});
it('should not reflect bad delete', function(done) {
Request.get({
url: BASE_URL + '/pets/1',
json: true
}, successResponse(PETS[1], done));
})

@@ -174,3 +213,3 @@

method: 'delete',
url: BASE_URL + '/pets/42',
url: BASE_URL + '/pets/1',
headers: {

@@ -185,5 +224,6 @@ username: USER_1.username,

it('should allow deletes from owner', function(done) {
CurrentPets.shift();
Request({
method: 'delete',
url: BASE_URL + '/pets/42',
url: BASE_URL + '/pets/1',
headers: USER_1,

@@ -195,18 +235,7 @@ json: true

it('should allow batched adds of pets', function(done) {
CurrentPets.unshift(PETS[3], PETS[4], PETS[5]);
Request.post({
url: BASE_URL + '/pets',
headers: USER_1,
body: [{
id: 1,
name: "Pet1",
animalType: "cat",
}, {
id: 2,
name: "Pet2",
animalType: "cat",
}, {
id: 3,
name: "Pet3",
animalType: "cat",
}],
body: [PETS[3], PETS[4], PETS[5]],
json: true

@@ -217,2 +246,5 @@ }, successResponse(null, done))

it('should allow batched modification of pets', function(done) {
CurrentPets.forEach(function(pet) {
if (pet.owner == USER_1.username && pet.animalType === 'cat') pet.animalType = 'dog';
});
Request({

@@ -239,10 +271,38 @@ method: 'patch',

json: true
}, successResponse([
{id: 1, name: "Pet1", owner: USER_1.username, animalType: 'dog'},
{id: 2, name: "Pet2", owner: USER_1.username, animalType: 'dog'},
{id: 3, name: "Pet3", owner: USER_1.username, animalType: 'dog'},
], done))
}, successResponse(CurrentPets.filter(function(pet) {return pet.animalType === 'dog'}), done))
})
it('should support pet_count', function(done) {
Request.get({
url: BASE_URL + '/pet_count',
json: true
}, successResponse({count: CurrentPets.length}, done));
});
it('should support mapItem to get pet types', function(done) {
Request.get({
url: BASE_URL + '/pet_types',
json: true,
}, successResponse(CurrentPets.map(function(pet) {return pet.animalType}), done));
})
it('should allow adding a vaccination', function(done) {
PETS[3].vaccinations = VACCINATIONS;
Request.patch({
url: BASE_URL + '/pets/3',
headers: USER_1,
body: {vaccinations: VACCINATIONS},
json: true,
}, successResponse(done))
})
it('should reflect added vaccination', function(done) {
Request.get({
url: BASE_URL + '/pets/3',
json: true,
}, successResponse(PETS[3], done));
})
it('should allow batched deletes of pets', function(done) {
CurrentPets = CurrentPets.filter(function(pet) {return pet.animalType !== 'dog'});
Request({

@@ -249,0 +309,0 @@ method: 'delete',

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc