From 1cfc8eda19176f9359a1bce6ff62d3c6680d3395 Mon Sep 17 00:00:00 2001 From: Nelson Silva Date: Wed, 13 Feb 2013 16:29:01 +0000 Subject: Initial work on swagger --- src/ep.json | 3 +- src/node/handler/APIHandler.js | 5 + src/node/hooks/express/swagger.js | 378 ++++++++++++++++++++++++++++++++++++++ src/package.json | 3 +- 4 files changed, 387 insertions(+), 2 deletions(-) create mode 100644 src/node/hooks/express/swagger.js diff --git a/src/ep.json b/src/ep.json index 89c8964a..eeb5c640 100644 --- a/src/ep.json +++ b/src/ep.json @@ -23,6 +23,7 @@ { "name": "adminsettings", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/adminsettings:expressCreateServer", "socketio": "ep_etherpad-lite/node/hooks/express/adminsettings:socketio" } - } + }, + { "name": "swagger", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/swagger:expressCreateServer" } } ] } diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index 8be5b5fe..4b7dd951 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -219,6 +219,9 @@ var version = // set the latest available API version here exports.latestApiVersion = '1.2.7'; +// exports the versions so it can be used by the new Swagger endpoint +exports.version = version; + /** * Handles a HTTP API call * @param functionName the name of the called function @@ -266,6 +269,8 @@ exports.handle = function(apiVersion, functionName, fields, req, res) } //check the api key! + fields["apikey"] = fields["apikey"] || fields["api_key"]; + if(fields["apikey"] != apikey.trim()) { res.send({code: 4, message: "no or wrong API Key", data: null}); diff --git a/src/node/hooks/express/swagger.js b/src/node/hooks/express/swagger.js new file mode 100644 index 00000000..cd0bf8ad --- /dev/null +++ b/src/node/hooks/express/swagger.js @@ -0,0 +1,378 @@ +var log4js = require('log4js'); +var express = require('express'); +var swagger = require("swagger-node-express"); +var apiHandler = require('../../handler/APIHandler'); +var apiCaller = require('./apicalls').apiCaller; +var settings = require("../../utils/Settings"); + +var versions = Object.keys(apiHandler.version) +var version = versions[versions.length - 1]; + +var swaggerModels = { + 'models': { + 'SessionInfo' : { + "id": 'SessionInfo', + "properties": { + "id": { + "type": "string" + }, + "authorID": { + "type": "string" + }, + "groupID":{ + "type":"string" + }, + "validUntil":{ + "type":"long" + } + } + }, + 'UserInfo' : { + "id": 'UserInfo', + "properties": { + "id": { + "type": "string" + }, + "colorId": { + "type": "string" + }, + "name":{ + "type":"string" + }, + "timestamp":{ + "type":"long" + } + } + }, + 'Message' : { + "id": 'Message', + "properties": { + "text": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "userName":{ + "type":"string" + }, + "time":{ + "type":"long" + } + } + } + } +}; + +function sessionListResponseProcessor(res) { + if (res.data) { + var sessions = []; + for (var sessionId in res.data) { + var sessionInfo = res.data[sessionId]; + sessionId["id"] = sessionId; + sessions.push(sessionInfo); + } + res.data = sessions; + } + + return res; +} + +// We'll add some more info to the API methods +var API = { + + // Group + "group": { + "create" : { + "func" : "createGroup", + "description": "creates a new group", + "response": {"groupID":{"type":"string"}} + }, + "createIfNotExistsFor" : { + "func": "createGroupIfNotExistsFor", + "description": "this functions helps you to map your application group ids to etherpad lite group ids", + "response": {"groupID":{"type":"string"}} + }, + "delete" : { + "func": "deleteGroup", + "description": "deletes a group" + }, + "listPads" : { + "func": "listPads", + "description": "returns all pads of this group", + "response": {"padIDs":{"type":"List", "items":{"type":"string"}}} + }, + "createPad" : { + "func": "createGroupPad", + "description": "creates a new pad in this group" + }, + "listSessions": { + "func": "listSessionsOfGroup", + "responseProcessor": sessionListResponseProcessor, + "description": "", + "response": {"sessions":{"type":"List", "items":{"type":"SessionInfo"}}} + }, + "list": { + "func": "listAllGroups", + "description": "", + "response": {"groupIDs":{"type":"List", "items":{"type":"string"}}} + }, + }, + + // Author + "author": { + "create" : { + "func" : "createAuthor", + "description": "creates a new author", + "response": {"authorID":{"type":"string"}} + }, + "createIfNotExistsFor": { + "func": "createAuthorIfNotExistsFor", + "description": "this functions helps you to map your application author ids to etherpad lite author ids", + "response": {"authorID":{"type":"string"}} + }, + "listPads": { + "func": "listPadsOfAuthor", + "description": "returns an array of all pads this author contributed to", + "response": {"padIDs":{"type":"List", "items":{"type":"string"}}} + }, + "listSessions": { + "func": "listSessionsOfAuthor", + "responseProcessor": sessionListResponseProcessor, + "description": "returns all sessions of an author", + "response": {"sessions":{"type":"List", "items":{"type":"SessionInfo"}}} + }, + "getName" : { + "func": "getAuthorName", + "description": "Returns the Author Name of the author", + "response": {"authorName":{"type":"string"}} + }, + }, + "session": { + "create" : { + "func": "createSession", + "description": "creates a new session. validUntil is an unix timestamp in seconds", + "response": {"sessionID":{"type":"string"}} + }, + "delete" : { + "func": "deleteSession", + "description": "deletes a session" + }, + "info": { + "func": "getSessionInfo", + "description": "returns informations about a session", + "response": {"authorID":{"type":"string"}, "groupID":{"type":"string"}, "validUntil":{"type":"long"}} + }, + }, + "pad": { + "listAll" : { + "func": "listAllPads", + "description": "list all the pads", + "response": {"padIDs":{"type":"List", "items": {"type" : "string"}}} + }, + "createDiffHTML" : { + "func" : "createDiffHTML", + "description": "", + "response": {} + }, + "create" : { + "func" : "createPad", + "description": "creates a new (non-group) pad. Note that if you need to create a group Pad, you should call createGroupPad", + }, + "getText" : { + "func" : "getText", + "description": "returns the text of a pad" + }, + "setText" : { + "func" : "setText", + "description": "sets the text of a pad", + "response": {"groupID":{"type":"string"}} + }, + "getHTML": { + "func" : "getHTML", + "description": "returns the text of a pad formatted as HTML", + "response": {"html":{"type":"string"}} + }, + "setHTML": { + "func" : "setHTML", + "description": "sets the text of a pad with HTML" + }, + "getRevisionsCount": { + "func" : "getRevisionsCount", + "description": "returns the number of revisions of this pad", + "response": {"revisions":{"type":"long"}} + }, + "getLastEdited": { + "func" : "getLastEdited", + "description": "returns the timestamp of the last revision of the pad", + "response": {"lastEdited":{"type":"long"}} + }, + "delete": { + "func" : "deletePad", + "description": "deletes a pad" + }, + "getReadOnlyID": { + "func" : "getReadOnlyID", + "description": "returns the read only link of a pad", + "response": {"readOnlyID":{"type":"string"}} + }, + "setPublicStatus": { + "func": "setPublicStatus", + "description": "sets a boolean for the public status of a pad" + }, + "getPublicStatus": { + "func": "getPublicStatus", + "description": "return true of false", + "response": {"publicStatus":{"type":"bool"}} + }, + "setPassword": { + "func": "setPassword", + "description": "returns ok or a error message" + }, + "isPasswordProtected": { + "func": "isPasswordProtected", + "description": "returns true or false", + "response": {"passwordProtection":{"type":"bool"}} + }, + "authors": { + "func": "listAuthorsOfPad", + "description": "returns an array of authors who contributed to this pad", + "response": {"authorIDs":{"type":"List", "items":{"type" : "string"}}} + }, + "usersCount": { + "func": "padUsersCount", + "description": "returns the number of user that are currently editing this pad", + "response": {"padUsersCount":{"type": "long"}} + }, + "users": { + "func": "padUsers", + "description": "returns the list of users that are currently editing this pad", + "response": {"padUsers":{"type":"Lists", "items":{"type": "UserInfo"}}} + }, + "sendClientsMessage": { + "func": "sendClientsMessage", + "description": "sends a custom message of type msg to the pad" + }, + "checkToken" : { + "func": "checkToken", + "description": "returns ok when the current api token is valid" + }, + "getChatHistory": { + "func": "getChatHistory", + "description": "returns the chat history", + "response": {"messages":{"type":"List", "items": {"type" : "Message"}}} + }, + "getChatHead": { + "func": "getChatHead", + "description": "returns the chatHead (last number of the last chat-message) of the pad", + "response": {"chatHead":{"type":"long"}} + } + } +}; + +function capitalise(string){ + return string.charAt(0).toUpperCase() + string.slice(1); +} + +for (var resource in API) { + for (var func in API[resource]) { + + // Add the response model + var responseModelId = capitalise(resource) + capitalise(func) + "Response"; + + swaggerModels['models'][responseModelId] = { + "id": responseModelId, + "properties": { + "code":{ + "type":"int" + }, + "message":{ + "type":"string" + } + } + }; + + // This returns some data + if (API[resource][func]["response"]) { + // Add the data model + var dataModelId = capitalise(resource) + capitalise(func) + "Data"; + swaggerModels['models'][dataModelId] = { + "id": dataModelId, + "properties": API[resource][func]["response"] + }; + + swaggerModels['models'][responseModelId]["properties"]["data"] = { + "type": dataModelId + }; + } + + // Store the response model id + API[resource][func]["responseClass"] = responseModelId; + + // get the api function + var apiFunc = apiHandler.version[version][API[resource][func]["func"]]; + + // Add the api function parameters + API[resource][func]["params"] = apiFunc.map( function(param) { + return swagger.queryParam(param, param, "string"); + }); + } +} + +exports.expressCreateServer = function (hook_name, args, cb) { + + // Let's put this under /rest for now + var subpath = express(); + + args.app.use(express.bodyParser()); + args.app.use("/rest", subpath); + + swagger.setAppHandler(subpath); + + swagger.addModels(swaggerModels); + + for (var resource in API) { + + for (var funcName in API[resource]) { + var func = API[resource][funcName]; + + var swaggerFunc = { + 'spec': { + "description" : func["description"], + "path" : "/" + resource + "/" + funcName, + "summary" : funcName, + "nickname" : funcName, + "method": "GET", + "params" : func["params"], + "responseClass" : func["responseClass"] + }, + 'action': (function(func, responseProcessor) { + return function (req,res) { + req.params.version = version; + req.params.func = func; // call the api function + + if (responseProcessor) { + //wrap the send function so we can process the response + res.__swagger_send = res.send; + res.send = function (response) { + response = responseProcessor(response); + res.__swagger_send(response); + } + } + apiCaller(req, res, req.query); + }; + })(func["func"], func["responseProcessor"]) // must use a closure here + }; + + swagger.addGet(swaggerFunc); + } + } + + swagger.setHeaders = function setHeaders(res) { + res.header('Access-Control-Allow-Origin', "*"); + }; + + swagger.configureSwaggerPaths("", "/api" , ""); + + swagger.configure("http://" + settings.ip + ":" + settings.port + "/rest", version); +} diff --git a/src/package.json b/src/package.json index 44d03d80..f9d7a7a4 100644 --- a/src/package.json +++ b/src/package.json @@ -36,7 +36,8 @@ "tinycon" : "0.0.1", "underscore" : "1.3.1", "unorm" : "1.0.0", - "languages4translatewiki" : "0.1.3" + "languages4translatewiki" : "0.1.3", + "swagger-node-express" : "1.2.3" }, "bin": { "etherpad-lite": "./node/server.js" }, "devDependencies": { -- cgit v1.2.3 From 8f279a67100f5225d05ee58fe90cb08fb6e9f119 Mon Sep 17 00:00:00 2001 From: Nelson Silva Date: Fri, 15 Feb 2013 14:10:03 +0000 Subject: Added some fixes to make it work with the codegen --- src/node/hooks/express/swagger.js | 103 ++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 33 deletions(-) diff --git a/src/node/hooks/express/swagger.js b/src/node/hooks/express/swagger.js index cd0bf8ad..3e06ed29 100644 --- a/src/node/hooks/express/swagger.js +++ b/src/node/hooks/express/swagger.js @@ -142,11 +142,18 @@ var API = { "description": "returns all sessions of an author", "response": {"sessions":{"type":"List", "items":{"type":"SessionInfo"}}} }, + // We need an operation that return a UserInfo so it can be picked up by the codegen :( "getName" : { "func": "getAuthorName", - "description": "Returns the Author Name of the author", - "response": {"authorName":{"type":"string"}} - }, + "description": "Returns the Author Name of the author", + "responseProcessor": function(response) { + if (response.data) { + response["info"] = {"name": response.data.authorName}; + delete response["data"]; + } + }, + "response": {"info":{"type":"UserInfo"}} + } }, "session": { "create" : { @@ -158,10 +165,18 @@ var API = { "func": "deleteSession", "description": "deletes a session" }, + // We need an operation that returns a SessionInfo so it can be picked up by the codegen :( "info": { "func": "getSessionInfo", - "description": "returns informations about a session", - "response": {"authorID":{"type":"string"}, "groupID":{"type":"string"}, "validUntil":{"type":"long"}} + "description": "returns informations about a session", + "responseProcessor": function(response) { + // move this to info + if (response.data) { + response["info"] = response.data; + delete response["data"]; + } + }, + "response": {"info":{"type":"SessionInfo"}} }, }, "pad": { @@ -181,12 +196,12 @@ var API = { }, "getText" : { "func" : "getText", - "description": "returns the text of a pad" + "description": "returns the text of a pad", + "response": {"text":{"type":"string"}} }, "setText" : { "func" : "setText", - "description": "sets the text of a pad", - "response": {"groupID":{"type":"string"}} + "description": "sets the text of a pad" }, "getHTML": { "func" : "getHTML", @@ -223,7 +238,7 @@ var API = { "getPublicStatus": { "func": "getPublicStatus", "description": "return true of false", - "response": {"publicStatus":{"type":"bool"}} + "response": {"publicStatus":{"type":"boolean"}} }, "setPassword": { "func": "setPassword", @@ -232,7 +247,7 @@ var API = { "isPasswordProtected": { "func": "isPasswordProtected", "description": "returns true or false", - "response": {"passwordProtection":{"type":"bool"}} + "response": {"passwordProtection":{"type":"boolean"}} }, "authors": { "func": "listAuthorsOfPad", @@ -247,7 +262,7 @@ var API = { "users": { "func": "padUsers", "description": "returns the list of users that are currently editing this pad", - "response": {"padUsers":{"type":"Lists", "items":{"type": "UserInfo"}}} + "response": {"padUsers":{"type":"List", "items":{"type": "UserInfo"}}} }, "sendClientsMessage": { "func": "sendClientsMessage", @@ -262,10 +277,18 @@ var API = { "description": "returns the chat history", "response": {"messages":{"type":"List", "items": {"type" : "Message"}}} }, + // We need an operation that returns a Message so it can be picked up by the codegen :( "getChatHead": { "func": "getChatHead", - "description": "returns the chatHead (last number of the last chat-message) of the pad", - "response": {"chatHead":{"type":"long"}} + "description": "returns the chatHead (chat-message) of the pad", + "responseProcessor": function(response) { + // move this to info + if (response.data) { + response["chatHead"] = {"time": response.data["chatHead"]}; + delete response["data"]; + } + }, + "response": {"chatHead":{"type":"Message"}} } } }; @@ -277,11 +300,8 @@ function capitalise(string){ for (var resource in API) { for (var func in API[resource]) { - // Add the response model - var responseModelId = capitalise(resource) + capitalise(func) + "Response"; - - swaggerModels['models'][responseModelId] = { - "id": responseModelId, + // The base response model + var responseModel = { "properties": { "code":{ "type":"int" @@ -292,20 +312,25 @@ for (var resource in API) { } }; - // This returns some data + var responseModelId = "Response"; + + // Add the data properties (if any) to the response if (API[resource][func]["response"]) { - // Add the data model - var dataModelId = capitalise(resource) + capitalise(func) + "Data"; - swaggerModels['models'][dataModelId] = { - "id": dataModelId, - "properties": API[resource][func]["response"] - }; + // This is a specific response so let's set a new id + responseModelId = capitalise(resource) + capitalise(func) + "Response"; - swaggerModels['models'][responseModelId]["properties"]["data"] = { - "type": dataModelId - }; + for(var prop in API[resource][func]["response"]) { + var propType = API[resource][func]["response"][prop]; + responseModel["properties"][prop] = propType; + } } + // Add the id + responseModel["id"] = responseModelId; + + // Add this to the swagger models + swaggerModels['models'][responseModelId] = responseModel; + // Store the response model id API[resource][func]["responseClass"] = responseModelId; @@ -351,14 +376,26 @@ exports.expressCreateServer = function (hook_name, args, cb) { req.params.version = version; req.params.func = func; // call the api function - if (responseProcessor) { - //wrap the send function so we can process the response - res.__swagger_send = res.send; - res.send = function (response) { + //wrap the send function so we can process the response + res.__swagger_send = res.send; + res.send = function (response) { + // ugly but we need to get this as json + response = JSON.parse(response); + // process the response if needed + if (responseProcessor) { response = responseProcessor(response); - res.__swagger_send(response); } + // Let's move everything out of "data" + if (response.data) { + for(var prop in response.data) { + response[prop] = response.data[prop]; + delete response.data; + } + } + response = JSON.stringify(response); + res.__swagger_send(response); } + apiCaller(req, res, req.query); }; })(func["func"], func["responseProcessor"]) // must use a closure here -- cgit v1.2.3 From a5987285e01413ab9f0921011ab57d2615025b63 Mon Sep 17 00:00:00 2001 From: "nelson.silva" Date: Sat, 16 Feb 2013 14:57:09 +0000 Subject: Multiple REST endpoints (one per version) --- src/node/hooks/express/swagger.js | 226 ++++++++++++++++++++------------------ 1 file changed, 121 insertions(+), 105 deletions(-) diff --git a/src/node/hooks/express/swagger.js b/src/node/hooks/express/swagger.js index 3e06ed29..f4fc5cff 100644 --- a/src/node/hooks/express/swagger.js +++ b/src/node/hooks/express/swagger.js @@ -1,13 +1,9 @@ var log4js = require('log4js'); var express = require('express'); -var swagger = require("swagger-node-express"); var apiHandler = require('../../handler/APIHandler'); var apiCaller = require('./apicalls').apiCaller; var settings = require("../../utils/Settings"); -var versions = Object.keys(apiHandler.version) -var version = versions[versions.length - 1]; - var swaggerModels = { 'models': { 'SessionInfo' : { @@ -83,14 +79,14 @@ var API = { // Group "group": { - "create" : { + "create" : { "func" : "createGroup", - "description": "creates a new group", + "description": "creates a new group", "response": {"groupID":{"type":"string"}} }, "createIfNotExistsFor" : { "func": "createGroupIfNotExistsFor", - "description": "this functions helps you to map your application group ids to etherpad lite group ids", + "description": "this functions helps you to map your application group ids to etherpad lite group ids", "response": {"groupID":{"type":"string"}} }, "delete" : { @@ -98,23 +94,23 @@ var API = { "description": "deletes a group" }, "listPads" : { - "func": "listPads", - "description": "returns all pads of this group", + "func": "listPads", + "description": "returns all pads of this group", "response": {"padIDs":{"type":"List", "items":{"type":"string"}}} }, "createPad" : { - "func": "createGroupPad", + "func": "createGroupPad", "description": "creates a new pad in this group" }, "listSessions": { "func": "listSessionsOfGroup", "responseProcessor": sessionListResponseProcessor, - "description": "", + "description": "", "response": {"sessions":{"type":"List", "items":{"type":"SessionInfo"}}} }, "list": { "func": "listAllGroups", - "description": "", + "description": "", "response": {"groupIDs":{"type":"List", "items":{"type":"string"}}} }, }, @@ -122,24 +118,24 @@ var API = { // Author "author": { "create" : { - "func" : "createAuthor", - "description": "creates a new author", + "func" : "createAuthor", + "description": "creates a new author", "response": {"authorID":{"type":"string"}} }, "createIfNotExistsFor": { "func": "createAuthorIfNotExistsFor", - "description": "this functions helps you to map your application author ids to etherpad lite author ids", + "description": "this functions helps you to map your application author ids to etherpad lite author ids", "response": {"authorID":{"type":"string"}} }, "listPads": { "func": "listPadsOfAuthor", - "description": "returns an array of all pads this author contributed to", + "description": "returns an array of all pads this author contributed to", "response": {"padIDs":{"type":"List", "items":{"type":"string"}}} }, "listSessions": { "func": "listSessionsOfAuthor", "responseProcessor": sessionListResponseProcessor, - "description": "returns all sessions of an author", + "description": "returns all sessions of an author", "response": {"sessions":{"type":"List", "items":{"type":"SessionInfo"}}} }, // We need an operation that return a UserInfo so it can be picked up by the codegen :( @@ -158,7 +154,7 @@ var API = { "session": { "create" : { "func": "createSession", - "description": "creates a new session. validUntil is an unix timestamp in seconds", + "description": "creates a new session. validUntil is an unix timestamp in seconds", "response": {"sessionID":{"type":"string"}} }, "delete" : { @@ -167,7 +163,7 @@ var API = { }, // We need an operation that returns a SessionInfo so it can be picked up by the codegen :( "info": { - "func": "getSessionInfo", + "func": "getSessionInfo", "description": "returns informations about a session", "responseProcessor": function(response) { // move this to info @@ -177,22 +173,22 @@ var API = { } }, "response": {"info":{"type":"SessionInfo"}} - }, + } }, "pad": { - "listAll" : { - "func": "listAllPads", - "description": "list all the pads", + "listAll" : { + "func": "listAllPads", + "description": "list all the pads", "response": {"padIDs":{"type":"List", "items": {"type" : "string"}}} }, "createDiffHTML" : { - "func" : "createDiffHTML", - "description": "", + "func" : "createDiffHTML", + "description": "", "response": {} }, - "create" : { + "create" : { "func" : "createPad", - "description": "creates a new (non-group) pad. Note that if you need to create a group Pad, you should call createGroupPad", + "description": "creates a new (non-group) pad. Note that if you need to create a group Pad, you should call createGroupPad" }, "getText" : { "func" : "getText", @@ -205,7 +201,7 @@ var API = { }, "getHTML": { "func" : "getHTML", - "description": "returns the text of a pad formatted as HTML", + "description": "returns the text of a pad formatted as HTML", "response": {"html":{"type":"string"}} }, "setHTML": { @@ -214,12 +210,12 @@ var API = { }, "getRevisionsCount": { "func" : "getRevisionsCount", - "description": "returns the number of revisions of this pad", + "description": "returns the number of revisions of this pad", "response": {"revisions":{"type":"long"}} }, "getLastEdited": { "func" : "getLastEdited", - "description": "returns the timestamp of the last revision of the pad", + "description": "returns the timestamp of the last revision of the pad", "response": {"lastEdited":{"type":"long"}} }, "delete": { @@ -228,16 +224,16 @@ var API = { }, "getReadOnlyID": { "func" : "getReadOnlyID", - "description": "returns the read only link of a pad", + "description": "returns the read only link of a pad", "response": {"readOnlyID":{"type":"string"}} }, "setPublicStatus": { - "func": "setPublicStatus", + "func": "setPublicStatus", "description": "sets a boolean for the public status of a pad" }, "getPublicStatus": { "func": "getPublicStatus", - "description": "return true of false", + "description": "return true of false", "response": {"publicStatus":{"type":"boolean"}} }, "setPassword": { @@ -245,27 +241,27 @@ var API = { "description": "returns ok or a error message" }, "isPasswordProtected": { - "func": "isPasswordProtected", - "description": "returns true or false", + "func": "isPasswordProtected", + "description": "returns true or false", "response": {"passwordProtection":{"type":"boolean"}} }, "authors": { - "func": "listAuthorsOfPad", - "description": "returns an array of authors who contributed to this pad", + "func": "listAuthorsOfPad", + "description": "returns an array of authors who contributed to this pad", "response": {"authorIDs":{"type":"List", "items":{"type" : "string"}}} }, "usersCount": { - "func": "padUsersCount", - "description": "returns the number of user that are currently editing this pad", + "func": "padUsersCount", + "description": "returns the number of user that are currently editing this pad", "response": {"padUsersCount":{"type": "long"}} }, "users": { - "func": "padUsers", - "description": "returns the list of users that are currently editing this pad", + "func": "padUsers", + "description": "returns the list of users that are currently editing this pad", "response": {"padUsers":{"type":"List", "items":{"type": "UserInfo"}}} }, "sendClientsMessage": { - "func": "sendClientsMessage", + "func": "sendClientsMessage", "description": "sends a custom message of type msg to the pad" }, "checkToken" : { @@ -273,13 +269,13 @@ var API = { "description": "returns ok when the current api token is valid" }, "getChatHistory": { - "func": "getChatHistory", - "description": "returns the chat history", + "func": "getChatHistory", + "description": "returns the chat history", "response": {"messages":{"type":"List", "items": {"type" : "Message"}}} }, // We need an operation that returns a Message so it can be picked up by the codegen :( "getChatHead": { - "func": "getChatHead", + "func": "getChatHead", "description": "returns the chatHead (chat-message) of the pad", "responseProcessor": function(response) { // move this to info @@ -334,82 +330,102 @@ for (var resource in API) { // Store the response model id API[resource][func]["responseClass"] = responseModelId; - // get the api function - var apiFunc = apiHandler.version[version][API[resource][func]["func"]]; + } +} - // Add the api function parameters - API[resource][func]["params"] = apiFunc.map( function(param) { - return swagger.queryParam(param, param, "string"); - }); +function newSwagger() { + var swagger_module = require.resolve("swagger-node-express"); + if (require.cache[swagger_module]) { + // delete the child modules from cache + require.cache[swagger_module].children.forEach(function(m) {delete require.cache[m.id];}); + // delete the module from cache + delete require.cache[swagger_module]; } + return require("swagger-node-express"); } exports.expressCreateServer = function (hook_name, args, cb) { - // Let's put this under /rest for now - var subpath = express(); + for (var version in apiHandler.version) { + + var swagger = newSwagger(); + var basePath = "/rest/" + version; - args.app.use(express.bodyParser()); - args.app.use("/rest", subpath); + // Let's put this under /rest for now + var subpath = express(); - swagger.setAppHandler(subpath); + args.app.use(express.bodyParser()); + args.app.use(basePath, subpath); - swagger.addModels(swaggerModels); + swagger.setAppHandler(subpath); - for (var resource in API) { + swagger.addModels(swaggerModels); - for (var funcName in API[resource]) { - var func = API[resource][funcName]; + for (var resource in API) { - var swaggerFunc = { - 'spec': { - "description" : func["description"], - "path" : "/" + resource + "/" + funcName, - "summary" : funcName, - "nickname" : funcName, - "method": "GET", - "params" : func["params"], - "responseClass" : func["responseClass"] - }, - 'action': (function(func, responseProcessor) { - return function (req,res) { - req.params.version = version; - req.params.func = func; // call the api function + for (var funcName in API[resource]) { + var func = API[resource][funcName]; + + // get the api function + var apiFunc = apiHandler.version[version][func["func"]]; + + // Skip this one if it does not exist in the version + if(!apiFunc) { + continue; + } + + var swaggerFunc = { + 'spec': { + "description" : func["description"], + "path" : "/" + resource + "/" + funcName, + "summary" : funcName, + "nickname" : funcName, + "method": "GET", + "params" : apiFunc.map( function(param) { + return swagger.queryParam(param, param, "string"); + }), + "responseClass" : func["responseClass"] + }, + 'action': (function(func, responseProcessor) { + return function (req,res) { + req.params.version = version; + req.params.func = func; // call the api function - //wrap the send function so we can process the response - res.__swagger_send = res.send; - res.send = function (response) { - // ugly but we need to get this as json - response = JSON.parse(response); - // process the response if needed - if (responseProcessor) { - response = responseProcessor(response); - } - // Let's move everything out of "data" - if (response.data) { - for(var prop in response.data) { - response[prop] = response.data[prop]; - delete response.data; + //wrap the send function so we can process the response + res.__swagger_send = res.send; + res.send = function (response) { + // ugly but we need to get this as json + response = JSON.parse(response); + // process the response if needed + if (responseProcessor) { + response = responseProcessor(response); + } + // Let's move everything out of "data" + if (response.data) { + for(var prop in response.data) { + response[prop] = response.data[prop]; + delete response.data; + } } - } - response = JSON.stringify(response); - res.__swagger_send(response); - } + response = JSON.stringify(response); + res.__swagger_send(response); + }; - apiCaller(req, res, req.query); - }; - })(func["func"], func["responseProcessor"]) // must use a closure here - }; + apiCaller(req, res, req.query); + }; + })(func["func"], func["responseProcessor"]) // must use a closure here + }; - swagger.addGet(swaggerFunc); + swagger.addGet(swaggerFunc); + } } - } - swagger.setHeaders = function setHeaders(res) { - res.header('Access-Control-Allow-Origin', "*"); - }; + swagger.setHeaders = function setHeaders(res) { + res.header('Access-Control-Allow-Origin', "*"); + }; - swagger.configureSwaggerPaths("", "/api" , ""); - - swagger.configure("http://" + settings.ip + ":" + settings.port + "/rest", version); -} + swagger.configureSwaggerPaths("", "/api" , ""); + + swagger.configure("http://" + settings.ip + ":" + settings.port + basePath, version); + } +}; -- cgit v1.2.3