Last active
January 7, 2020 17:21
-
-
Save crrobinson14/7cdfcda6d7c15551923d4d235197f5d3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FROM node:8.6.0 | |
#USER node | |
# Deal with node-gyp permissions issues in Docker | |
RUN npm -g config set user root | |
RUN mkdir /root/.npm-global | |
ENV PATH=/root/.npm-global/bin:$PATH | |
ENV NPM_CONFIG_PREFIX=/root/.npm-global | |
# Base tools | |
RUN apt-get update && \ | |
apt-get -y install less man ssh python python-pip libpython-dev python-dev jq apt-transport-https \ | |
curl apt-transport-https ca-certificates mysql-client && \ | |
rm -rf /var/lib/apt/lists/* | |
# Install Docker | |
RUN echo deb https://apt.dockerproject.org/repo debian-jessie main > /etc/apt/sources.list.d/docker.list && \ | |
apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D && \ | |
apt-get update && \ | |
apt-cache policy docker-engine && \ | |
apt-get install docker-engine -y && \ | |
rm -rf /var/lib/apt/lists/* | |
# jFrog CLI | |
RUN curl -fL https://getcli.jfrog.io | sh | |
# AWS CLI and MkDocs tools | |
ENV PYTHONIOENCODING=UTF-8 | |
RUN pip install awscli mkdocs mkdocs-material pymdown-extensions pygments && \ | |
npm install -g jsdoc-to-markdown swagger-markdown && \ | |
npm cache clean --force | |
# Install vault for firebase vault sync service | |
RUN apt-get update && apt-get -y install unzip | |
RUN curl -O https://releases.hashicorp.com/vault/0.8.3/vault_0.8.3_linux_amd64.zip && \ | |
unzip vault_0.8.3_linux_amd64.zip && mv vault /usr/local/bin/ | |
# Module publishing tools | |
COPY scripts/bump-npm.sh /usr/local/bin/ | |
COPY scripts/bump-docker.sh /usr/local/bin/ | |
COPY scripts/notify-slack-npm.sh /usr/local/bin/ | |
COPY scripts/push-docker-jfrog.sh /usr/local/bin/ | |
COPY scripts/copy-maxmind-db.sh /usr/local/bin/ | |
COPY scripts/ecs-deploy.sh /usr/local/bin/ | |
COPY scripts/copy-docker-jfrog-ecr.sh /usr/local/bin/ | |
COPY scripts/s3-deploy.sh /usr/local/bin/ | |
COPY scripts/s3-copy-api-docs.sh /usr/local/bin/ | |
COPY scripts/s3-copy-project-docs.sh /usr/local/bin/ | |
COPY scripts/notify-slack-microsvc.sh /usr/local/bin/ | |
COPY scripts/notify-slack-site.sh /usr/local/bin/ | |
COPY scripts/notify-slack-on-failure.sh /usr/local/bin/ | |
COPY scripts/launch-review-app.sh /usr/local/bin/ | |
COPY scripts/destroy-review-app.sh /usr/local/bin/ | |
COPY scripts/notify-slack-reviewapp.sh /usr/local/bin/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
site_name: Auth Service | |
site_url: http://web-ng-docs.s3-website-us-east-1.amazonaws.com/web-services/auth | |
theme: material | |
extra: | |
palette: | |
primary: 'blue grey' | |
accent: 'green' | |
site_dir: public | |
pages: | |
- Home: index.md | |
- API: api.md | |
- TODO: todo.md | |
- Last Test Results: test.md | |
- Schema: schema.md | |
- Security: security.md | |
- Link Dump: links.md | |
markdown_extensions: | |
- admonition | |
- codehilite(linenums=true) | |
- footnotes | |
- meta | |
- toc(permalink=true) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"scripts": { | |
"docs_schema": "sequelize-erd --source ./lib/models --destination ./docs/img/schema.svg", | |
"docs_readme": "cp README.md docs/index.md", | |
"docs_mkdocs": "mkdocs build", | |
"docs_todo": "leasot -r markdown */*.js functions/**/*.js test/**/*s.js > docs/todo.md || true", | |
"docs_swagger": "node_modules/.bin/serverless-swagger && swagger-markdown -i docs/swagger.yml -o docs/api.md", | |
"docs": "npm run build_yml && npm run docs_swagger && npm run docs_readme && npm run docs_mkdocs && npm run docs_todo" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
const fs = require('fs'); | |
const path = require('path'); | |
const json2yaml = require('json2yaml'); | |
const yaml = require('js-yaml'); | |
// eslint-disable-next-line import/no-dynamic-require | |
const packageJson = require(path.join(process.cwd(), 'package.json')); | |
const SWAGGER_SPEC_DIR = "docs"; | |
const SWAGGER_SPEC_NAME = "swagger.yml"; | |
const MODELS_FILE = "lib/orm.js"; | |
class Swagger { | |
constructor(functions) { | |
this.functions = functions; | |
this.doc = {}; | |
this.definitions = {}; | |
} | |
static standardResponses() { | |
return { | |
401: { | |
description: 'Session Error. Required authentication was missing or invalid for the requested resource.' | |
}, | |
403: { | |
description: 'Forbidden. Authentication was provided, but not sufficient for the request.' | |
}, | |
404: { | |
description: 'Not Found. The primary content related to the request does not exist.' | |
}, | |
405: { | |
description: 'Request Error. An required input parameter was missing or invalid.' | |
}, | |
429: { | |
description: 'Quota Exceeded. Reduce request rate.' | |
}, | |
500: { | |
description: 'Internal server error. Try again later.' | |
} | |
}; | |
} | |
static typeLookup(attribute) { | |
const types = { | |
STRING: 'string', | |
CHAR: 'string', | |
TEXT: 'string', | |
NUMBER: 'integer', | |
INTEGER: 'integer', | |
BIGINT: 'integer', | |
FLOAT: 'number', | |
TIME: 'string', | |
DATE: 'string', | |
DATEONLY: 'string', | |
BOOLEAN: 'boolean', | |
NOW: 'string', | |
BLOB: 'string', | |
DECIMAL: 'number', | |
NUMERIC: 'number', | |
UUID: 'string', | |
UUIDV1: 'string', | |
UUIDV4: 'string', | |
ENUM: 'string', | |
INT32: 'integer', | |
INT64: 'integer', | |
DOUBLE: 'number', | |
BYTE: 'string', | |
'DATE-TIME': 'string', | |
VARCHAR: 'string', | |
TIMESTAMP: 'string', | |
REAL: 'number', | |
}; | |
const formats = { | |
INTEGER: 'int32', | |
INT32: 'integer', | |
INT64: 'int64', | |
BIGINT: 'int64', | |
FLOAT: 'float', | |
DOUBLE: 'double', | |
DATE: 'date-time', | |
'DATE-TIME': 'date-time', | |
DATEONLY: 'date', | |
BLOB: 'binary', | |
}; | |
const typeKey = attribute.type.key; | |
const type = { | |
type: types[typeKey] || 'string', | |
description: attribute.comment, | |
}; | |
if (formats[typeKey]) { | |
type.format = formats[typeKey]; | |
} | |
if (typeKey === 'ENUM') { | |
type.enum = attribute.type.values; | |
} | |
if (typeKey === 'UUID') { | |
type.maxLength = 36; | |
} | |
if (attribute.allowNull) { | |
type.nullable = true; | |
} | |
return type; | |
} | |
generate() { | |
return this | |
.header() | |
.paths() | |
.objectDefinitions(); | |
} | |
toYAML() { | |
return json2yaml.stringify(this.doc); | |
} | |
// add spec summary | |
header() { | |
const swaggerMeta = packageJson.swagger || {}; | |
Object.assign(this.doc, { | |
swagger: '2.0', | |
info: { | |
description: swaggerMeta.description || packageJson.description, | |
version: swaggerMeta.version || packageJson.version, | |
title: swaggerMeta.title || packageJson.name, | |
termsOfService: swaggerMeta.termsOfService || 'http://www.snap-interactive.com/terms-of-service/', | |
contact: { | |
email: swaggerMeta.contact || packageJson.author | |
} | |
}, | |
host: swaggerMeta.uri || `${packageJson.name}.apis.theirweb.net`, | |
basePath: swaggerMeta.basePath || '/v1', | |
schemes: swaggerMeta.schemes || ['https'], | |
}); | |
return this; | |
} | |
// return the metadata of the given function handler | |
getHandlerData(handler) { | |
return require(path.join(process.cwd(), handler)); | |
} | |
// add path entries | |
paths() { | |
this.doc.paths = {}; | |
// functions | |
Object.keys(this.functions).forEach(f => { | |
const func = this.functions[f]; | |
const handlerPath = this.getHandlerPath(func.handler); | |
const metadata = this.getHandlerData(handlerPath); | |
// include only the funtions with a description for its handler | |
if (metadata.description) { | |
func.events.forEach(event => { // events | |
// summary | |
const path = event.http.path; | |
const method = event.http.method; | |
this.doc.paths[path] = this.doc.paths[path] || {}; | |
this.doc.paths[path][method] = this.doc.paths[path][method] || {}; | |
if (metadata.tags) { | |
this.doc.paths[path][method].tags = metadata.tags; | |
} | |
this.doc.paths[path][method].summary = metadata.name; | |
this.doc.paths[path][method].description = metadata.description; | |
this.doc.paths[path][method].operationId = metadata.name; | |
this.doc.paths[path][method].consumes = ['application/json']; | |
this.doc.paths[path][method].produces = ['application/json']; | |
// output (response) | |
const responseSchema = {}; | |
Object.keys(metadata.output).sort().forEach(key => { | |
const type = metadata.output[key].type; | |
if (['string', 'object', 'number', 'integer', 'boolean'].indexOf(type) !== -1) { | |
responseSchema.type = type; | |
} else if (type === 'array') { | |
responseSchema.type = type; | |
const items = metadata.output[key].items.substring(1); | |
this.definitions[items] = true; | |
responseSchema.items = { | |
$ref: `#/definitions/${items}` | |
}; | |
} else if (type.charAt(0) === '#') { | |
const model = type.substring(1); | |
this.definitions[model] = true; | |
responseSchema.$ref = `#/definitions/${model}`; | |
} | |
}); | |
const response = { | |
200: { | |
description: metadata.output.description || "", | |
headers: metadata.output.headers || {}, | |
schema: responseSchema, | |
} | |
}; | |
this.doc.paths[path][method].responses = Object.assign( | |
response, | |
Swagger.standardResponses() | |
); | |
// inputs (parameters) | |
if (metadata.inputs) { | |
this.doc.paths[path][method].parameters = []; | |
Object.keys(metadata.inputs).sort().forEach(inputKey => { | |
const input = metadata.inputs[inputKey]; | |
const paramLocation = input.type && input.type.charAt(0) === '#' ? 'body' : 'query'; | |
const param = { in: paramLocation, | |
name: inputKey, | |
description: input.description, | |
required: input.required, | |
}; | |
if (paramLocation === 'body') { | |
const definition = input.type.substring(1); | |
this.definitions[definition] = true; | |
param.schema = { | |
$ref: `#/definitions/${definition}` | |
}; | |
} else { | |
param.type = input.type || 'string'; | |
} | |
this.doc.paths[path][method].parameters.push(param); | |
}); | |
} | |
}); | |
} | |
}) | |
return this; | |
} | |
// models | |
objectDefinitions() { | |
const orm_path = path.join(process.cwd(), MODELS_FILE); | |
if (fs.existsSync(orm_path)) { | |
const ORM = require(orm_path); | |
Object.keys(ORM.models).sort().forEach(model => { | |
const rawAttributes = ORM.models[model].rawAttributes || {}; | |
const properties = {}; | |
Object.keys(rawAttributes).sort().forEach(key => { | |
properties[key] = Swagger.typeLookup(rawAttributes[key]); | |
}); | |
this.doc.definitions = this.doc.definitions || {}; | |
this.doc.definitions[model] = { | |
type: 'object', | |
description: ORM.models[model].options.comment, | |
properties | |
}; | |
}); | |
} else { | |
console.log(`ORM models file does not exist.`); | |
} | |
return this; | |
} | |
// Return the path of the given handler | |
getHandlerPath(handler) { | |
const parsedPath = path.parse(handler); | |
return path.join(parsedPath.dir, parsedPath.name); | |
} | |
} | |
if (require.main === module) { | |
const configFilePath = path.join(process.cwd(), 'serverless.yml'); | |
try { | |
// Read functions | |
var _config = yaml.safeLoad(fs.readFileSync(configFilePath, 'utf8')); | |
var _functions = _config.functions; | |
// Generate Swagger yml from the functions' meta-data | |
const spec = new Swagger(_functions).generate().toYAML(); | |
// Write swagger spec to the specified file | |
fs.writeFileSync(path.join(SWAGGER_SPEC_DIR, SWAGGER_SPEC_NAME), spec); | |
process.exit(0); | |
} catch (e) { | |
console.log(`Error in reading the serverless functions. ${e}`); | |
} | |
} else { | |
module.exports = Swagger; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment