-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
first commit, combined swagger and node-neo4j template at a basic level
- Loading branch information
Showing
35 changed files
with
11,559 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Compiled source # | ||
################### | ||
*.com | ||
*.class | ||
*.dll | ||
*.exe | ||
*.o | ||
*.so | ||
|
||
# Packages # | ||
############ | ||
# it's better to unpack these files and commit the raw source | ||
# git has its own built in compression methods | ||
*.7z | ||
*.dmg | ||
*.gz | ||
*.iso | ||
*.jar | ||
*.rar | ||
*.tar | ||
*.zip | ||
|
||
# Logs and databases # | ||
###################### | ||
*.log | ||
*.sql | ||
*.sqlite | ||
|
||
# OS generated files # | ||
###################### | ||
.DS_Store* | ||
ehthumbs.db | ||
Icon? | ||
Thumbs.db | ||
*.swp | ||
node_modules | ||
.env | ||
.env_local | ||
.env_hosted | ||
.env_staging | ||
.env_development | ||
.env_production | ||
|
||
#directories# | ||
node_modules/ | ||
|
||
public/app/scripts/vendor/*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/** | ||
* Module dependencies. | ||
*/ | ||
|
||
var express = require('express') | ||
, url = require("url") | ||
, swagger = require("swagger-node-express") | ||
, http = require('http') | ||
, path = require('path') | ||
|
||
, routes = require('./routes') | ||
|
||
, PORT = process.env.PORT || 3000 | ||
, API_STRING = '/api' | ||
, BASE_URL = process.env.BASE_CALLBACK_URL || "http://localhost:"+PORT | ||
|
||
, app = express() | ||
, subpath = express(); | ||
|
||
|
||
app.use(API_STRING, subpath); | ||
|
||
var petResources = require("./swagger/model_resources"); | ||
|
||
// configure api subpath | ||
subpath.configure(function () { | ||
// subpath.use(express.bodyParser()); | ||
subpath.use(express.json()); | ||
subpath.use(express.methodOverride()); | ||
subpath.use(app.router); | ||
|
||
}); | ||
|
||
// all environments | ||
app.configure(function () { | ||
app.set('port', PORT); | ||
// app.set('views', __dirname + '/views'); | ||
// app.set('view engine', 'jade'); | ||
// app.use(express.favicon()); | ||
// app.use(express.static(path.join(__dirname, 'public'))); | ||
app.use(express.logger('dev')); | ||
|
||
// app.use(express.bodyParser()); // | ||
// app.use(express.urlencoded()); | ||
app.use(express.json()); | ||
|
||
app.use(express.methodOverride()); | ||
app.use(app.router); | ||
|
||
|
||
// development only | ||
if ('development' == app.get('env')) { | ||
app.use(express.errorHandler()); | ||
} | ||
|
||
// app.locals({ | ||
// title: 'Node-Neo4j-API' // default title | ||
// }); | ||
|
||
|
||
}); | ||
|
||
|
||
|
||
// Set the main handler in swagger to the express app | ||
swagger.setAppHandler(subpath); | ||
|
||
swagger.configureSwaggerPaths("", "/api-docs", ""); | ||
|
||
// default document middleware for swagger/index.html | ||
// app.use('/swagger', function (req, res, next) { | ||
// if (req.url === '/swagger') { | ||
// res.redirect('/swagger/'); | ||
// } | ||
// next(); | ||
// }); | ||
|
||
|
||
// This is a sample validator. It simply says that for _all_ POST, DELETE, PUT | ||
// methods, the header `api_key` OR query param `api_key` must be equal | ||
// to the string literal `special-key`. All other HTTP ops are A-OK | ||
swagger.addValidator( | ||
function validate(req, path, httpMethod) { | ||
// example, only allow POST for api_key="special-key" | ||
if ("POST" == httpMethod || "DELETE" == httpMethod || "PUT" == httpMethod) { | ||
var apiKey = req.headers["api_key"]; | ||
if (!apiKey) { | ||
apiKey = url.parse(req.url,true).query["api_key"]; } | ||
if ("special-key" == apiKey) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
return true; | ||
} | ||
); | ||
|
||
|
||
var models = require("./swagger/models"); | ||
|
||
// Add models and methods to swagger | ||
swagger.addModels(models) | ||
.addGet(petResources.findByTags) | ||
.addGet(petResources.findByStatus) | ||
.addGet(petResources.findById) | ||
.addPost(petResources.addPet) | ||
.addPut(petResources.updatePet) | ||
.addDelete(petResources.deletePet); | ||
|
||
|
||
// Configures the app's base path and api version. | ||
console.log(BASE_URL+API_STRING); | ||
swagger.configure(BASE_URL+API_STRING, "0.1"); | ||
|
||
|
||
// Routes | ||
|
||
// Serve up swagger ui at /docs via static route | ||
var docs_handler = express.static(__dirname + '/views/docs/'); | ||
app.get(/^\/docs(\/.*)?$/, function(req, res, next) { | ||
if (req.url === '/docs') { // express static barfs on root url w/o trailing slash | ||
res.writeHead(302, { 'Location' : req.url + '/' }); | ||
res.end(); | ||
return; | ||
} | ||
// take off leading /docs so that connect locates file correctly | ||
req.url = req.url.substr('/docs'.length); | ||
return docs_handler(req, res, next); | ||
}); | ||
|
||
// app.get('/', routes.site.index); | ||
|
||
// app.get('/users', routes.users.list); | ||
// app.post('/users', routes.users.create); | ||
// app.get('/users/:id', routes.users.show); | ||
// app.post('/users/:id', routes.users.edit); | ||
// app.del('/users/:id', routes.users.del); | ||
|
||
// app.post('/users/:id/follow', routes.users.follow); | ||
// app.post('/users/:id/unfollow', routes.users.unfollow); | ||
|
||
|
||
|
||
app.listen(app.get('port'), function() { | ||
console.log('Express server listening on port ' + app.get('port')); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
// user.js | ||
// User model logic. | ||
|
||
var neo4j = require('neo4j'); | ||
var db = new neo4j.GraphDatabase(process.env.NEO4J_URL || 'http://localhost:7474'); | ||
|
||
// constants: | ||
|
||
var INDEX_NAME = 'nodes'; | ||
var INDEX_KEY = 'type'; | ||
var INDEX_VAL = 'user'; | ||
|
||
var FOLLOWS_REL = 'follows'; | ||
|
||
// private constructor: | ||
|
||
var User = module.exports = function User(_node) { | ||
// all we'll really store is the node; the rest of our properties will be | ||
// derivable or just pass-through properties (see below). | ||
this._node = _node; | ||
}; | ||
|
||
// public instance properties: | ||
|
||
Object.defineProperty(User.prototype, 'id', { | ||
get: function () { return this._node.id; } | ||
}); | ||
|
||
Object.defineProperty(User.prototype, 'exists', { | ||
get: function () { return this._node.exists; } | ||
}); | ||
|
||
Object.defineProperty(User.prototype, 'name', { | ||
get: function () { | ||
return this._node.data['name']; | ||
}, | ||
set: function (name) { | ||
this._node.data['name'] = name; | ||
} | ||
}); | ||
|
||
// private instance methods: | ||
|
||
User.prototype._getFollowingRel = function (other, callback) { | ||
var query = [ | ||
'START user=node({userId}), other=node({otherId})', | ||
'MATCH (user) -[rel?:FOLLOWS_REL]-> (other)', | ||
'RETURN rel' | ||
].join('\n') | ||
.replace('FOLLOWS_REL', FOLLOWS_REL); | ||
|
||
var params = { | ||
userId: this.id, | ||
otherId: other.id, | ||
}; | ||
|
||
db.query(query, params, function (err, results) { | ||
if (err) return callback(err); | ||
var rel = results[0] && results[0]['rel']; | ||
callback(null, rel); | ||
}); | ||
}; | ||
|
||
// public instance methods: | ||
|
||
User.prototype.save = function (callback) { | ||
this._node.save(function (err) { | ||
callback(err); | ||
}); | ||
}; | ||
|
||
User.prototype.del = function (callback) { | ||
this._node.del(function (err) { | ||
callback(err); | ||
}, true); // true = yes, force it (delete all relationships) | ||
}; | ||
|
||
User.prototype.follow = function (other, callback) { | ||
this._node.createRelationshipTo(other._node, 'follows', {}, function (err, rel) { | ||
callback(err); | ||
}); | ||
}; | ||
|
||
User.prototype.unfollow = function (other, callback) { | ||
this._getFollowingRel(other, function (err, rel) { | ||
if (err) return callback(err); | ||
if (!rel) return callback(null); | ||
rel.del(function (err) { | ||
callback(err); | ||
}); | ||
}); | ||
}; | ||
|
||
// calls callback w/ (err, following, others) where following is an array of | ||
// users this user follows, and others is all other users minus him/herself. | ||
User.prototype.getFollowingAndOthers = function (callback) { | ||
// query all users and whether we follow each one or not: | ||
var query = [ | ||
'START user=node({userId}), other=node:INDEX_NAME(INDEX_KEY="INDEX_VAL")', | ||
'MATCH (user) -[rel?:FOLLOWS_REL]-> (other)', | ||
'RETURN other, COUNT(rel)' // COUNT(rel) is a hack for 1 or 0 | ||
].join('\n') | ||
.replace('INDEX_NAME', INDEX_NAME) | ||
.replace('INDEX_KEY', INDEX_KEY) | ||
.replace('INDEX_VAL', INDEX_VAL) | ||
.replace('FOLLOWS_REL', FOLLOWS_REL); | ||
|
||
var params = { | ||
userId: this.id, | ||
}; | ||
|
||
var user = this; | ||
db.query(query, params, function (err, results) { | ||
if (err) return callback(err); | ||
|
||
var following = []; | ||
var others = []; | ||
|
||
for (var i = 0; i < results.length; i++) { | ||
var other = new User(results[i]['other']); | ||
var follows = results[i]['COUNT(rel)']; | ||
|
||
if (user.id === other.id) { | ||
continue; | ||
} else if (follows) { | ||
following.push(other); | ||
} else { | ||
others.push(other); | ||
} | ||
} | ||
|
||
callback(null, following, others); | ||
}); | ||
}; | ||
|
||
// static methods: | ||
|
||
User.get = function (id, callback) { | ||
db.getNodeById(id, function (err, node) { | ||
if (err) return callback(err); | ||
callback(null, new User(node)); | ||
}); | ||
}; | ||
|
||
User.getAll = function (callback) { | ||
db.getIndexedNodes(INDEX_NAME, INDEX_KEY, INDEX_VAL, function (err, nodes) { | ||
// if (err) return callback(err); | ||
// FIXME the index might not exist in the beginning, so special-case | ||
// this error detection. warning: this is super brittle! | ||
// the better and correct thing is to either ensure the index exists | ||
// somewhere by creating it, or just use Neo4j's auto-indexing. | ||
// (the Heroku Neo4j add-on doesn't support auto-indexing currently.) | ||
if (err) return callback(null, []); | ||
var users = nodes.map(function (node) { | ||
return new User(node); | ||
}); | ||
callback(null, users); | ||
}); | ||
}; | ||
|
||
// creates the user and persists (saves) it to the db, incl. indexing it: | ||
User.create = function (data, callback) { | ||
var node = db.createNode(data); | ||
var user = new User(node); | ||
node.save(function (err) { | ||
if (err) return callback(err); | ||
node.index(INDEX_NAME, INDEX_KEY, INDEX_VAL, function (err) { | ||
if (err) return callback(err); | ||
callback(null, user); | ||
}); | ||
}); | ||
}; |
Oops, something went wrong.