forked from loafle/openapi-generator-original
Nodejs express js packages update (#5675)
* Updated to new nodejs packages, depending heavily on express-openapi-validator. Requires quite a change in code. Updated the business-logic in the controllers/Controller.js file. Logger now records also timestamp of events. Files are uploaded according to definition in config.js file * Removed commented-out code; Changed openApi document extensions to suit new express-openapi-validator definition; multipart and file uploading is supported now; Automatic response returns the values the were sent in the request * fixed README documentation, fixed a mistage in package.json/mustache * added generated files that were created when running the ./bin/test file
This commit is contained in:
@@ -269,7 +269,7 @@ public class NodeJSExpressServerCodegen extends DefaultCodegen implements Codege
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static List<Map<String, Object>> getOperations(Map<String, Object> objs) {
|
||||
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
|
||||
List<Map<String, Object>> result = new ArrayList<>();
|
||||
Map<String, Object> apiInfo = (Map<String, Object>) objs.get("apiInfo");
|
||||
List<Map<String, Object>> apis = (List<Map<String, Object>>) apiInfo.get("apis");
|
||||
for (Map<String, Object> api : apis) {
|
||||
@@ -285,9 +285,9 @@ public class NodeJSExpressServerCodegen extends DefaultCodegen implements Codege
|
||||
opsByPath.put(op.path, op);
|
||||
}
|
||||
|
||||
List<Map<String, Object>> opsByPathList = new ArrayList<Map<String, Object>>();
|
||||
List<Map<String, Object>> opsByPathList = new ArrayList<>();
|
||||
for (Entry<String, Collection<CodegenOperation>> entry : opsByPath.asMap().entrySet()) {
|
||||
Map<String, Object> opsByPathEntry = new HashMap<String, Object>();
|
||||
Map<String, Object> opsByPathEntry = new HashMap<>();
|
||||
opsByPathList.add(opsByPathEntry);
|
||||
opsByPathEntry.put("path", entry.getKey());
|
||||
opsByPathEntry.put("operation", entry.getValue());
|
||||
@@ -369,14 +369,18 @@ public class NodeJSExpressServerCodegen extends DefaultCodegen implements Codege
|
||||
operation.setOperationId(getOrGenerateOperationId(operation, pathname, method.toString()));
|
||||
}
|
||||
// add x-openapi-router-controller
|
||||
// if (operation.getExtensions() == null ||
|
||||
// operation.getExtensions().get("x-openapi-router-controller") == null) {
|
||||
// operation.addExtension("x-openapi-router-controller", sanitizeTag(tag) + "Controller");
|
||||
// }
|
||||
// // add x-openapi-router-service
|
||||
// if (operation.getExtensions() == null ||
|
||||
// operation.getExtensions().get("x-openapi-router-service") == null) {
|
||||
// operation.addExtension("x-openapi-router-service", sanitizeTag(tag) + "Service");
|
||||
// }
|
||||
if (operation.getExtensions() == null ||
|
||||
operation.getExtensions().get("x-openapi-router-controller") == null) {
|
||||
operation.addExtension("x-openapi-router-controller", sanitizeTag(tag) + "Controller");
|
||||
}
|
||||
// add x-openapi-router-service
|
||||
if (operation.getExtensions() == null ||
|
||||
operation.getExtensions().get("x-openapi-router-service") == null) {
|
||||
operation.addExtension("x-openapi-router-service", sanitizeTag(tag) + "Service");
|
||||
operation.getExtensions().get("x-eov-operation-handler") == null) {
|
||||
operation.addExtension("x-eov-operation-handler", "controllers/" + sanitizeTag(tag) + "Controller");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,58 @@
|
||||
{{=<% %>=}}
|
||||
|
||||
# OpenAPI Generated JavaScript/Express Server
|
||||
|
||||
## Overview
|
||||
This server was generated using the [OpenAPI Generator](https://openapi-generator.tech) project. The code generator, and it's generated code allows you to develop your system with an API-First attitude, where the API contract is the anchor and definer of your project, and your code and business-logic aims to complete and comply to the terms in the API contract.
|
||||
|
||||
### prerequisites
|
||||
- NodeJS >= 10.4
|
||||
- NodeJS >= 10.6
|
||||
- NPM >= 6.10.0
|
||||
|
||||
The code was written on a mac, so assuming all should work smoothly on Linux-based computers. However, there is no reason not to run this library on Windows-based machines. If you find an OS-related problem, please open an issue and it will be resolved.
|
||||
|
||||
### Running the server
|
||||
To run the server, run:
|
||||
|
||||
```
|
||||
npm start
|
||||
```
|
||||
### View and test the API
|
||||
You can see the API documentation, and check the available endpoints by going to http://localhost:3000/api-docs/. Endpoints that require security need to have security handlers configured before they can return a successful response. At this point they will return [ a response code of 401](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401).
|
||||
##### At this stage the server does not support document body sent in xml format. Forms will be supported in the near future.
|
||||
### Running the server
|
||||
#### This is a long read, but there's a lot to understand. Please take the time to go through this.
|
||||
1. Use the OpenAPI Generator to generate your application:
|
||||
Assuming you have Java (1.8+), and [have the jar](https://github.com/openapitools/openapi-generator#13---download-jar) to generate the application, run:
|
||||
```java -jar {path_to_jar_file} generate -g nodejs-express-server -i {openapi yaml/json file} -o {target_directory_where_the_app_will_be_installed} ```
|
||||
If you do not have the jar, or do not want to run Java from your local machine, follow instructions on the [OpenAPITools page](https://github.com/openapitools/openapi-generator). You can run the script online, on docker, and various other ways.
|
||||
2. Go to the generated directory you defined. There's a fully working NodeJS-ExpressJs server waiting for you. This is important - the code is yours to change and update! Look at config.js and see that the settings there are ok with you - the server will run on port 3000, and files will be uploaded to a new directory 'uploaded_files'.
|
||||
3. The server will base itself on an openapi.yaml file which is located under /api/openapi.yaml. This is not exactly the same file that you used to generate the app:
|
||||
I. If you have `application/json` contentBody that was defined inside the path object - the generate will have moved it to the components/schemas section of the openapi document.
|
||||
II. Every process has a new element added to it - `x-eov-operation-handler: controllers/PetController` which directs the call to that file.
|
||||
III. We have a Java application that translates the operationId to a method, and a nodeJS script that does the same process to call that method. Both are converting the method to `camelCase`, but might have discrepancy. Please pay attention to the operationID names, and see that they are represented in the `controllers` and `services` directories.
|
||||
4. Take the time to understand the structure of the application. There might be bugs, and there might be settings and business-logic that does not meet your expectation. Instead of dumping this solution and looking for something else - see if you can make the generated code work for you.
|
||||
To keep the explanation short (a more detailed explanation will follow): Application starts with a call to index.js (this is where you will plug in the db later). It calls expressServer.js which is where the express.js and openapi-validator kick in. This is an important file. Learn it. All calls to endpoints that were configured in the openapi.yaml document go to `controllers/{name_of_tag_which_the_operation_was_associated_with}.js`, which is a very small method. All the business-logic lies in `controllers/Controller.js`, and from there - to `services/{name_of_tag_which_the_operation_was_associated_with}.js`.
|
||||
|
||||
### Node version and guidelines
|
||||
The code was written using Node version 10.6, and complies to the [Airbnb .eslint guiding rules](https://github.com/airbnb/javascript).
|
||||
5. Once you've understood what is *going* to happen, launch the app and ensure everything is working as expected:
|
||||
```
|
||||
npm start
|
||||
```
|
||||
### Tests
|
||||
Unfortunately, I have not written any unit-tests. Those will come in the future. However, the package does come with all that is needed to write and run tests - mocha and sinon and the related libraries are included in the package.js and will be installed upon npm install command
|
||||
|
||||
### View and test the API
|
||||
(Assuming no changes were made to config.js)
|
||||
|
||||
1. API documentation, and to check the available endpoints:
|
||||
http://localhost:3000/api-docs/. To
|
||||
2. Download the oepnapi.yaml document: http://localhost:3000/openapi.
|
||||
3. Every call to an endpoint that was defined in the openapi document will return a 200 and a list of all the parameters and objects that were sent in the request.
|
||||
4. Endpoints that require security need to have security handlers configured before they can return a successful response. At this point they will return [ a response code of 401](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401).
|
||||
5. ##### At this stage the server does not support document body sent in xml format.
|
||||
|
||||
### Node version and guidelines
|
||||
The code was written using Node version 10.6, and complies to the [Airbnb .eslint guiding rules](https://github.com/airbnb/javascript).
|
||||
|
||||
### Project Files
|
||||
#### Root Directory:
|
||||
In the root directory we have (besides package.json, config.js, and log files):
|
||||
- **logger.js** - where we define the logger for the project. The project uses winston, but the purpose of this file is to enable users to change and modify their own logger behavior.
|
||||
- **index.js** - This is the project's 'main' file, and from here we launch the application. This is a very short and concise file, and the idea behind launching from this short file is to allow use-cases of launching the server with different parameters (changing config and/or logger) without affecting the rest of the code.
|
||||
- **index.js** - This is the project's 'main' file, and from here we launch the application. This is a very short and concise file, and the idea behind launching from this short file is to allow use-cases of launching the server with different parameters (changing config and/or logger) without affecting the rest of the code.
|
||||
- **expressServer.js** - The core of the Express.js server. This is where the express server is initialized, together with the OpenAPI validator, OpenAPI UI, and other libraries needed to start our server. If we want to add external links, that's where they would go. Our project uses the [express-openapi-validator](https://www.npmjs.com/package/express-openapi-validator) library that acts as a first step in the routing process - requests that are directed to paths defined in the `openapi.yaml` file are caught by this process, and it's parameters and bodyContent are validated against the schema. A successful result of this validation will be a new 'openapi' object added to the request. If the path requested is not part of the openapi.yaml file, the validator ignores the request and passes it on, as is, down the flow of the Express server.
|
||||
|
||||
#### api/
|
||||
- **openapi.yaml** - This is the OpenAPI contract to which this server will comply. The file was generated using the codegen, and should contain everything needed to run the API Gateway - no references to external models/schemas.
|
||||
- **openapi.yaml** - This is the OpenAPI contract to which this server will comply. The file was generated using the codegen, and should contain everything needed to run the API Gateway - no references to external models/schemas.
|
||||
|
||||
#### utils/
|
||||
Currently a single file:
|
||||
@@ -39,11 +60,11 @@ Currently a single file:
|
||||
- **openapiRouter.js** - This is where the routing to our back-end code happens. If the request object includes an ```openapi``` object, it picks up the following values (that are part of the ```openapi.yaml``` file): 'x-openapi-router-controller', and 'x-openapi-router-service'. These variables are names of files/classes in the controllers and services directories respectively. The operationId of the request is also extracted. The operationId is a method in the controller and the service that was generated as part of the codegen process. The routing process sends the request and response objects to the controller, which will extract the expected variables from the request, and send it to be processed by the service, returning the response from the service to the caller.
|
||||
|
||||
#### controllers/
|
||||
After validating the request, and ensuring this belongs to our API gateway, we send the request to a `controller`, where the variables and parameters are extracted from the request and sent to the relevant `service` for processing. The `controller` handles the response from the `service` and builds the appropriate HTTP response to be sent back to the user.
|
||||
After validating the request, and ensuring this belongs to our API gateway, we send the request to a `controller`, where the variables and parameters are extracted from the request and sent to the relevant `service` for processing. The `controller` handles the response from the `service` and builds the appropriate HTTP response to be sent back to the user.
|
||||
|
||||
- **index.js** - load all the controllers that were generated for this project, and export them to be used dynamically by the `openapiRouter.js`. If you would like to customize your controller, it is advised that you link to your controller here, and ensure that the codegen does not rewrite this file.
|
||||
|
||||
- **Controller.js** - The core processor of the generated controllers. The generated controllers are designed to be as slim and generic as possible, referencing to the `Controller.js` for the business logic of parsing the needed variables and arguments from the request, and for building the HTTP response which will be sent back. The `Controller.js` is a class with static methods.
|
||||
- **Controller.js** - The core processor of the generated controllers. The generated controllers are designed to be as slim and generic as possible, referencing to the `Controller.js` for the business logic of parsing the needed variables and arguments from the request, and for building the HTTP response which will be sent back. The `Controller.js` is a class with static methods.
|
||||
|
||||
- **{{x-openapi-router-controller}}.js** - auto-generated code, processing all the operations. The Controller is a class that is constructed with the service class it will be sending the request to. Every request defined by the `openapi.yaml` has an operationId. The operationId is the name of the method that will be called. Every method receives the request and response, and calls the `Controller.js` to process the request and response, adding the service method that should be called for the actual business-logic processing.
|
||||
|
||||
@@ -67,6 +88,3 @@ Future tests should be written to ensure that the response of every request sent
|
||||
|
||||
#### models/
|
||||
Currently a concept awaiting feedback. The idea is to have the objects defined in the openapi.yaml act as models which are passed between the different modules. This will conform the programmers to interact using defined objects, rather than loosley-defined JSON objects. Given the nature of JavaScript progrmmers, who want to work with their own bootstrapped parameters, this concept might not work. Keeping this here for future discussion and feedback.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@ const config = {
|
||||
URL_PATH: 'http://localhost',
|
||||
BASE_VERSION: 'v2',
|
||||
CONTROLLER_DIRECTORY: path.join(__dirname, 'controllers'),
|
||||
PROJECT_DIR: __dirname,
|
||||
};
|
||||
config.OPENAPI_YAML = path.join(config.ROOT_DIR, 'api', 'openapi.yaml');
|
||||
config.FULL_PATH = `${config.URL_PATH}:${config.URL_PORT}/${config.BASE_VERSION}`;
|
||||
config.FILE_UPLOAD_PATH = path.join(config.PROJECT_DIR, 'uploaded_files');
|
||||
|
||||
module.exports = config;
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
/**
|
||||
* The {{{classname}}}Controller file is a very simple one, which does not need to be changed manually,
|
||||
* unless there's a case where business logic reoutes the request to an entity which is not
|
||||
* the service.
|
||||
* The heavy lifting of the Controller item is done in Request.js - that is where request
|
||||
* parameters are extracted and sent to the service, and where response is handled.
|
||||
*/
|
||||
|
||||
const Controller = require('./Controller');
|
||||
|
||||
class {{{classname}}}Controller {
|
||||
constructor(Service) {
|
||||
this.service = Service;
|
||||
}
|
||||
|
||||
const service = require('../services/{{{classname}}}Service');
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
async {{operationId}}(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.{{operationId}});
|
||||
}
|
||||
const {{operationId}} = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.{{operationId}});
|
||||
};
|
||||
|
||||
{{/operation}}
|
||||
}
|
||||
|
||||
module.exports = {{classname}}Controller;
|
||||
{{/operations}}
|
||||
|
||||
module.exports = {
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
{{operationId}},
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
};
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const config = require('../config');
|
||||
const logger = require('../logger');
|
||||
|
||||
class Controller {
|
||||
@@ -25,35 +28,99 @@ class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
static collectFiles(request) {
|
||||
logger.info('Checking if files are expected in schema');
|
||||
if (request.openapi.schema.requestBody !== undefined) {
|
||||
const [contentType] = request.headers['content-type'].split(';');
|
||||
if (contentType === 'multipart/form-data') {
|
||||
const contentSchema = request.openapi.schema.requestBody.content[contentType].schema;
|
||||
Object.entries(contentSchema.properties).forEach(([name, property]) => {
|
||||
if (property.type === 'string' && ['binary', 'base64'].indexOf(property.format) > -1) {
|
||||
request.body[name] = request.files.find(file => file.fieldname === name);
|
||||
}
|
||||
});
|
||||
} else if (request.openapi.schema.requestBody.content[contentType] !== undefined
|
||||
&& request.files !== undefined) {
|
||||
[request.body] = request.files;
|
||||
/**
|
||||
* Files have been uploaded to the directory defined by config.js as upload directory
|
||||
* Files have a temporary name, that was saved as 'filename' of the file object that is
|
||||
* referenced in reuquest.files array.
|
||||
* This method finds the file and changes it to the file name that was originally called
|
||||
* when it was uploaded. To prevent files from being overwritten, a timestamp is added between
|
||||
* the filename and its extension
|
||||
* @param request
|
||||
* @param fieldName
|
||||
* @returns {string}
|
||||
*/
|
||||
static collectFile(request, fieldName) {
|
||||
let uploadedFileName = '';
|
||||
if (request.files && request.files.length > 0) {
|
||||
const fileObject = request.files.find(file => file.fieldname === fieldName);
|
||||
if (fileObject) {
|
||||
const fileArray = fileObject.originalname.split('.');
|
||||
const extension = fileArray.pop();
|
||||
fileArray.push(`_${Date.now()}`);
|
||||
uploadedFileName = `${fileArray.join('')}.${extension}`;
|
||||
fs.renameSync(path.join(config.FILE_UPLOAD_PATH, fileObject.filename),
|
||||
path.join(config.FILE_UPLOAD_PATH, uploadedFileName));
|
||||
}
|
||||
}
|
||||
return uploadedFileName;
|
||||
}
|
||||
|
||||
// static collectFiles(request) {
|
||||
// logger.info('Checking if files are expected in schema');
|
||||
// const requestFiles = {};
|
||||
// if (request.openapi.schema.requestBody !== undefined) {
|
||||
// const [contentType] = request.headers['content-type'].split(';');
|
||||
// if (contentType === 'multipart/form-data') {
|
||||
// const contentSchema = request.openapi.schema.requestBody.content[contentType].schema;
|
||||
// Object.entries(contentSchema.properties).forEach(([name, property]) => {
|
||||
// if (property.type === 'string' && ['binary', 'base64'].indexOf(property.format) > -1) {
|
||||
// const fileObject = request.files.find(file => file.fieldname === name);
|
||||
// const fileArray = fileObject.originalname.split('.');
|
||||
// const extension = fileArray.pop();
|
||||
// fileArray.push(`_${Date.now()}`);
|
||||
// const uploadedFileName = `${fileArray.join('')}.${extension}`;
|
||||
// fs.renameSync(path.join(config.FILE_UPLOAD_PATH, fileObject.filename),
|
||||
// path.join(config.FILE_UPLOAD_PATH, uploadedFileName));
|
||||
// requestFiles[name] = uploadedFileName;
|
||||
// }
|
||||
// });
|
||||
// } else if (request.openapi.schema.requestBody.content[contentType] !== undefined
|
||||
// && request.files !== undefined) {
|
||||
// [request.body] = request.files;
|
||||
// }
|
||||
// }
|
||||
// return requestFiles;
|
||||
// }
|
||||
|
||||
static collectRequestParams(request) {
|
||||
this.collectFiles(request);
|
||||
const requestParams = {};
|
||||
if (request.openapi.schema.requestBody !== undefined) {
|
||||
requestParams.body = request.body;
|
||||
const { content } = request.openapi.schema.requestBody;
|
||||
if (content['application/json'] !== undefined) {
|
||||
const schema = request.openapi.schema.requestBody.content['application/json'];
|
||||
if (schema.$ref) {
|
||||
requestParams[schema.$ref.substr(schema.$ref.lastIndexOf('.'))] = request.body;
|
||||
} else {
|
||||
requestParams.body = request.body;
|
||||
}
|
||||
} else if (content['multipart/form-data'] !== undefined) {
|
||||
Object.keys(content['multipart/form-data'].schema.properties).forEach(
|
||||
(property) => {
|
||||
const propertyObject = content['multipart/form-data'].schema.properties[property];
|
||||
if (propertyObject.format !== undefined && propertyObject.format === 'binary') {
|
||||
requestParams[property] = this.collectFile(request, property);
|
||||
} else {
|
||||
requestParams[property] = request.body[property];
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
// if (request.openapi.schema.requestBody.content['application/json'] !== undefined) {
|
||||
// const schema = request.openapi.schema.requestBody.content['application/json'];
|
||||
// if (schema.$ref) {
|
||||
// requestParams[schema.$ref.substr(schema.$ref.lastIndexOf('.'))] = request.body;
|
||||
// } else {
|
||||
// requestParams.body = request.body;
|
||||
// }
|
||||
// }
|
||||
request.openapi.schema.parameters.forEach((param) => {
|
||||
if (param.in === 'path') {
|
||||
requestParams[param.name] = request.openapi.pathParams[param.name];
|
||||
} else if (param.in === 'query') {
|
||||
requestParams[param.name] = request.query[param.name];
|
||||
} else if (param.in === 'header') {
|
||||
requestParams[param.name] = request.headers[param.name];
|
||||
}
|
||||
});
|
||||
return requestParams;
|
||||
|
||||
@@ -1,35 +1,43 @@
|
||||
// const { Middleware } = require('swagger-express-middleware');
|
||||
const http = require('http');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const swaggerUI = require('swagger-ui-express');
|
||||
const yamljs = require('yamljs');
|
||||
const jsYaml = require('js-yaml');
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const bodyParser = require('body-parser');
|
||||
const { OpenApiValidator } = require('express-openapi-validator');
|
||||
const openapiRouter = require('./utils/openapiRouter');
|
||||
const logger = require('./logger');
|
||||
const config = require('./config');
|
||||
|
||||
class ExpressServer {
|
||||
constructor(port, openApiYaml) {
|
||||
this.port = port;
|
||||
this.app = express();
|
||||
this.openApiPath = openApiYaml;
|
||||
this.schema = yamljs.load(openApiYaml);
|
||||
try {
|
||||
this.schema = jsYaml.safeLoad(fs.readFileSync(openApiYaml));
|
||||
} catch (e) {
|
||||
logger.error('failed to start Express Server', e.message);
|
||||
}
|
||||
this.setupMiddleware();
|
||||
}
|
||||
|
||||
setupMiddleware() {
|
||||
// this.setupAllowedMedia();
|
||||
this.app.use(cors());
|
||||
this.app.use(bodyParser.json());
|
||||
this.app.use(bodyParser.json({ limit: '14MB' }));
|
||||
this.app.use(express.json());
|
||||
this.app.use(express.urlencoded({ extended: false }));
|
||||
this.app.use(cookieParser());
|
||||
this.app.use('/spec', express.static(path.join(__dirname, 'api')));
|
||||
this.app.get('/hello', (req, res) => res.send('Hello World. path: '+this.openApiPath));
|
||||
// this.app.get('/spec', express.static(this.openApiPath));
|
||||
this.app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(this.schema));
|
||||
//Simple test to see that the server is up and responding
|
||||
this.app.get('/hello', (req, res) => res.send(`Hello World. path: ${this.openApiPath}`));
|
||||
//Send the openapi document *AS GENERATED BY THE GENERATOR*
|
||||
this.app.get('/openapi', (req, res) => res.sendFile((path.join(__dirname, 'api', 'openapi.yaml'))));
|
||||
//View the openapi document in a visual interface. Should be able to test from this page
|
||||
this.app.use('/api-doc', swaggerUI.serve, swaggerUI.setup(this.schema));
|
||||
this.app.get('/login-redirect', (req, res) => {
|
||||
res.status(200);
|
||||
res.json(req.query);
|
||||
@@ -38,50 +46,31 @@ class ExpressServer {
|
||||
res.status(200);
|
||||
res.json(req.query);
|
||||
});
|
||||
}
|
||||
|
||||
launch() {
|
||||
new OpenApiValidator({
|
||||
apiSpecPath: this.openApiPath,
|
||||
}).install(this.app);
|
||||
this.app.use(openapiRouter());
|
||||
this.app.get('/', (req, res) => {
|
||||
res.status(200);
|
||||
res.end('Hello World');
|
||||
});
|
||||
}
|
||||
|
||||
addErrorHandler() {
|
||||
this.app.use('*', (req, res) => {
|
||||
res.status(404);
|
||||
res.send(JSON.stringify({ error: `path ${req.baseUrl} doesn't exist` }));
|
||||
});
|
||||
/**
|
||||
* suppressed eslint rule: The next variable is required here, even though it's not used.
|
||||
*
|
||||
** */
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
this.app.use((error, req, res, next) => {
|
||||
const errorResponse = error.error || error.errors || error.message || 'Unknown error';
|
||||
res.status(error.status || 500);
|
||||
res.type('json');
|
||||
res.json({ error: errorResponse });
|
||||
});
|
||||
}
|
||||
|
||||
async launch() {
|
||||
return new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
this.addErrorHandler();
|
||||
this.server = await this.app.listen(this.port, () => {
|
||||
console.log(`server running on port ${this.port}`);
|
||||
resolve(this.server);
|
||||
apiSpec: this.openApiPath,
|
||||
operationHandlers: path.join(__dirname),
|
||||
fileUploader: { dest: config.FILE_UPLOAD_PATH },
|
||||
}).install(this.app)
|
||||
.catch(e => console.log(e))
|
||||
.then(() => {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
this.app.use((err, req, res, next) => {
|
||||
// format errors
|
||||
res.status(err.status || 500).json({
|
||||
message: err.message || err,
|
||||
errors: err.errors || '',
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
http.createServer(this.app).listen(this.port);
|
||||
console.log(`Listening on port ${this.port}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async close() {
|
||||
if (this.server !== undefined) {
|
||||
await this.server.close();
|
||||
|
||||
@@ -1,26 +1,14 @@
|
||||
const config = require('./config');
|
||||
const logger = require('./logger');
|
||||
const ExpressServer = require('./expressServer');
|
||||
// const App = require('./app');
|
||||
|
||||
// const app = new App(config);
|
||||
// app.launch()
|
||||
// .then(() => {
|
||||
// logger.info('Server launched');
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// logger.error('found error, shutting down server');
|
||||
// app.close()
|
||||
// .catch(closeError => logger.error(closeError))
|
||||
// .finally(() => logger.error(error));
|
||||
// });
|
||||
const launchServer = async () => {
|
||||
try {
|
||||
this.expressServer = new ExpressServer(config.URL_PORT, config.OPENAPI_YAML);
|
||||
await this.expressServer.launch();
|
||||
this.expressServer.launch();
|
||||
logger.info('Express server running');
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
logger.error('Express Server failure', error.message);
|
||||
await this.close();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
const winston = require('winston');
|
||||
const { transports, createLogger, format } = require('winston');
|
||||
|
||||
const logger = winston.createLogger({
|
||||
const logger = createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.json(),
|
||||
format: format.combine(
|
||||
format.timestamp(),
|
||||
format.json(),
|
||||
),
|
||||
defaultMeta: { service: 'user-service' },
|
||||
transports: [
|
||||
new winston.transports.File({ filename: 'error.log', level: 'error' }),
|
||||
new winston.transports.File({ filename: 'combined.log' }),
|
||||
new transports.Console(),
|
||||
new transports.File({ filename: 'error.log', level: 'error', timestamp: true }),
|
||||
new transports.File({ filename: 'combined.log', timestamp: true }),
|
||||
],
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
logger.add(new winston.transports.Console({ format: winston.format.simple() }));
|
||||
logger.add(new transports.Console({ format: format.simple() }));
|
||||
}
|
||||
|
||||
module.exports = logger;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "{{projectName}}",
|
||||
"name": "{{projectName}}",
|
||||
"version": "{{appVersion}}",
|
||||
"description": "{{{appDescription}}}",
|
||||
"main": "index.js",
|
||||
@@ -15,28 +15,25 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"body-parser": "^1.19.0",
|
||||
"connect": "^3.2.0",
|
||||
"camelcase": "^5.3.1",
|
||||
"cookie-parser": "^1.4.4",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.16.4",
|
||||
"express-openapi-validator": "^1.0.0",
|
||||
"express-openapi-validator": "^3.9.1",
|
||||
"js-yaml": "^3.3.0",
|
||||
"jstoxml": "^1.5.0",
|
||||
"ono": "^5.0.1",
|
||||
"openapi-sampler": "^1.0.0-beta.15",
|
||||
"swagger-express-middleware": "^2.0.2",
|
||||
"swagger-tools": "^0.10.4",
|
||||
"swagger-ui-express": "^4.0.2",
|
||||
"winston": "^3.2.1",
|
||||
"yamljs": "^0.3.0",
|
||||
"mocha": "^6.1.4",
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^0.19.0",
|
||||
"chai": "^4.2.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-airbnb-base": "^13.1.0",
|
||||
"eslint-config-airbnb-base": "^14.0.0",
|
||||
"eslint-plugin-import": "^2.17.2",
|
||||
"form-data": "^2.3.3"
|
||||
"mocha": "^7.1.1"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"env": {
|
||||
|
||||
@@ -1,45 +1,49 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
const Service = require('./Service');
|
||||
|
||||
class {{{classname}}}Service {
|
||||
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
/**
|
||||
{{#summary}}
|
||||
* {{{summary}}}
|
||||
{{/summary}}
|
||||
{{#notes}}
|
||||
* {{{notes}}}
|
||||
{{/notes}}
|
||||
*
|
||||
{{#allParams}}
|
||||
* {{paramName}} {{{dataType}}} {{{description}}}{{^required}} (optional){{/required}}
|
||||
{{/allParams}}
|
||||
{{^returnType}}
|
||||
* no response value expected for this operation
|
||||
{{/returnType}}
|
||||
{{#returnType}}
|
||||
* returns {{{returnType}}}
|
||||
{{/returnType}}
|
||||
**/
|
||||
static {{{operationId}}}({{#allParams}}{{#-first}}{ {{/-first}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{#-last}} }{{/-last}}{{/allParams}}) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
{{#summary}}
|
||||
* {{{summary}}}
|
||||
{{/summary}}
|
||||
{{#notes}}
|
||||
* {{{notes}}}
|
||||
{{/notes}}
|
||||
*
|
||||
{{#allParams}}
|
||||
* {{paramName}} {{{dataType}}} {{{description}}}{{^required}} (optional){{/required}}
|
||||
{{/allParams}}
|
||||
{{^returnType}}
|
||||
* no response value expected for this operation
|
||||
{{/returnType}}
|
||||
{{#returnType}}
|
||||
* returns {{{returnType}}}
|
||||
{{/returnType}}
|
||||
* */
|
||||
const {{{operationId}}} = ({{#allParams}}{{#-first}}{ {{/-first}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{#-last}} }{{/-last}}{{/allParams}}) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
{{#allParams}}
|
||||
{{paramName}},
|
||||
{{/allParams}}
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
{{/operation}}
|
||||
}
|
||||
|
||||
module.exports = {{{classname}}}Service;
|
||||
{{/operations}}
|
||||
|
||||
module.exports = {
|
||||
{{#operations}}
|
||||
{{#operation}}
|
||||
{{operationId}},
|
||||
{{/operation}}
|
||||
{{/operations}}
|
||||
};
|
||||
|
||||
@@ -1 +1 @@
|
||||
4.1.0-SNAPSHOT
|
||||
unset
|
||||
@@ -1,36 +1,58 @@
|
||||
|
||||
# OpenAPI Generated JavaScript/Express Server
|
||||
|
||||
## Overview
|
||||
This server was generated using the [OpenAPI Generator](https://openapi-generator.tech) project. The code generator, and it's generated code allows you to develop your system with an API-First attitude, where the API contract is the anchor and definer of your project, and your code and business-logic aims to complete and comply to the terms in the API contract.
|
||||
|
||||
### prerequisites
|
||||
- NodeJS >= 10.4
|
||||
- NodeJS >= 10.6
|
||||
- NPM >= 6.10.0
|
||||
|
||||
The code was written on a mac, so assuming all should work smoothly on Linux-based computers. However, there is no reason not to run this library on Windows-based machines. If you find an OS-related problem, please open an issue and it will be resolved.
|
||||
|
||||
### Running the server
|
||||
To run the server, run:
|
||||
|
||||
```
|
||||
npm start
|
||||
```
|
||||
### View and test the API
|
||||
You can see the API documentation, and check the available endpoints by going to http://localhost:3000/api-docs/. Endpoints that require security need to have security handlers configured before they can return a successful response. At this point they will return [ a response code of 401](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401).
|
||||
##### At this stage the server does not support document body sent in xml format. Forms will be supported in the near future.
|
||||
### Running the server
|
||||
#### This is a long read, but there's a lot to understand. Please take the time to go through this.
|
||||
1. Use the OpenAPI Generator to generate your application:
|
||||
Assuming you have Java (1.8+), and [have the jar](https://github.com/openapitools/openapi-generator#13---download-jar) to generate the application, run:
|
||||
```java -jar {path_to_jar_file} generate -g nodejs-express-server -i {openapi yaml/json file} -o {target_directory_where_the_app_will_be_installed} ```
|
||||
If you do not have the jar, or do not want to run Java from your local machine, follow instructions on the [OpenAPITools page](https://github.com/openapitools/openapi-generator). You can run the script online, on docker, and various other ways.
|
||||
2. Go to the generated directory you defined. There's a fully working NodeJS-ExpressJs server waiting for you. This is important - the code is yours to change and update! Look at config.js and see that the settings there are ok with you - the server will run on port 3000, and files will be uploaded to a new directory 'uploaded_files'.
|
||||
3. The server will base itself on an openapi.yaml file which is located under /api/openapi.yaml. This is not exactly the same file that you used to generate the app:
|
||||
I. If you have `application/json` contentBody that was defined inside the path object - the generate will have moved it to the components/schemas section of the openapi document.
|
||||
II. Every process has a new element added to it - `x-eov-operation-handler: controllers/PetController` which directs the call to that file.
|
||||
III. We have a Java application that translates the operationId to a method, and a nodeJS script that does the same process to call that method. Both are converting the method to `camelCase`, but might have discrepancy. Please pay attention to the operationID names, and see that they are represented in the `controllers` and `services` directories.
|
||||
4. Take the time to understand the structure of the application. There might be bugs, and there might be settings and business-logic that does not meet your expectation. Instead of dumping this solution and looking for something else - see if you can make the generated code work for you.
|
||||
To keep the explanation short (a more detailed explanation will follow): Application starts with a call to index.js (this is where you will plug in the db later). It calls expressServer.js which is where the express.js and openapi-validator kick in. This is an important file. Learn it. All calls to endpoints that were configured in the openapi.yaml document go to `controllers/{name_of_tag_which_the_operation_was_associated_with}.js`, which is a very small method. All the business-logic lies in `controllers/Controller.js`, and from there - to `services/{name_of_tag_which_the_operation_was_associated_with}.js`.
|
||||
|
||||
### Node version and guidelines
|
||||
The code was written using Node version 10.6, and complies to the [Airbnb .eslint guiding rules](https://github.com/airbnb/javascript).
|
||||
5. Once you've understood what is *going* to happen, launch the app and ensure everything is working as expected:
|
||||
```
|
||||
npm start
|
||||
```
|
||||
### Tests
|
||||
Unfortunately, I have not written any unit-tests. Those will come in the future. However, the package does come with all that is needed to write and run tests - mocha and sinon and the related libraries are included in the package.js and will be installed upon npm install command
|
||||
|
||||
### View and test the API
|
||||
(Assuming no changes were made to config.js)
|
||||
|
||||
1. API documentation, and to check the available endpoints:
|
||||
http://localhost:3000/api-docs/. To
|
||||
2. Download the oepnapi.yaml document: http://localhost:3000/openapi.
|
||||
3. Every call to an endpoint that was defined in the openapi document will return a 200 and a list of all the parameters and objects that were sent in the request.
|
||||
4. Endpoints that require security need to have security handlers configured before they can return a successful response. At this point they will return [ a response code of 401](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401).
|
||||
5. ##### At this stage the server does not support document body sent in xml format.
|
||||
|
||||
### Node version and guidelines
|
||||
The code was written using Node version 10.6, and complies to the [Airbnb .eslint guiding rules](https://github.com/airbnb/javascript).
|
||||
|
||||
### Project Files
|
||||
#### Root Directory:
|
||||
In the root directory we have (besides package.json, config.js, and log files):
|
||||
- **logger.js** - where we define the logger for the project. The project uses winston, but the purpose of this file is to enable users to change and modify their own logger behavior.
|
||||
- **index.js** - This is the project's 'main' file, and from here we launch the application. This is a very short and concise file, and the idea behind launching from this short file is to allow use-cases of launching the server with different parameters (changing config and/or logger) without affecting the rest of the code.
|
||||
- **index.js** - This is the project's 'main' file, and from here we launch the application. This is a very short and concise file, and the idea behind launching from this short file is to allow use-cases of launching the server with different parameters (changing config and/or logger) without affecting the rest of the code.
|
||||
- **expressServer.js** - The core of the Express.js server. This is where the express server is initialized, together with the OpenAPI validator, OpenAPI UI, and other libraries needed to start our server. If we want to add external links, that's where they would go. Our project uses the [express-openapi-validator](https://www.npmjs.com/package/express-openapi-validator) library that acts as a first step in the routing process - requests that are directed to paths defined in the `openapi.yaml` file are caught by this process, and it's parameters and bodyContent are validated against the schema. A successful result of this validation will be a new 'openapi' object added to the request. If the path requested is not part of the openapi.yaml file, the validator ignores the request and passes it on, as is, down the flow of the Express server.
|
||||
|
||||
#### api/
|
||||
- **openapi.yaml** - This is the OpenAPI contract to which this server will comply. The file was generated using the codegen, and should contain everything needed to run the API Gateway - no references to external models/schemas.
|
||||
- **openapi.yaml** - This is the OpenAPI contract to which this server will comply. The file was generated using the codegen, and should contain everything needed to run the API Gateway - no references to external models/schemas.
|
||||
|
||||
#### utils/
|
||||
Currently a single file:
|
||||
@@ -38,13 +60,13 @@ Currently a single file:
|
||||
- **openapiRouter.js** - This is where the routing to our back-end code happens. If the request object includes an ```openapi``` object, it picks up the following values (that are part of the ```openapi.yaml``` file): 'x-openapi-router-controller', and 'x-openapi-router-service'. These variables are names of files/classes in the controllers and services directories respectively. The operationId of the request is also extracted. The operationId is a method in the controller and the service that was generated as part of the codegen process. The routing process sends the request and response objects to the controller, which will extract the expected variables from the request, and send it to be processed by the service, returning the response from the service to the caller.
|
||||
|
||||
#### controllers/
|
||||
After validating the request, and ensuring this belongs to our API gateway, we send the request to a `controller`, where the variables and parameters are extracted from the request and sent to the relevant `service` for processing. The `controller` handles the response from the `service` and builds the appropriate HTTP response to be sent back to the user.
|
||||
After validating the request, and ensuring this belongs to our API gateway, we send the request to a `controller`, where the variables and parameters are extracted from the request and sent to the relevant `service` for processing. The `controller` handles the response from the `service` and builds the appropriate HTTP response to be sent back to the user.
|
||||
|
||||
- **index.js** - load all the controllers that were generated for this project, and export them to be used dynamically by the `openapiRouter.js`. If you would like to customize your controller, it is advised that you link to your controller here, and ensure that the codegen does not rewrite this file.
|
||||
|
||||
- **Controller.js** - The core processor of the generated controllers. The generated controllers are designed to be as slim and generic as possible, referencing to the `Controller.js` for the business logic of parsing the needed variables and arguments from the request, and for building the HTTP response which will be sent back. The `Controller.js` is a class with static methods.
|
||||
- **Controller.js** - The core processor of the generated controllers. The generated controllers are designed to be as slim and generic as possible, referencing to the `Controller.js` for the business logic of parsing the needed variables and arguments from the request, and for building the HTTP response which will be sent back. The `Controller.js` is a class with static methods.
|
||||
|
||||
- **{{x-openapi-router-controller}}.js** - auto-generated code, processing all the operations. The Controller is a class that is constructed with the service class it will be sending the request to. Every request defined by the `openapi.yaml` has an operationId. The operationId is the name of the method that will be called. Every method receives the request and response, and calls the `Controller.js` to process the request and response, adding the service method that should be called for the actual business-logic processing.
|
||||
- **.js** - auto-generated code, processing all the operations. The Controller is a class that is constructed with the service class it will be sending the request to. Every request defined by the `openapi.yaml` has an operationId. The operationId is the name of the method that will be called. Every method receives the request and response, and calls the `Controller.js` to process the request and response, adding the service method that should be called for the actual business-logic processing.
|
||||
|
||||
#### services/
|
||||
This is where the API Gateway ends, and the unique business-logic of your application kicks in. Every endpoint in the `openapi.yaml` has a variable 'x-openapi-router-service', which is the name of the service class that is generated. The operationID of the endpoint is the name of the method that will be called. The generated code provides a simple promise with a try/catch clause. A successful operation ends with a call to the generic `Service.js` to build a successful response (payload and response code), and a failure will call the generic `Service.js` to build a response with an error object and the relevant response code. It is recommended to have the services be generated automatically once, and after the initial build add methods manually.
|
||||
@@ -53,7 +75,7 @@ This is where the API Gateway ends, and the unique business-logic of your applic
|
||||
|
||||
- **Service.js** - A utility class, very simple and thin at this point, with two static methods for building a response object for successful and failed results in the service operation. The default response code is 200 for success and 500 for failure. It is recommended to send more accurate response codes and override these defaults when relevant.
|
||||
|
||||
- **{{x-openapi-router-service}}.js** - auto-generated code, providing a stub Promise for each operationId defined in the `openapi.yaml`. Each method receives the variables that were defined in the `openapi.yaml` file, and wraps a Promise in a try/catch clause. The Promise resolves both success and failure in a call to the `Service.js` utility class for building the appropriate response that will be sent back to the Controller and then to the caller of this endpoint.
|
||||
- **.js** - auto-generated code, providing a stub Promise for each operationId defined in the `openapi.yaml`. Each method receives the variables that were defined in the `openapi.yaml` file, and wraps a Promise in a try/catch clause. The Promise resolves both success and failure in a call to the `Service.js` utility class for building the appropriate response that will be sent back to the Controller and then to the caller of this endpoint.
|
||||
|
||||
#### tests/
|
||||
- **serverTests.js** - basic server validation tests, checking that the server is up, that a call to an endpoint within the scope of the `openapi.yaml` file returns 200, that a call to a path outside that scope returns 200 if it exists and a 404 if not.
|
||||
@@ -66,6 +88,3 @@ Future tests should be written to ensure that the response of every request sent
|
||||
|
||||
#### models/
|
||||
Currently a concept awaiting feedback. The idea is to have the objects defined in the openapi.yaml act as models which are passed between the different modules. This will conform the programmers to interact using defined objects, rather than loosley-defined JSON objects. Given the nature of JavaScript progrmmers, who want to work with their own bootstrapped parameters, this concept might not work. Keeping this here for future discussion and feedback.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ paths:
|
||||
description: Pet object that needs to be added to the store
|
||||
required: true
|
||||
responses:
|
||||
405:
|
||||
"405":
|
||||
content: {}
|
||||
description: Invalid input
|
||||
security:
|
||||
@@ -42,8 +42,7 @@ paths:
|
||||
tags:
|
||||
- pet
|
||||
x-codegen-request-body-name: body
|
||||
x-openapi-router-controller: PetController
|
||||
x-openapi-router-service: PetService
|
||||
x-eov-operation-handler: controllers/PetController
|
||||
put:
|
||||
operationId: updatePet
|
||||
requestBody:
|
||||
@@ -57,13 +56,13 @@ paths:
|
||||
description: Pet object that needs to be added to the store
|
||||
required: true
|
||||
responses:
|
||||
400:
|
||||
"400":
|
||||
content: {}
|
||||
description: Invalid ID supplied
|
||||
404:
|
||||
"404":
|
||||
content: {}
|
||||
description: Pet not found
|
||||
405:
|
||||
"405":
|
||||
content: {}
|
||||
description: Validation exception
|
||||
security:
|
||||
@@ -74,8 +73,7 @@ paths:
|
||||
tags:
|
||||
- pet
|
||||
x-codegen-request-body-name: body
|
||||
x-openapi-router-controller: PetController
|
||||
x-openapi-router-service: PetService
|
||||
x-eov-operation-handler: controllers/PetController
|
||||
/pet/findByStatus:
|
||||
get:
|
||||
description: Multiple status values can be provided with comma separated strings
|
||||
@@ -97,7 +95,7 @@ paths:
|
||||
type: array
|
||||
style: form
|
||||
responses:
|
||||
200:
|
||||
"200":
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
@@ -110,7 +108,7 @@ paths:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
type: array
|
||||
description: successful operation
|
||||
400:
|
||||
"400":
|
||||
content: {}
|
||||
description: Invalid status value
|
||||
security:
|
||||
@@ -120,8 +118,7 @@ paths:
|
||||
summary: Finds Pets by status
|
||||
tags:
|
||||
- pet
|
||||
x-openapi-router-controller: PetController
|
||||
x-openapi-router-service: PetService
|
||||
x-eov-operation-handler: controllers/PetController
|
||||
/pet/findByTags:
|
||||
get:
|
||||
deprecated: true
|
||||
@@ -140,7 +137,7 @@ paths:
|
||||
type: array
|
||||
style: form
|
||||
responses:
|
||||
200:
|
||||
"200":
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
@@ -153,7 +150,7 @@ paths:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
type: array
|
||||
description: successful operation
|
||||
400:
|
||||
"400":
|
||||
content: {}
|
||||
description: Invalid tag value
|
||||
security:
|
||||
@@ -163,8 +160,7 @@ paths:
|
||||
summary: Finds Pets by tags
|
||||
tags:
|
||||
- pet
|
||||
x-openapi-router-controller: PetController
|
||||
x-openapi-router-service: PetService
|
||||
x-eov-operation-handler: controllers/PetController
|
||||
/pet/{petId}:
|
||||
delete:
|
||||
operationId: deletePet
|
||||
@@ -181,7 +177,7 @@ paths:
|
||||
format: int64
|
||||
type: integer
|
||||
responses:
|
||||
400:
|
||||
"400":
|
||||
content: {}
|
||||
description: Invalid pet value
|
||||
security:
|
||||
@@ -191,8 +187,7 @@ paths:
|
||||
summary: Deletes a pet
|
||||
tags:
|
||||
- pet
|
||||
x-openapi-router-controller: PetController
|
||||
x-openapi-router-service: PetService
|
||||
x-eov-operation-handler: controllers/PetController
|
||||
get:
|
||||
description: Returns a single pet
|
||||
operationId: getPetById
|
||||
@@ -205,7 +200,7 @@ paths:
|
||||
format: int64
|
||||
type: integer
|
||||
responses:
|
||||
200:
|
||||
"200":
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
@@ -214,10 +209,10 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Pet'
|
||||
description: successful operation
|
||||
400:
|
||||
"400":
|
||||
content: {}
|
||||
description: Invalid ID supplied
|
||||
404:
|
||||
"404":
|
||||
content: {}
|
||||
description: Pet not found
|
||||
security:
|
||||
@@ -225,8 +220,7 @@ paths:
|
||||
summary: Find pet by ID
|
||||
tags:
|
||||
- pet
|
||||
x-openapi-router-controller: PetController
|
||||
x-openapi-router-service: PetService
|
||||
x-eov-operation-handler: controllers/PetController
|
||||
post:
|
||||
operationId: updatePetWithForm
|
||||
parameters:
|
||||
@@ -249,7 +243,7 @@ paths:
|
||||
description: Updated status of the pet
|
||||
type: string
|
||||
responses:
|
||||
405:
|
||||
"405":
|
||||
content: {}
|
||||
description: Invalid input
|
||||
security:
|
||||
@@ -259,8 +253,7 @@ paths:
|
||||
summary: Updates a pet in the store with form data
|
||||
tags:
|
||||
- pet
|
||||
x-openapi-router-controller: PetController
|
||||
x-openapi-router-service: PetService
|
||||
x-eov-operation-handler: controllers/PetController
|
||||
/pet/{petId}/uploadImage:
|
||||
post:
|
||||
operationId: uploadFile
|
||||
@@ -285,7 +278,7 @@ paths:
|
||||
format: binary
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -298,14 +291,13 @@ paths:
|
||||
summary: uploads an image
|
||||
tags:
|
||||
- pet
|
||||
x-openapi-router-controller: PetController
|
||||
x-openapi-router-service: PetService
|
||||
x-eov-operation-handler: controllers/PetController
|
||||
/store/inventory:
|
||||
get:
|
||||
description: Returns a map of status codes to quantities
|
||||
operationId: getInventory
|
||||
responses:
|
||||
200:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -319,8 +311,7 @@ paths:
|
||||
summary: Returns pet inventories by status
|
||||
tags:
|
||||
- store
|
||||
x-openapi-router-controller: StoreController
|
||||
x-openapi-router-service: StoreService
|
||||
x-eov-operation-handler: controllers/StoreController
|
||||
/store/order:
|
||||
post:
|
||||
operationId: placeOrder
|
||||
@@ -332,7 +323,7 @@ paths:
|
||||
description: order placed for purchasing the pet
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
"200":
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
@@ -341,15 +332,14 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
description: successful operation
|
||||
400:
|
||||
"400":
|
||||
content: {}
|
||||
description: Invalid Order
|
||||
summary: Place an order for a pet
|
||||
tags:
|
||||
- store
|
||||
x-codegen-request-body-name: body
|
||||
x-openapi-router-controller: StoreController
|
||||
x-openapi-router-service: StoreService
|
||||
x-eov-operation-handler: controllers/StoreController
|
||||
/store/order/{orderId}:
|
||||
delete:
|
||||
description: For valid response try integer IDs with value < 1000. Anything
|
||||
@@ -363,17 +353,16 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
400:
|
||||
"400":
|
||||
content: {}
|
||||
description: Invalid ID supplied
|
||||
404:
|
||||
"404":
|
||||
content: {}
|
||||
description: Order not found
|
||||
summary: Delete purchase order by ID
|
||||
tags:
|
||||
- store
|
||||
x-openapi-router-controller: StoreController
|
||||
x-openapi-router-service: StoreService
|
||||
x-eov-operation-handler: controllers/StoreController
|
||||
get:
|
||||
description: For valid response try integer IDs with value <= 5 or > 10. Other
|
||||
values will generated exceptions
|
||||
@@ -389,7 +378,7 @@ paths:
|
||||
minimum: 1
|
||||
type: integer
|
||||
responses:
|
||||
200:
|
||||
"200":
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
@@ -398,17 +387,16 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Order'
|
||||
description: successful operation
|
||||
400:
|
||||
"400":
|
||||
content: {}
|
||||
description: Invalid ID supplied
|
||||
404:
|
||||
"404":
|
||||
content: {}
|
||||
description: Order not found
|
||||
summary: Find purchase order by ID
|
||||
tags:
|
||||
- store
|
||||
x-openapi-router-controller: StoreController
|
||||
x-openapi-router-service: StoreService
|
||||
x-eov-operation-handler: controllers/StoreController
|
||||
/user:
|
||||
post:
|
||||
description: This can only be done by the logged in user.
|
||||
@@ -428,8 +416,7 @@ paths:
|
||||
tags:
|
||||
- user
|
||||
x-codegen-request-body-name: body
|
||||
x-openapi-router-controller: UserController
|
||||
x-openapi-router-service: UserService
|
||||
x-eov-operation-handler: controllers/UserController
|
||||
/user/createWithArray:
|
||||
post:
|
||||
operationId: createUsersWithArrayInput
|
||||
@@ -450,8 +437,7 @@ paths:
|
||||
tags:
|
||||
- user
|
||||
x-codegen-request-body-name: body
|
||||
x-openapi-router-controller: UserController
|
||||
x-openapi-router-service: UserService
|
||||
x-eov-operation-handler: controllers/UserController
|
||||
/user/createWithList:
|
||||
post:
|
||||
operationId: createUsersWithListInput
|
||||
@@ -472,8 +458,7 @@ paths:
|
||||
tags:
|
||||
- user
|
||||
x-codegen-request-body-name: body
|
||||
x-openapi-router-controller: UserController
|
||||
x-openapi-router-service: UserService
|
||||
x-eov-operation-handler: controllers/UserController
|
||||
/user/login:
|
||||
get:
|
||||
operationId: loginUser
|
||||
@@ -491,7 +476,7 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
"200":
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
@@ -511,14 +496,13 @@ paths:
|
||||
schema:
|
||||
format: date-time
|
||||
type: string
|
||||
400:
|
||||
"400":
|
||||
content: {}
|
||||
description: Invalid username/password supplied
|
||||
summary: Logs user into the system
|
||||
tags:
|
||||
- user
|
||||
x-openapi-router-controller: UserController
|
||||
x-openapi-router-service: UserService
|
||||
x-eov-operation-handler: controllers/UserController
|
||||
/user/logout:
|
||||
get:
|
||||
operationId: logoutUser
|
||||
@@ -529,8 +513,7 @@ paths:
|
||||
summary: Logs out current logged in user session
|
||||
tags:
|
||||
- user
|
||||
x-openapi-router-controller: UserController
|
||||
x-openapi-router-service: UserService
|
||||
x-eov-operation-handler: controllers/UserController
|
||||
/user/{username}:
|
||||
delete:
|
||||
description: This can only be done by the logged in user.
|
||||
@@ -543,17 +526,16 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
400:
|
||||
"400":
|
||||
content: {}
|
||||
description: Invalid username supplied
|
||||
404:
|
||||
"404":
|
||||
content: {}
|
||||
description: User not found
|
||||
summary: Delete user
|
||||
tags:
|
||||
- user
|
||||
x-openapi-router-controller: UserController
|
||||
x-openapi-router-service: UserService
|
||||
x-eov-operation-handler: controllers/UserController
|
||||
get:
|
||||
operationId: getUserByName
|
||||
parameters:
|
||||
@@ -564,7 +546,7 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
"200":
|
||||
content:
|
||||
application/xml:
|
||||
schema:
|
||||
@@ -573,17 +555,16 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
description: successful operation
|
||||
400:
|
||||
"400":
|
||||
content: {}
|
||||
description: Invalid username supplied
|
||||
404:
|
||||
"404":
|
||||
content: {}
|
||||
description: User not found
|
||||
summary: Get user by user name
|
||||
tags:
|
||||
- user
|
||||
x-openapi-router-controller: UserController
|
||||
x-openapi-router-service: UserService
|
||||
x-eov-operation-handler: controllers/UserController
|
||||
put:
|
||||
description: This can only be done by the logged in user.
|
||||
operationId: updateUser
|
||||
@@ -602,18 +583,17 @@ paths:
|
||||
description: Updated user object
|
||||
required: true
|
||||
responses:
|
||||
400:
|
||||
"400":
|
||||
content: {}
|
||||
description: Invalid user supplied
|
||||
404:
|
||||
"404":
|
||||
content: {}
|
||||
description: User not found
|
||||
summary: Updated user
|
||||
tags:
|
||||
- user
|
||||
x-codegen-request-body-name: body
|
||||
x-openapi-router-controller: UserController
|
||||
x-openapi-router-service: UserService
|
||||
x-eov-operation-handler: controllers/UserController
|
||||
components:
|
||||
schemas:
|
||||
Order:
|
||||
|
||||
@@ -1,795 +0,0 @@
|
||||
---
|
||||
swagger: "2.0"
|
||||
info:
|
||||
description: |
|
||||
"This is a sample server Petstore server. You can find out more about\
|
||||
\ Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).\
|
||||
\ For this sample, you can use the api key `special-key` to test the authorization\
|
||||
\ filters."
|
||||
version: "1.0.0"
|
||||
title: "Swagger Petstore"
|
||||
termsOfService: "http://swagger.io/terms/"
|
||||
contact:
|
||||
email: "apiteam@swagger.io"
|
||||
license:
|
||||
name: "Apache-2.0"
|
||||
url: "https://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
basePath: "/v2"
|
||||
tags:
|
||||
- name: "pet"
|
||||
description: "Everything about your Pets"
|
||||
externalDocs:
|
||||
description: "Find out more"
|
||||
url: "http://swagger.io"
|
||||
- name: "store"
|
||||
description: "Access to Petstore orders"
|
||||
- name: "user"
|
||||
description: "Operations about user"
|
||||
externalDocs:
|
||||
description: "Find out more about our store"
|
||||
url: "http://swagger.io"
|
||||
schemes:
|
||||
- "http"
|
||||
paths:
|
||||
/pet:
|
||||
post:
|
||||
tags:
|
||||
- "pet"
|
||||
summary: "Add a new pet to the store"
|
||||
description: ""
|
||||
operationId: "addPet"
|
||||
consumes:
|
||||
- "application/json"
|
||||
- "application/xml"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- in: "body"
|
||||
name: "body"
|
||||
description: "Pet object that needs to be added to the store"
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/Pet"
|
||||
responses:
|
||||
405:
|
||||
description: "Invalid input"
|
||||
security:
|
||||
- petstore_auth:
|
||||
- "write:pets"
|
||||
- "read:pets"
|
||||
x-swagger-router-controller: "Pet"
|
||||
put:
|
||||
tags:
|
||||
- "pet"
|
||||
summary: "Update an existing pet"
|
||||
description: ""
|
||||
operationId: "updatePet"
|
||||
consumes:
|
||||
- "application/json"
|
||||
- "application/xml"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- in: "body"
|
||||
name: "body"
|
||||
description: "Pet object that needs to be added to the store"
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/Pet"
|
||||
responses:
|
||||
400:
|
||||
description: "Invalid ID supplied"
|
||||
404:
|
||||
description: "Pet not found"
|
||||
405:
|
||||
description: "Validation exception"
|
||||
security:
|
||||
- petstore_auth:
|
||||
- "write:pets"
|
||||
- "read:pets"
|
||||
x-swagger-router-controller: "Pet"
|
||||
/pet/findByStatus:
|
||||
get:
|
||||
tags:
|
||||
- "pet"
|
||||
summary: "Finds Pets by status"
|
||||
description: "Multiple status values can be provided with comma separated strings"
|
||||
operationId: "findPetsByStatus"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- name: "status"
|
||||
in: "query"
|
||||
description: "Status values that need to be considered for filter"
|
||||
required: true
|
||||
type: "array"
|
||||
items:
|
||||
type: "string"
|
||||
default: "available"
|
||||
enum:
|
||||
- "available"
|
||||
- "pending"
|
||||
- "sold"
|
||||
collectionFormat: "csv"
|
||||
responses:
|
||||
200:
|
||||
description: "successful operation"
|
||||
schema:
|
||||
type: "array"
|
||||
items:
|
||||
$ref: "#/definitions/Pet"
|
||||
400:
|
||||
description: "Invalid status value"
|
||||
security:
|
||||
- petstore_auth:
|
||||
- "write:pets"
|
||||
- "read:pets"
|
||||
x-swagger-router-controller: "Pet"
|
||||
/pet/findByTags:
|
||||
get:
|
||||
tags:
|
||||
- "pet"
|
||||
summary: "Finds Pets by tags"
|
||||
description: |
|
||||
"Multiple tags can be provided with comma separated strings. Use\
|
||||
\ tag1, tag2, tag3 for testing."
|
||||
operationId: "findPetsByTags"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- name: "tags"
|
||||
in: "query"
|
||||
description: "Tags to filter by"
|
||||
required: true
|
||||
type: "array"
|
||||
items:
|
||||
type: "string"
|
||||
collectionFormat: "csv"
|
||||
responses:
|
||||
200:
|
||||
description: "successful operation"
|
||||
schema:
|
||||
type: "array"
|
||||
items:
|
||||
$ref: "#/definitions/Pet"
|
||||
400:
|
||||
description: "Invalid tag value"
|
||||
security:
|
||||
- petstore_auth:
|
||||
- "write:pets"
|
||||
- "read:pets"
|
||||
deprecated: true
|
||||
x-swagger-router-controller: "Pet"
|
||||
/pet/{petId}:
|
||||
get:
|
||||
tags:
|
||||
- "pet"
|
||||
summary: "Find pet by ID"
|
||||
description: "Returns a single pet"
|
||||
operationId: "getPetById"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- name: "petId"
|
||||
in: "path"
|
||||
description: "ID of pet to return"
|
||||
required: true
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
responses:
|
||||
200:
|
||||
description: "successful operation"
|
||||
schema:
|
||||
$ref: "#/definitions/Pet"
|
||||
400:
|
||||
description: "Invalid ID supplied"
|
||||
404:
|
||||
description: "Pet not found"
|
||||
security:
|
||||
- api_key: []
|
||||
x-swagger-router-controller: "Pet"
|
||||
post:
|
||||
tags:
|
||||
- "pet"
|
||||
summary: "Updates a pet in the store with form data"
|
||||
description: ""
|
||||
operationId: "updatePetWithForm"
|
||||
consumes:
|
||||
- "application/x-www-form-urlencoded"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- name: "petId"
|
||||
in: "path"
|
||||
description: "ID of pet that needs to be updated"
|
||||
required: true
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
- name: "name"
|
||||
in: "formData"
|
||||
description: "Updated name of the pet"
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "status"
|
||||
in: "formData"
|
||||
description: "Updated status of the pet"
|
||||
required: false
|
||||
type: "string"
|
||||
responses:
|
||||
405:
|
||||
description: "Invalid input"
|
||||
security:
|
||||
- petstore_auth:
|
||||
- "write:pets"
|
||||
- "read:pets"
|
||||
x-swagger-router-controller: "Pet"
|
||||
delete:
|
||||
tags:
|
||||
- "pet"
|
||||
summary: "Deletes a pet"
|
||||
description: ""
|
||||
operationId: "deletePet"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- name: "api_key"
|
||||
in: "header"
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "petId"
|
||||
in: "path"
|
||||
description: "Pet id to delete"
|
||||
required: true
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
responses:
|
||||
400:
|
||||
description: "Invalid pet value"
|
||||
security:
|
||||
- petstore_auth:
|
||||
- "write:pets"
|
||||
- "read:pets"
|
||||
x-swagger-router-controller: "Pet"
|
||||
/pet/{petId}/uploadImage:
|
||||
post:
|
||||
tags:
|
||||
- "pet"
|
||||
summary: "uploads an image"
|
||||
description: ""
|
||||
operationId: "uploadFile"
|
||||
consumes:
|
||||
- "multipart/form-data"
|
||||
produces:
|
||||
- "application/json"
|
||||
parameters:
|
||||
- name: "petId"
|
||||
in: "path"
|
||||
description: "ID of pet to update"
|
||||
required: true
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
- name: "additionalMetadata"
|
||||
in: "formData"
|
||||
description: "Additional data to pass to server"
|
||||
required: false
|
||||
type: "string"
|
||||
- name: "file"
|
||||
in: "formData"
|
||||
description: "file to upload"
|
||||
required: false
|
||||
type: "file"
|
||||
responses:
|
||||
200:
|
||||
description: "successful operation"
|
||||
schema:
|
||||
$ref: "#/definitions/ApiResponse"
|
||||
security:
|
||||
- petstore_auth:
|
||||
- "write:pets"
|
||||
- "read:pets"
|
||||
x-swagger-router-controller: "Pet"
|
||||
/store/inventory:
|
||||
get:
|
||||
tags:
|
||||
- "store"
|
||||
summary: "Returns pet inventories by status"
|
||||
description: "Returns a map of status codes to quantities"
|
||||
operationId: "getInventory"
|
||||
produces:
|
||||
- "application/json"
|
||||
parameters: []
|
||||
responses:
|
||||
200:
|
||||
description: "successful operation"
|
||||
schema:
|
||||
type: "object"
|
||||
additionalProperties:
|
||||
type: "integer"
|
||||
format: "int32"
|
||||
security:
|
||||
- api_key: []
|
||||
x-swagger-router-controller: "Store"
|
||||
/store/order:
|
||||
post:
|
||||
tags:
|
||||
- "store"
|
||||
summary: "Place an order for a pet"
|
||||
description: ""
|
||||
operationId: "placeOrder"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- in: "body"
|
||||
name: "body"
|
||||
description: "order placed for purchasing the pet"
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/Order"
|
||||
responses:
|
||||
200:
|
||||
description: "successful operation"
|
||||
schema:
|
||||
$ref: "#/definitions/Order"
|
||||
400:
|
||||
description: "Invalid Order"
|
||||
x-swagger-router-controller: "Store"
|
||||
/store/order/{orderId}:
|
||||
get:
|
||||
tags:
|
||||
- "store"
|
||||
summary: "Find purchase order by ID"
|
||||
description: |
|
||||
"For valid response try integer IDs with value <= 5 or > 10. Other\
|
||||
\ values will generated exceptions"
|
||||
operationId: "getOrderById"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- name: "orderId"
|
||||
in: "path"
|
||||
description: "ID of pet that needs to be fetched"
|
||||
required: true
|
||||
type: "integer"
|
||||
maximum: 5
|
||||
minimum: 1
|
||||
format: "int64"
|
||||
responses:
|
||||
200:
|
||||
description: "successful operation"
|
||||
schema:
|
||||
$ref: "#/definitions/Order"
|
||||
400:
|
||||
description: "Invalid ID supplied"
|
||||
404:
|
||||
description: "Order not found"
|
||||
x-swagger-router-controller: "Store"
|
||||
delete:
|
||||
tags:
|
||||
- "store"
|
||||
summary: "Delete purchase order by ID"
|
||||
description: |
|
||||
"For valid response try integer IDs with value < 1000. Anything\
|
||||
\ above 1000 or nonintegers will generate API errors"
|
||||
operationId: "deleteOrder"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- name: "orderId"
|
||||
in: "path"
|
||||
description: "ID of the order that needs to be deleted"
|
||||
required: true
|
||||
type: "string"
|
||||
responses:
|
||||
400:
|
||||
description: "Invalid ID supplied"
|
||||
404:
|
||||
description: "Order not found"
|
||||
x-swagger-router-controller: "Store"
|
||||
/user:
|
||||
post:
|
||||
tags:
|
||||
- "user"
|
||||
summary: "Create user"
|
||||
description: "This can only be done by the logged in user."
|
||||
operationId: "createUser"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- in: "body"
|
||||
name: "body"
|
||||
description: "Created user object"
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/User"
|
||||
responses:
|
||||
default:
|
||||
description: "successful operation"
|
||||
x-swagger-router-controller: "User"
|
||||
/user/createWithArray:
|
||||
post:
|
||||
tags:
|
||||
- "user"
|
||||
summary: "Creates list of users with given input array"
|
||||
description: ""
|
||||
operationId: "createUsersWithArrayInput"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- in: "body"
|
||||
name: "body"
|
||||
description: "List of user object"
|
||||
required: true
|
||||
schema:
|
||||
type: "array"
|
||||
items:
|
||||
$ref: "#/definitions/User"
|
||||
responses:
|
||||
default:
|
||||
description: "successful operation"
|
||||
x-swagger-router-controller: "User"
|
||||
/user/createWithList:
|
||||
post:
|
||||
tags:
|
||||
- "user"
|
||||
summary: "Creates list of users with given input array"
|
||||
description: ""
|
||||
operationId: "createUsersWithListInput"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- in: "body"
|
||||
name: "body"
|
||||
description: "List of user object"
|
||||
required: true
|
||||
schema:
|
||||
type: "array"
|
||||
items:
|
||||
$ref: "#/definitions/User"
|
||||
responses:
|
||||
default:
|
||||
description: "successful operation"
|
||||
x-swagger-router-controller: "User"
|
||||
/user/login:
|
||||
get:
|
||||
tags:
|
||||
- "user"
|
||||
summary: "Logs user into the system"
|
||||
description: ""
|
||||
operationId: "loginUser"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- name: "username"
|
||||
in: "query"
|
||||
description: "The user name for login"
|
||||
required: true
|
||||
type: "string"
|
||||
- name: "password"
|
||||
in: "query"
|
||||
description: "The password for login in clear text"
|
||||
required: true
|
||||
type: "string"
|
||||
responses:
|
||||
200:
|
||||
description: "successful operation"
|
||||
schema:
|
||||
type: "string"
|
||||
headers:
|
||||
X-Rate-Limit:
|
||||
type: "integer"
|
||||
format: "int32"
|
||||
description: "calls per hour allowed by the user"
|
||||
X-Expires-After:
|
||||
type: "string"
|
||||
format: "date-time"
|
||||
description: "date in UTC when toekn expires"
|
||||
400:
|
||||
description: "Invalid username/password supplied"
|
||||
x-swagger-router-controller: "User"
|
||||
/user/logout:
|
||||
get:
|
||||
tags:
|
||||
- "user"
|
||||
summary: "Logs out current logged in user session"
|
||||
description: ""
|
||||
operationId: "logoutUser"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters: []
|
||||
responses:
|
||||
default:
|
||||
description: "successful operation"
|
||||
x-swagger-router-controller: "User"
|
||||
/user/{username}:
|
||||
get:
|
||||
tags:
|
||||
- "user"
|
||||
summary: "Get user by user name"
|
||||
description: ""
|
||||
operationId: "getUserByName"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- name: "username"
|
||||
in: "path"
|
||||
description: "The name that needs to be fetched. Use user1 for testing."
|
||||
required: true
|
||||
type: "string"
|
||||
responses:
|
||||
200:
|
||||
description: "successful operation"
|
||||
schema:
|
||||
$ref: "#/definitions/User"
|
||||
400:
|
||||
description: "Invalid username supplied"
|
||||
404:
|
||||
description: "User not found"
|
||||
x-swagger-router-controller: "User"
|
||||
put:
|
||||
tags:
|
||||
- "user"
|
||||
summary: "Updated user"
|
||||
description: "This can only be done by the logged in user."
|
||||
operationId: "updateUser"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- name: "username"
|
||||
in: "path"
|
||||
description: "name that need to be deleted"
|
||||
required: true
|
||||
type: "string"
|
||||
- in: "body"
|
||||
name: "body"
|
||||
description: "Updated user object"
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/definitions/User"
|
||||
responses:
|
||||
400:
|
||||
description: "Invalid user supplied"
|
||||
404:
|
||||
description: "User not found"
|
||||
x-swagger-router-controller: "User"
|
||||
delete:
|
||||
tags:
|
||||
- "user"
|
||||
summary: "Delete user"
|
||||
description: "This can only be done by the logged in user."
|
||||
operationId: "deleteUser"
|
||||
produces:
|
||||
- "application/xml"
|
||||
- "application/json"
|
||||
parameters:
|
||||
- name: "username"
|
||||
in: "path"
|
||||
description: "The name that needs to be deleted"
|
||||
required: true
|
||||
type: "string"
|
||||
responses:
|
||||
400:
|
||||
description: "Invalid username supplied"
|
||||
404:
|
||||
description: "User not found"
|
||||
x-swagger-router-controller: "User"
|
||||
|
||||
securityDefinitions:
|
||||
petstore_auth:
|
||||
type: "oauth2"
|
||||
authorizationUrl: "http://petstore.swagger.io/api/oauth/dialog"
|
||||
flow: "implicit"
|
||||
scopes:
|
||||
write:pets: "modify pets in your account"
|
||||
read:pets: "read your pets"
|
||||
api_key:
|
||||
type: "apiKey"
|
||||
name: "api_key"
|
||||
in: "header"
|
||||
definitions:
|
||||
Order:
|
||||
type: "object"
|
||||
properties:
|
||||
id:
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
petId:
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
quantity:
|
||||
type: "integer"
|
||||
format: "int32"
|
||||
shipDate:
|
||||
type: "string"
|
||||
format: "date-time"
|
||||
status:
|
||||
type: "string"
|
||||
description: "Order Status"
|
||||
enum:
|
||||
- "placed"
|
||||
- "approved"
|
||||
- "delivered"
|
||||
complete:
|
||||
type: "boolean"
|
||||
default: false
|
||||
title: "Pet Order"
|
||||
description: "An order for a pets from the pet store"
|
||||
example:
|
||||
petId: 6
|
||||
quantity: 1
|
||||
id: 0
|
||||
shipDate: "2000-01-23T04:56:07.000+00:00"
|
||||
complete: false
|
||||
status: "placed"
|
||||
xml:
|
||||
name: "Order"
|
||||
Category:
|
||||
type: "object"
|
||||
properties:
|
||||
id:
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
name:
|
||||
type: "string"
|
||||
title: "Pet category"
|
||||
description: "A category for a pet"
|
||||
example:
|
||||
name: "name"
|
||||
id: 6
|
||||
xml:
|
||||
name: "Category"
|
||||
User:
|
||||
type: "object"
|
||||
properties:
|
||||
id:
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
username:
|
||||
type: "string"
|
||||
firstName:
|
||||
type: "string"
|
||||
lastName:
|
||||
type: "string"
|
||||
email:
|
||||
type: "string"
|
||||
password:
|
||||
type: "string"
|
||||
phone:
|
||||
type: "string"
|
||||
userStatus:
|
||||
type: "integer"
|
||||
format: "int32"
|
||||
description: "User Status"
|
||||
title: "a User"
|
||||
description: "A User who is purchasing from the pet store"
|
||||
example:
|
||||
firstName: "firstName"
|
||||
lastName: "lastName"
|
||||
password: "password"
|
||||
userStatus: 6
|
||||
phone: "phone"
|
||||
id: 0
|
||||
email: "email"
|
||||
username: "username"
|
||||
xml:
|
||||
name: "User"
|
||||
Tag:
|
||||
type: "object"
|
||||
properties:
|
||||
id:
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
name:
|
||||
type: "string"
|
||||
title: "Pet Tag"
|
||||
description: "A tag for a pet"
|
||||
example:
|
||||
name: "name"
|
||||
id: 1
|
||||
xml:
|
||||
name: "Tag"
|
||||
Pet:
|
||||
type: "object"
|
||||
required:
|
||||
- "name"
|
||||
- "photoUrls"
|
||||
properties:
|
||||
id:
|
||||
type: "integer"
|
||||
format: "int64"
|
||||
category:
|
||||
$ref: "#/definitions/Category"
|
||||
name:
|
||||
type: "string"
|
||||
example: "doggie"
|
||||
photoUrls:
|
||||
type: "array"
|
||||
xml:
|
||||
name: "photoUrl"
|
||||
wrapped: true
|
||||
items:
|
||||
type: "string"
|
||||
tags:
|
||||
type: "array"
|
||||
xml:
|
||||
name: "tag"
|
||||
wrapped: true
|
||||
items:
|
||||
$ref: "#/definitions/Tag"
|
||||
status:
|
||||
type: "string"
|
||||
description: "pet status in the store"
|
||||
enum:
|
||||
- "available"
|
||||
- "pending"
|
||||
- "sold"
|
||||
title: "a Pet"
|
||||
description: "A pet for sale in the pet store"
|
||||
example:
|
||||
photoUrls:
|
||||
- "photoUrls"
|
||||
- "photoUrls"
|
||||
name: "doggie"
|
||||
id: 0
|
||||
category:
|
||||
name: "name"
|
||||
id: 6
|
||||
tags:
|
||||
- name: "name"
|
||||
id: 1
|
||||
- name: "name"
|
||||
id: 1
|
||||
status: "available"
|
||||
xml:
|
||||
name: "Pet"
|
||||
ApiResponse:
|
||||
type: "object"
|
||||
properties:
|
||||
code:
|
||||
type: "integer"
|
||||
format: "int32"
|
||||
type:
|
||||
type: "string"
|
||||
message:
|
||||
type: "string"
|
||||
title: "An uploaded response"
|
||||
description: "Describes the result of uploading an image resource"
|
||||
example:
|
||||
code: 0
|
||||
type: "type"
|
||||
message: "message"
|
||||
testItem:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
descrtiption:
|
||||
type: string
|
||||
version:
|
||||
type: number
|
||||
example:
|
||||
id: 1
|
||||
name: "testItem"
|
||||
description: "An item which means very little, as it's only a test"
|
||||
version: 2.3
|
||||
externalDocs:
|
||||
description: "Find out more about Swagger"
|
||||
url: "http://swagger.io"
|
||||
30
samples/server/petstore/nodejs-express-server/app.js
Normal file
30
samples/server/petstore/nodejs-express-server/app.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const ExpressServer = require('./expressServer');
|
||||
const logger = require('./logger');
|
||||
// const swaggerRouter = require('./utils/swaggerRouter');
|
||||
|
||||
class App {
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
async launch() {
|
||||
try {
|
||||
this.expressServer = new ExpressServer(this.config.URL_PORT, this.config.OPENAPI_YAML);
|
||||
// this.expressServer.app.use(swaggerRouter());
|
||||
await this.expressServer.launch();
|
||||
logger.info('Express server running');
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
await this.close();
|
||||
}
|
||||
}
|
||||
|
||||
async close() {
|
||||
if (this.expressServer !== undefined) {
|
||||
await this.expressServer.close();
|
||||
logger.info(`Server shut down on port ${this.config.URL_PORT}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = App;
|
||||
@@ -6,7 +6,10 @@ const config = {
|
||||
URL_PATH: 'http://localhost',
|
||||
BASE_VERSION: 'v2',
|
||||
CONTROLLER_DIRECTORY: path.join(__dirname, 'controllers'),
|
||||
PROJECT_DIR: __dirname,
|
||||
};
|
||||
config.OPENAPI_YAML = path.join(config.ROOT_DIR, 'api', 'openapi.yaml');
|
||||
config.FULL_PATH = `${config.URL_PATH}:${config.URL_PORT}/${config.BASE_VERSION}`;
|
||||
config.FILE_UPLOAD_PATH = path.join(config.PROJECT_DIR, 'uploaded_files');
|
||||
|
||||
module.exports = config;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const config = require('../config');
|
||||
const logger = require('../logger');
|
||||
|
||||
class Controller {
|
||||
@@ -25,35 +28,99 @@ class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
static collectFiles(request) {
|
||||
logger.info('Checking if files are expected in schema');
|
||||
if (request.openapi.schema.requestBody !== undefined) {
|
||||
const [contentType] = request.headers['content-type'].split(';');
|
||||
if (contentType === 'multipart/form-data') {
|
||||
const contentSchema = request.openapi.schema.requestBody.content[contentType].schema;
|
||||
Object.entries(contentSchema.properties).forEach(([name, property]) => {
|
||||
if (property.type === 'string' && ['binary', 'base64'].indexOf(property.format) > -1) {
|
||||
request.body[name] = request.files.find(file => file.fieldname === name);
|
||||
}
|
||||
});
|
||||
} else if (request.openapi.schema.requestBody.content[contentType] !== undefined
|
||||
&& request.files !== undefined) {
|
||||
[request.body] = request.files;
|
||||
/**
|
||||
* Files have been uploaded to the directory defined by config.js as upload directory
|
||||
* Files have a temporary name, that was saved as 'filename' of the file object that is
|
||||
* referenced in reuquest.files array.
|
||||
* This method finds the file and changes it to the file name that was originally called
|
||||
* when it was uploaded. To prevent files from being overwritten, a timestamp is added between
|
||||
* the filename and its extension
|
||||
* @param request
|
||||
* @param fieldName
|
||||
* @returns {string}
|
||||
*/
|
||||
static collectFile(request, fieldName) {
|
||||
let uploadedFileName = '';
|
||||
if (request.files && request.files.length > 0) {
|
||||
const fileObject = request.files.find(file => file.fieldname === fieldName);
|
||||
if (fileObject) {
|
||||
const fileArray = fileObject.originalname.split('.');
|
||||
const extension = fileArray.pop();
|
||||
fileArray.push(`_${Date.now()}`);
|
||||
uploadedFileName = `${fileArray.join('')}.${extension}`;
|
||||
fs.renameSync(path.join(config.FILE_UPLOAD_PATH, fileObject.filename),
|
||||
path.join(config.FILE_UPLOAD_PATH, uploadedFileName));
|
||||
}
|
||||
}
|
||||
return uploadedFileName;
|
||||
}
|
||||
|
||||
// static collectFiles(request) {
|
||||
// logger.info('Checking if files are expected in schema');
|
||||
// const requestFiles = {};
|
||||
// if (request.openapi.schema.requestBody !== undefined) {
|
||||
// const [contentType] = request.headers['content-type'].split(';');
|
||||
// if (contentType === 'multipart/form-data') {
|
||||
// const contentSchema = request.openapi.schema.requestBody.content[contentType].schema;
|
||||
// Object.entries(contentSchema.properties).forEach(([name, property]) => {
|
||||
// if (property.type === 'string' && ['binary', 'base64'].indexOf(property.format) > -1) {
|
||||
// const fileObject = request.files.find(file => file.fieldname === name);
|
||||
// const fileArray = fileObject.originalname.split('.');
|
||||
// const extension = fileArray.pop();
|
||||
// fileArray.push(`_${Date.now()}`);
|
||||
// const uploadedFileName = `${fileArray.join('')}.${extension}`;
|
||||
// fs.renameSync(path.join(config.FILE_UPLOAD_PATH, fileObject.filename),
|
||||
// path.join(config.FILE_UPLOAD_PATH, uploadedFileName));
|
||||
// requestFiles[name] = uploadedFileName;
|
||||
// }
|
||||
// });
|
||||
// } else if (request.openapi.schema.requestBody.content[contentType] !== undefined
|
||||
// && request.files !== undefined) {
|
||||
// [request.body] = request.files;
|
||||
// }
|
||||
// }
|
||||
// return requestFiles;
|
||||
// }
|
||||
|
||||
static collectRequestParams(request) {
|
||||
this.collectFiles(request);
|
||||
const requestParams = {};
|
||||
if (request.openapi.schema.requestBody !== undefined) {
|
||||
requestParams.body = request.body;
|
||||
const { content } = request.openapi.schema.requestBody;
|
||||
if (content['application/json'] !== undefined) {
|
||||
const schema = request.openapi.schema.requestBody.content['application/json'];
|
||||
if (schema.$ref) {
|
||||
requestParams[schema.$ref.substr(schema.$ref.lastIndexOf('.'))] = request.body;
|
||||
} else {
|
||||
requestParams.body = request.body;
|
||||
}
|
||||
} else if (content['multipart/form-data'] !== undefined) {
|
||||
Object.keys(content['multipart/form-data'].schema.properties).forEach(
|
||||
(property) => {
|
||||
const propertyObject = content['multipart/form-data'].schema.properties[property];
|
||||
if (propertyObject.format !== undefined && propertyObject.format === 'binary') {
|
||||
requestParams[property] = this.collectFile(request, property);
|
||||
} else {
|
||||
requestParams[property] = request.body[property];
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
// if (request.openapi.schema.requestBody.content['application/json'] !== undefined) {
|
||||
// const schema = request.openapi.schema.requestBody.content['application/json'];
|
||||
// if (schema.$ref) {
|
||||
// requestParams[schema.$ref.substr(schema.$ref.lastIndexOf('.'))] = request.body;
|
||||
// } else {
|
||||
// requestParams.body = request.body;
|
||||
// }
|
||||
// }
|
||||
request.openapi.schema.parameters.forEach((param) => {
|
||||
if (param.in === 'path') {
|
||||
requestParams[param.name] = request.openapi.pathParams[param.name];
|
||||
} else if (param.in === 'query') {
|
||||
requestParams[param.name] = request.query[param.name];
|
||||
} else if (param.in === 'header') {
|
||||
requestParams[param.name] = request.headers[param.name];
|
||||
}
|
||||
});
|
||||
return requestParams;
|
||||
|
||||
@@ -1,42 +1,53 @@
|
||||
/**
|
||||
* The PetController file is a very simple one, which does not need to be changed manually,
|
||||
* unless there's a case where business logic reoutes the request to an entity which is not
|
||||
* the service.
|
||||
* The heavy lifting of the Controller item is done in Request.js - that is where request
|
||||
* parameters are extracted and sent to the service, and where response is handled.
|
||||
*/
|
||||
|
||||
const Controller = require('./Controller');
|
||||
const service = require('../services/PetService');
|
||||
const addPet = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.addPet);
|
||||
};
|
||||
|
||||
class PetController {
|
||||
constructor(Service) {
|
||||
this.service = Service;
|
||||
}
|
||||
const deletePet = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.deletePet);
|
||||
};
|
||||
|
||||
async addPet(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.addPet);
|
||||
}
|
||||
const findPetsByStatus = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.findPetsByStatus);
|
||||
};
|
||||
|
||||
async deletePet(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.deletePet);
|
||||
}
|
||||
const findPetsByTags = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.findPetsByTags);
|
||||
};
|
||||
|
||||
async findPetsByStatus(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.findPetsByStatus);
|
||||
}
|
||||
const getPetById = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.getPetById);
|
||||
};
|
||||
|
||||
async findPetsByTags(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.findPetsByTags);
|
||||
}
|
||||
const updatePet = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.updatePet);
|
||||
};
|
||||
|
||||
async getPetById(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.getPetById);
|
||||
}
|
||||
const updatePetWithForm = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.updatePetWithForm);
|
||||
};
|
||||
|
||||
async updatePet(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.updatePet);
|
||||
}
|
||||
const uploadFile = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.uploadFile);
|
||||
};
|
||||
|
||||
async updatePetWithForm(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.updatePetWithForm);
|
||||
}
|
||||
|
||||
async uploadFile(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.uploadFile);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = PetController;
|
||||
module.exports = {
|
||||
addPet,
|
||||
deletePet,
|
||||
findPetsByStatus,
|
||||
findPetsByTags,
|
||||
getPetById,
|
||||
updatePet,
|
||||
updatePetWithForm,
|
||||
uploadFile,
|
||||
};
|
||||
|
||||
@@ -1,26 +1,33 @@
|
||||
/**
|
||||
* The StoreController file is a very simple one, which does not need to be changed manually,
|
||||
* unless there's a case where business logic reoutes the request to an entity which is not
|
||||
* the service.
|
||||
* The heavy lifting of the Controller item is done in Request.js - that is where request
|
||||
* parameters are extracted and sent to the service, and where response is handled.
|
||||
*/
|
||||
|
||||
const Controller = require('./Controller');
|
||||
const service = require('../services/StoreService');
|
||||
const deleteOrder = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.deleteOrder);
|
||||
};
|
||||
|
||||
class StoreController {
|
||||
constructor(Service) {
|
||||
this.service = Service;
|
||||
}
|
||||
const getInventory = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.getInventory);
|
||||
};
|
||||
|
||||
async deleteOrder(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.deleteOrder);
|
||||
}
|
||||
const getOrderById = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.getOrderById);
|
||||
};
|
||||
|
||||
async getInventory(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.getInventory);
|
||||
}
|
||||
const placeOrder = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.placeOrder);
|
||||
};
|
||||
|
||||
async getOrderById(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.getOrderById);
|
||||
}
|
||||
|
||||
async placeOrder(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.placeOrder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = StoreController;
|
||||
module.exports = {
|
||||
deleteOrder,
|
||||
getInventory,
|
||||
getOrderById,
|
||||
placeOrder,
|
||||
};
|
||||
|
||||
@@ -1,42 +1,53 @@
|
||||
/**
|
||||
* The UserController file is a very simple one, which does not need to be changed manually,
|
||||
* unless there's a case where business logic reoutes the request to an entity which is not
|
||||
* the service.
|
||||
* The heavy lifting of the Controller item is done in Request.js - that is where request
|
||||
* parameters are extracted and sent to the service, and where response is handled.
|
||||
*/
|
||||
|
||||
const Controller = require('./Controller');
|
||||
const service = require('../services/UserService');
|
||||
const createUser = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.createUser);
|
||||
};
|
||||
|
||||
class UserController {
|
||||
constructor(Service) {
|
||||
this.service = Service;
|
||||
}
|
||||
const createUsersWithArrayInput = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.createUsersWithArrayInput);
|
||||
};
|
||||
|
||||
async createUser(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.createUser);
|
||||
}
|
||||
const createUsersWithListInput = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.createUsersWithListInput);
|
||||
};
|
||||
|
||||
async createUsersWithArrayInput(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.createUsersWithArrayInput);
|
||||
}
|
||||
const deleteUser = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.deleteUser);
|
||||
};
|
||||
|
||||
async createUsersWithListInput(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.createUsersWithListInput);
|
||||
}
|
||||
const getUserByName = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.getUserByName);
|
||||
};
|
||||
|
||||
async deleteUser(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.deleteUser);
|
||||
}
|
||||
const loginUser = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.loginUser);
|
||||
};
|
||||
|
||||
async getUserByName(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.getUserByName);
|
||||
}
|
||||
const logoutUser = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.logoutUser);
|
||||
};
|
||||
|
||||
async loginUser(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.loginUser);
|
||||
}
|
||||
const updateUser = async (request, response) => {
|
||||
await Controller.handleRequest(request, response, service.updateUser);
|
||||
};
|
||||
|
||||
async logoutUser(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.logoutUser);
|
||||
}
|
||||
|
||||
async updateUser(request, response) {
|
||||
await Controller.handleRequest(request, response, this.service.updateUser);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = UserController;
|
||||
module.exports = {
|
||||
createUser,
|
||||
createUsersWithArrayInput,
|
||||
createUsersWithListInput,
|
||||
deleteUser,
|
||||
getUserByName,
|
||||
loginUser,
|
||||
logoutUser,
|
||||
updateUser,
|
||||
};
|
||||
|
||||
@@ -1,35 +1,43 @@
|
||||
// const { Middleware } = require('swagger-express-middleware');
|
||||
const http = require('http');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const swaggerUI = require('swagger-ui-express');
|
||||
const yamljs = require('yamljs');
|
||||
const jsYaml = require('js-yaml');
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const bodyParser = require('body-parser');
|
||||
const { OpenApiValidator } = require('express-openapi-validator');
|
||||
const openapiRouter = require('./utils/openapiRouter');
|
||||
const logger = require('./logger');
|
||||
const config = require('./config');
|
||||
|
||||
class ExpressServer {
|
||||
constructor(port, openApiYaml) {
|
||||
this.port = port;
|
||||
this.app = express();
|
||||
this.openApiPath = openApiYaml;
|
||||
this.schema = yamljs.load(openApiYaml);
|
||||
try {
|
||||
this.schema = jsYaml.safeLoad(fs.readFileSync(openApiYaml));
|
||||
} catch (e) {
|
||||
logger.error('failed to start Express Server', e.message);
|
||||
}
|
||||
this.setupMiddleware();
|
||||
}
|
||||
|
||||
setupMiddleware() {
|
||||
// this.setupAllowedMedia();
|
||||
this.app.use(cors());
|
||||
this.app.use(bodyParser.json());
|
||||
this.app.use(bodyParser.json({ limit: '14MB' }));
|
||||
this.app.use(express.json());
|
||||
this.app.use(express.urlencoded({ extended: false }));
|
||||
this.app.use(cookieParser());
|
||||
this.app.use('/spec', express.static(path.join(__dirname, 'api')));
|
||||
this.app.get('/hello', (req, res) => res.send('Hello World. path: '+this.openApiPath));
|
||||
// this.app.get('/spec', express.static(this.openApiPath));
|
||||
this.app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(this.schema));
|
||||
//Simple test to see that the server is up and responding
|
||||
this.app.get('/hello', (req, res) => res.send(`Hello World. path: ${this.openApiPath}`));
|
||||
//Send the openapi document *AS GENERATED BY THE GENERATOR*
|
||||
this.app.get('/openapi', (req, res) => res.sendFile((path.join(__dirname, 'api', 'openapi.yaml'))));
|
||||
//View the openapi document in a visual interface. Should be able to test from this page
|
||||
this.app.use('/api-doc', swaggerUI.serve, swaggerUI.setup(this.schema));
|
||||
this.app.get('/login-redirect', (req, res) => {
|
||||
res.status(200);
|
||||
res.json(req.query);
|
||||
@@ -38,50 +46,31 @@ class ExpressServer {
|
||||
res.status(200);
|
||||
res.json(req.query);
|
||||
});
|
||||
}
|
||||
|
||||
launch() {
|
||||
new OpenApiValidator({
|
||||
apiSpecPath: this.openApiPath,
|
||||
}).install(this.app);
|
||||
this.app.use(openapiRouter());
|
||||
this.app.get('/', (req, res) => {
|
||||
res.status(200);
|
||||
res.end('Hello World');
|
||||
});
|
||||
}
|
||||
|
||||
addErrorHandler() {
|
||||
this.app.use('*', (req, res) => {
|
||||
res.status(404);
|
||||
res.send(JSON.stringify({ error: `path ${req.baseUrl} doesn't exist` }));
|
||||
});
|
||||
/**
|
||||
* suppressed eslint rule: The next variable is required here, even though it's not used.
|
||||
*
|
||||
** */
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
this.app.use((error, req, res, next) => {
|
||||
const errorResponse = error.error || error.errors || error.message || 'Unknown error';
|
||||
res.status(error.status || 500);
|
||||
res.type('json');
|
||||
res.json({ error: errorResponse });
|
||||
});
|
||||
}
|
||||
|
||||
async launch() {
|
||||
return new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
this.addErrorHandler();
|
||||
this.server = await this.app.listen(this.port, () => {
|
||||
console.log(`server running on port ${this.port}`);
|
||||
resolve(this.server);
|
||||
apiSpec: this.openApiPath,
|
||||
operationHandlers: path.join(__dirname),
|
||||
fileUploader: { dest: config.FILE_UPLOAD_PATH },
|
||||
}).install(this.app)
|
||||
.catch(e => console.log(e))
|
||||
.then(() => {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
this.app.use((err, req, res, next) => {
|
||||
// format errors
|
||||
res.status(err.status || 500).json({
|
||||
message: err.message || err,
|
||||
errors: err.errors || '',
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
http.createServer(this.app).listen(this.port);
|
||||
console.log(`Listening on port ${this.port}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async close() {
|
||||
if (this.server !== undefined) {
|
||||
await this.server.close();
|
||||
|
||||
@@ -1,26 +1,14 @@
|
||||
const config = require('./config');
|
||||
const logger = require('./logger');
|
||||
const ExpressServer = require('./expressServer');
|
||||
// const App = require('./app');
|
||||
|
||||
// const app = new App(config);
|
||||
// app.launch()
|
||||
// .then(() => {
|
||||
// logger.info('Server launched');
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// logger.error('found error, shutting down server');
|
||||
// app.close()
|
||||
// .catch(closeError => logger.error(closeError))
|
||||
// .finally(() => logger.error(error));
|
||||
// });
|
||||
const launchServer = async () => {
|
||||
try {
|
||||
this.expressServer = new ExpressServer(config.URL_PORT, config.OPENAPI_YAML);
|
||||
await this.expressServer.launch();
|
||||
this.expressServer.launch();
|
||||
logger.info('Express server running');
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
logger.error('Express Server failure', error.message);
|
||||
await this.close();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
const winston = require('winston');
|
||||
const { transports, createLogger, format } = require('winston');
|
||||
|
||||
const logger = winston.createLogger({
|
||||
const logger = createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.json(),
|
||||
format: format.combine(
|
||||
format.timestamp(),
|
||||
format.json(),
|
||||
),
|
||||
defaultMeta: { service: 'user-service' },
|
||||
transports: [
|
||||
new winston.transports.File({ filename: 'error.log', level: 'error' }),
|
||||
new winston.transports.File({ filename: 'combined.log' }),
|
||||
new transports.Console(),
|
||||
new transports.File({ filename: 'error.log', level: 'error', timestamp: true }),
|
||||
new transports.File({ filename: 'combined.log', timestamp: true }),
|
||||
],
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
logger.add(new winston.transports.Console({ format: winston.format.simple() }));
|
||||
logger.add(new transports.Console({ format: format.simple() }));
|
||||
}
|
||||
|
||||
module.exports = logger;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "openapi-petstore",
|
||||
"name": "openapi-petstore",
|
||||
"version": "1.0.0",
|
||||
"description": "This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.",
|
||||
"main": "index.js",
|
||||
@@ -15,28 +15,25 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"body-parser": "^1.19.0",
|
||||
"connect": "^3.2.0",
|
||||
"camelcase": "^5.3.1",
|
||||
"cookie-parser": "^1.4.4",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.16.4",
|
||||
"express-openapi-validator": "^1.0.0",
|
||||
"express-openapi-validator": "^3.9.1",
|
||||
"js-yaml": "^3.3.0",
|
||||
"jstoxml": "^1.5.0",
|
||||
"ono": "^5.0.1",
|
||||
"openapi-sampler": "^1.0.0-beta.15",
|
||||
"swagger-express-middleware": "^2.0.2",
|
||||
"swagger-tools": "^0.10.4",
|
||||
"swagger-ui-express": "^4.0.2",
|
||||
"winston": "^3.2.1",
|
||||
"yamljs": "^0.3.0",
|
||||
"mocha": "^6.1.4",
|
||||
"winston": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^0.19.0",
|
||||
"chai": "^4.2.0",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-airbnb-base": "^13.1.0",
|
||||
"eslint-config-airbnb-base": "^14.0.0",
|
||||
"eslint-plugin-import": "^2.17.2",
|
||||
"form-data": "^2.3.3"
|
||||
"mocha": "^7.1.1"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"env": {
|
||||
|
||||
@@ -1,184 +1,187 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
const Service = require('./Service');
|
||||
|
||||
class PetService {
|
||||
/**
|
||||
* Add a new pet to the store
|
||||
*
|
||||
* body Pet Pet object that needs to be added to the store
|
||||
* no response value expected for this operation
|
||||
* */
|
||||
const addPet = ({ body }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
body,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Deletes a pet
|
||||
*
|
||||
* petId Long Pet id to delete
|
||||
* apiUnderscorekey String (optional)
|
||||
* no response value expected for this operation
|
||||
* */
|
||||
const deletePet = ({ petId, apiUnderscorekey }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
petId,
|
||||
apiUnderscorekey,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Finds Pets by status
|
||||
* Multiple status values can be provided with comma separated strings
|
||||
*
|
||||
* status List Status values that need to be considered for filter
|
||||
* returns List
|
||||
* */
|
||||
const findPetsByStatus = ({ status }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
status,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Finds Pets by tags
|
||||
* Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
|
||||
*
|
||||
* tags List Tags to filter by
|
||||
* returns List
|
||||
* */
|
||||
const findPetsByTags = ({ tags }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
tags,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Find pet by ID
|
||||
* Returns a single pet
|
||||
*
|
||||
* petId Long ID of pet to return
|
||||
* returns Pet
|
||||
* */
|
||||
const getPetById = ({ petId }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
petId,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Update an existing pet
|
||||
*
|
||||
* body Pet Pet object that needs to be added to the store
|
||||
* no response value expected for this operation
|
||||
* */
|
||||
const updatePet = ({ body }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
body,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Updates a pet in the store with form data
|
||||
*
|
||||
* petId Long ID of pet that needs to be updated
|
||||
* name String Updated name of the pet (optional)
|
||||
* status String Updated status of the pet (optional)
|
||||
* no response value expected for this operation
|
||||
* */
|
||||
const updatePetWithForm = ({ petId, name, status }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
petId,
|
||||
name,
|
||||
status,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* uploads an image
|
||||
*
|
||||
* petId Long ID of pet to update
|
||||
* additionalMetadata String Additional data to pass to server (optional)
|
||||
* file File file to upload (optional)
|
||||
* returns ApiResponse
|
||||
* */
|
||||
const uploadFile = ({ petId, additionalMetadata, file }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
petId,
|
||||
additionalMetadata,
|
||||
file,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Add a new pet to the store
|
||||
*
|
||||
* body Pet Pet object that needs to be added to the store
|
||||
* no response value expected for this operation
|
||||
**/
|
||||
static addPet({ body }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a pet
|
||||
*
|
||||
* petId Long Pet id to delete
|
||||
* apiUnderscorekey String (optional)
|
||||
* no response value expected for this operation
|
||||
**/
|
||||
static deletePet({ petId, apiUnderscorekey }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds Pets by status
|
||||
* Multiple status values can be provided with comma separated strings
|
||||
*
|
||||
* status List Status values that need to be considered for filter
|
||||
* returns List
|
||||
**/
|
||||
static findPetsByStatus({ status }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds Pets by tags
|
||||
* Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
|
||||
*
|
||||
* tags List Tags to filter by
|
||||
* returns List
|
||||
**/
|
||||
static findPetsByTags({ tags }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find pet by ID
|
||||
* Returns a single pet
|
||||
*
|
||||
* petId Long ID of pet to return
|
||||
* returns Pet
|
||||
**/
|
||||
static getPetById({ petId }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing pet
|
||||
*
|
||||
* body Pet Pet object that needs to be added to the store
|
||||
* no response value expected for this operation
|
||||
**/
|
||||
static updatePet({ body }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a pet in the store with form data
|
||||
*
|
||||
* petId Long ID of pet that needs to be updated
|
||||
* name String Updated name of the pet (optional)
|
||||
* status String Updated status of the pet (optional)
|
||||
* no response value expected for this operation
|
||||
**/
|
||||
static updatePetWithForm({ petId, name, status }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* uploads an image
|
||||
*
|
||||
* petId Long ID of pet to update
|
||||
* additionalMetadata String Additional data to pass to server (optional)
|
||||
* file File file to upload (optional)
|
||||
* returns ApiResponse
|
||||
**/
|
||||
static uploadFile({ petId, additionalMetadata, file }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = PetService;
|
||||
module.exports = {
|
||||
addPet,
|
||||
deletePet,
|
||||
findPetsByStatus,
|
||||
findPetsByTags,
|
||||
getPetById,
|
||||
updatePet,
|
||||
updatePetWithForm,
|
||||
uploadFile,
|
||||
};
|
||||
|
||||
@@ -1,94 +1,91 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
const Service = require('./Service');
|
||||
|
||||
class StoreService {
|
||||
/**
|
||||
* Delete purchase order by ID
|
||||
* For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
|
||||
*
|
||||
* orderId String ID of the order that needs to be deleted
|
||||
* no response value expected for this operation
|
||||
* */
|
||||
const deleteOrder = ({ orderId }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
orderId,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Returns pet inventories by status
|
||||
* Returns a map of status codes to quantities
|
||||
*
|
||||
* returns Map
|
||||
* */
|
||||
const getInventory = () => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Find purchase order by ID
|
||||
* For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions
|
||||
*
|
||||
* orderId Long ID of pet that needs to be fetched
|
||||
* returns Order
|
||||
* */
|
||||
const getOrderById = ({ orderId }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
orderId,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Place an order for a pet
|
||||
*
|
||||
* body Order order placed for purchasing the pet
|
||||
* returns Order
|
||||
* */
|
||||
const placeOrder = ({ body }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
body,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Delete purchase order by ID
|
||||
* For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
|
||||
*
|
||||
* orderId String ID of the order that needs to be deleted
|
||||
* no response value expected for this operation
|
||||
**/
|
||||
static deleteOrder({ orderId }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns pet inventories by status
|
||||
* Returns a map of status codes to quantities
|
||||
*
|
||||
* returns Map
|
||||
**/
|
||||
static getInventory() {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find purchase order by ID
|
||||
* For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions
|
||||
*
|
||||
* orderId Long ID of pet that needs to be fetched
|
||||
* returns Order
|
||||
**/
|
||||
static getOrderById({ orderId }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Place an order for a pet
|
||||
*
|
||||
* body Order order placed for purchasing the pet
|
||||
* returns Order
|
||||
**/
|
||||
static placeOrder({ body }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = StoreService;
|
||||
module.exports = {
|
||||
deleteOrder,
|
||||
getInventory,
|
||||
getOrderById,
|
||||
placeOrder,
|
||||
};
|
||||
|
||||
@@ -1,180 +1,179 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
const Service = require('./Service');
|
||||
|
||||
class UserService {
|
||||
/**
|
||||
* Create user
|
||||
* This can only be done by the logged in user.
|
||||
*
|
||||
* body User Created user object
|
||||
* no response value expected for this operation
|
||||
* */
|
||||
const createUser = ({ body }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
body,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Creates list of users with given input array
|
||||
*
|
||||
* body List List of user object
|
||||
* no response value expected for this operation
|
||||
* */
|
||||
const createUsersWithArrayInput = ({ body }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
body,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Creates list of users with given input array
|
||||
*
|
||||
* body List List of user object
|
||||
* no response value expected for this operation
|
||||
* */
|
||||
const createUsersWithListInput = ({ body }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
body,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Delete user
|
||||
* This can only be done by the logged in user.
|
||||
*
|
||||
* username String The name that needs to be deleted
|
||||
* no response value expected for this operation
|
||||
* */
|
||||
const deleteUser = ({ username }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
username,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Get user by user name
|
||||
*
|
||||
* username String The name that needs to be fetched. Use user1 for testing.
|
||||
* returns User
|
||||
* */
|
||||
const getUserByName = ({ username }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
username,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Logs user into the system
|
||||
*
|
||||
* username String The user name for login
|
||||
* password String The password for login in clear text
|
||||
* returns String
|
||||
* */
|
||||
const loginUser = ({ username, password }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
username,
|
||||
password,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Logs out current logged in user session
|
||||
*
|
||||
* no response value expected for this operation
|
||||
* */
|
||||
const logoutUser = () => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
/**
|
||||
* Updated user
|
||||
* This can only be done by the logged in user.
|
||||
*
|
||||
* username String name that need to be deleted
|
||||
* body User Updated user object
|
||||
* no response value expected for this operation
|
||||
* */
|
||||
const updateUser = ({ username, body }) => new Promise(
|
||||
async (resolve, reject) => {
|
||||
try {
|
||||
resolve(Service.successResponse({
|
||||
username,
|
||||
body,
|
||||
}));
|
||||
} catch (e) {
|
||||
reject(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Create user
|
||||
* This can only be done by the logged in user.
|
||||
*
|
||||
* body User Created user object
|
||||
* no response value expected for this operation
|
||||
**/
|
||||
static createUser({ body }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates list of users with given input array
|
||||
*
|
||||
* body List List of user object
|
||||
* no response value expected for this operation
|
||||
**/
|
||||
static createUsersWithArrayInput({ body }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates list of users with given input array
|
||||
*
|
||||
* body List List of user object
|
||||
* no response value expected for this operation
|
||||
**/
|
||||
static createUsersWithListInput({ body }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user
|
||||
* This can only be done by the logged in user.
|
||||
*
|
||||
* username String The name that needs to be deleted
|
||||
* no response value expected for this operation
|
||||
**/
|
||||
static deleteUser({ username }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user by user name
|
||||
*
|
||||
* username String The name that needs to be fetched. Use user1 for testing.
|
||||
* returns User
|
||||
**/
|
||||
static getUserByName({ username }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs user into the system
|
||||
*
|
||||
* username String The user name for login
|
||||
* password String The password for login in clear text
|
||||
* returns String
|
||||
**/
|
||||
static loginUser({ username, password }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs out current logged in user session
|
||||
*
|
||||
* no response value expected for this operation
|
||||
**/
|
||||
static logoutUser() {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updated user
|
||||
* This can only be done by the logged in user.
|
||||
*
|
||||
* username String name that need to be deleted
|
||||
* body User Updated user object
|
||||
* no response value expected for this operation
|
||||
**/
|
||||
static updateUser({ username, body }) {
|
||||
return new Promise(
|
||||
async (resolve) => {
|
||||
try {
|
||||
resolve(Service.successResponse(''));
|
||||
} catch (e) {
|
||||
resolve(Service.rejectResponse(
|
||||
e.message || 'Invalid input',
|
||||
e.status || 405,
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = UserService;
|
||||
module.exports = {
|
||||
createUser,
|
||||
createUsersWithArrayInput,
|
||||
createUsersWithListInput,
|
||||
deleteUser,
|
||||
getUserByName,
|
||||
loginUser,
|
||||
logoutUser,
|
||||
updateUser,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user