Skip to content

Commit

Permalink
Merge d7dcd56 into 185472f
Browse files Browse the repository at this point in the history
  • Loading branch information
ben-vr committed Jan 29, 2019
2 parents 185472f + d7dcd56 commit 62a0277
Show file tree
Hide file tree
Showing 11 changed files with 387 additions and 11 deletions.
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,9 @@ treehouse.startServer(app, {

### setSwagger(app, route, filePath, options)

Serve Swagger UI via the a provided Swagger yaml file.
Serve Swagger UI via the a provided Swagger yaml file OR folder with valid structure and yaml files.

### YAML file implementation
```javascript
const app = express();

Expand All @@ -154,6 +155,33 @@ treehouse.setSwagger(app, '/documentation', 'documentation/swagger.yml', {
- [All available swagger-ui options](https://github.com/swagger-api/swagger-ui)
### Folder implementation with valid structure
Structure
```bash
.
├── validFolderName
| ├── index.yml # contains basic info + definition models
| └── routes
| ├── route1.yml
| └── randomName.yml
| ├── ... # more yml files
```
WARNING !!: make sure index.yml contains 'paths:' at the LAST LINE
```javascript
const app = express();

treehouse.setSwagger(app, '/documentation', './validFolderName', {
host: 'localhost:3000',
schemes: ['http'],
concatenate : true, // The property to enable folder functionality
};
```
- [All available swagger-ui options](https://github.com/swagger-api/swagger-ui)
## Validator
### validateSchema(schema, options)
Expand Down
7 changes: 3 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"build": "npm run clean && tsc",
"start": "npm run build && node build/index.js",
"lint": "tslint 'src/**/*.ts'",
"test": "jest",
"test:coverage": "jest --coverage --collectCoverageFrom=src/**/*.ts",
"test": "jest --forceExit",
"test:coverage": "jest --coverage --collectCoverageFrom=src/**/*.ts --forceExit",
"test:watch": "jest --watchAll",
"pretest": "npm run build",
"prepare": "npm run build",
Expand All @@ -20,6 +20,7 @@
"lint"
],
"dependencies": {
"@types/node": "^10.12.18",
"body-parser": "~1.18.3",
"cors": "~2.8.5",
"express": "~4.16.4",
Expand Down
53 changes: 49 additions & 4 deletions src/lib/swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,67 @@ import { Application } from 'express';
import * as swaggerUi from 'swagger-ui-express';
import * as yaml from 'js-yaml';
import * as fs from 'fs';
import * as path from 'path';

/**
* Serve swagger documentation
*/
export function setSwagger(app: Application, route: string, filePath: string, options: SwaggerOptions = {}): void {
try {
// Load yaml document
const swaggerDocument = yaml.safeLoad(fs.readFileSync(filePath, 'utf8'));
Object.assign(swaggerDocument, options);
const stats = fs.lstatSync(filePath);
let swaggerDocument;

if (options.concatenate) {
// Throw error if concatenate = true and filepath = file
if (stats.isFile()) {
throw new Error('Boolean concatenate cannot be true when you specify a file. When you want to concatenate, specify a folder');
}
if (stats.isDirectory()) {
const swaggerContent = buildSwaggerDocumentFromFiles(filePath);
swaggerDocument = yaml.safeLoad(swaggerContent);
}
} else {
if (stats.isFile()) {
// Load yaml document
swaggerDocument = yaml.safeLoad(fs.readFileSync(filePath, 'utf8'));
Object.assign(swaggerDocument, options);
}
if (stats.isDirectory()) {
throw new Error('To concatenate a folder of swagger YMLS, you need to explicitly set the boolean concatenate on true for the swaggerOptions');
}
}

// Bugfix to host multiple swagger definitions see:
// https://github.com/scottie1984/swagger-ui-express/issues/92#issuecomment-454034754
const useSchema = schema => (...args) => swaggerUi.setup(schema)(...args);

// Serve the document served via swagger-ui
app.use(route, swaggerUi.serve, swaggerUi.setup(swaggerDocument));
app.use(route, swaggerUi.serve, useSchema(swaggerDocument));
} catch (e) {
throw new Error(`Failed to load swagger documentation: ${e}`);
}
}

function buildSwaggerDocumentFromFiles(filePath: string) {
let swaggerDocument = '';
try {
swaggerDocument += fs.readFileSync(path.join(filePath, 'index.yml'), 'utf8');
} catch (error) {
throw new Error(`Could not read index.yml make sure the file is named: index.yml and in the correct folder ${error}`);
}

try {
const routeFiles = fs.readdirSync(path.join(filePath, 'routes'));
routeFiles.forEach((file) => {
swaggerDocument += fs.readFileSync(path.join(filePath, 'routes', file), 'utf8');
});
} catch (error) {
throw new Error(`Error while reading routes folder. Make sure there is one! , ${error}`);
}

return swaggerDocument;
}

// Interfaces
export interface SwaggerOptions {
swaggerUrl?: string;
Expand All @@ -31,4 +75,5 @@ export interface SwaggerOptions {
swaggerOptions?: {
validatorUrl?: string | null,
};
concatenate?: boolean;
}
69 changes: 69 additions & 0 deletions tests/assets/almostValidDocsFolder/endpoints/pet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/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"
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"
securityDefinitions:
petstore_auth:
type: "oauth2"
authorizationUrl: "http://petstore.swagger.io/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"
16 changes: 16 additions & 0 deletions tests/assets/almostValidDocsFolder/index.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
swagger: "2.0"
info:
description: "This is a module with some functions"
version: "1.0.0"
title: "Treehouse swagger"
host: "petstore.swagger.io"
basePath: "/v2"
tags:
- name: "pet"
description: "Everything about your Pets"
externalDocs:
description: "Find out more"
url: "http://swagger.io"
schemes:
- "http"
paths:
16 changes: 16 additions & 0 deletions tests/assets/docsFolder/base.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
swagger: "2.0"
info:
description: "This is a module with some functions"
version: "1.0.0"
title: "Treehouse swagger"
host: "petstore.swagger.io"
basePath: "/v2"
tags:
- name: "pet"
description: "Everything about your Pets"
externalDocs:
description: "Find out more"
url: "http://swagger.io"
schemes:
- "http"
paths:
69 changes: 69 additions & 0 deletions tests/assets/docsFolder/endpoints/pet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/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"
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"
securityDefinitions:
petstore_auth:
type: "oauth2"
authorizationUrl: "http://petstore.swagger.io/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"
16 changes: 16 additions & 0 deletions tests/assets/validDocsFolder/index.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
swagger: "2.0"
info:
description: "This is a module with some functions"
version: "1.0.0"
title: "Treehouse swagger"
host: "petstore.swagger.io"
basePath: "/v2"
tags:
- name: "pet"
description: "Everything about your Pets"
externalDocs:
description: "Find out more"
url: "http://swagger.io"
schemes:
- "http"
paths:
Loading

0 comments on commit 62a0277

Please sign in to comment.