-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
550 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
protobuf2swagger | ||
=== | ||
|
||
Work in progress project for saving some life, update not garrenteed. Welcome for pull request :). | ||
|
||
Main purpose is to convert [protobuf v2](https://developers.google.com/protocol-buffers/docs/proto) file to [openapi v3](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md) JSON schema with NodeJS, and merge with some custom open api configurations. | ||
Then you may render it easily with [SwaggerUI](https://github.com/swagger-api/swagger-ui). | ||
|
||
# What is supported | ||
|
||
- convert *enum*, *message* into components, paths will reference to the components schema | ||
- basic types mapping to JS type *number*, *string*, *boolean* ( long types will be mapped to *string*) | ||
- recognize fields: | ||
- [OperationObject](https://swagger.io/specification/#operationObject).requestBody.$proto | ||
Replace requestBody with a [Reference Object](https://swagger.io/specification/#referenceObject) | ||
- [OperationObject](https://swagger.io/specification/#operationObject).responses.$proto | ||
Replace responses['200'] with a [Reference Object](https://swagger.io/specification/#referenceObject) | ||
|
||
# Install | ||
|
||
`npm i -g protobuf2swagger` | ||
|
||
# Cli Usage | ||
|
||
`protobuf2swagger [config_file]` | ||
|
||
| Argument | Description | | ||
| --- | --- | | ||
| config_file | Customize configuration file. Default to **protobuf2swagger.config.js** under current folder. | | ||
|
||
For options may check `protobuf2swagger --help`. (Nothing there yet, seriously.) | ||
|
||
## Config File | ||
|
||
Example: | ||
```javascript | ||
module.exports = { | ||
file: 'test.proto', | ||
dist: 'apischema.json', | ||
customSchema: { // Similar to openapi v3 format | ||
info: { | ||
title: 'API', | ||
version: '1.0.0', | ||
contact: { | ||
name: 'Jennie Ji', | ||
email: 'jennie.ji@hotmail.com', | ||
url: 'jennieji.github.io' | ||
}, | ||
}, | ||
tags: [{ | ||
name: 'test', | ||
description: '' | ||
}], | ||
paths: { | ||
'/api/test': { | ||
get: { | ||
requestBody: { | ||
$proto: 'GetDataRequest', // Tell me the protobuf message name | ||
}, | ||
responses: { | ||
$proto: 'GetDataResponse', // Tell me the protobuf message name | ||
} | ||
} | ||
} | ||
}, | ||
components: { | ||
securitySchemes: { | ||
cookieAuth: { | ||
type: 'apiKey', | ||
in: 'cookie', | ||
name: 'token' | ||
} | ||
} | ||
}, | ||
security: [{ | ||
cookieAuth: [] | ||
}] | ||
} | ||
}; | ||
``` | ||
|
||
# Display with SwaggerUI | ||
|
||
index.html (modified from swagger-ui-dist) | ||
|
||
```html | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>API Document</title> | ||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.22.2/swagger-ui.css" > | ||
<style> | ||
html | ||
{ | ||
box-sizing: border-box; | ||
overflow: -moz-scrollbars-vertical; | ||
overflow-y: scroll; | ||
} | ||
*, | ||
*:before, | ||
*:after | ||
{ | ||
box-sizing: inherit; | ||
} | ||
body | ||
{ | ||
margin:0; | ||
background: #fafafa; | ||
} | ||
</style> | ||
</head> | ||
|
||
<body> | ||
<div id="swagger-ui"></div> | ||
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.22.2/swagger-ui-bundle.js"> </script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/swagger-ui/3.22.2/swagger-ui-standalone-preset.js"> </script> | ||
<script> | ||
window.onload = function() { | ||
// Begin Swagger UI call region | ||
const ui = SwaggerUIBundle({ | ||
url: "./apischema.json", // Path to the generated schema JSON file | ||
dom_id: '#swagger-ui', | ||
deepLinking: true, | ||
presets: [ | ||
SwaggerUIBundle.presets.apis, | ||
SwaggerUIStandalonePreset | ||
], | ||
plugins: [ | ||
SwaggerUIBundle.plugins.DownloadUrl | ||
], | ||
layout: "StandaloneLayout" | ||
}) | ||
// End Swagger UI call region | ||
window.ui = ui | ||
} | ||
</script> | ||
</body> | ||
</html> | ||
``` | ||
|
||
Serve with simple [express](https://www.npmjs.com/package/express) server: | ||
|
||
```javascript | ||
const express = require('express'); | ||
const app = express(); | ||
|
||
app.use(express.static(__dirname /* path to index.html */)); | ||
app.listen(3000); | ||
|
||
console.info('Served at port 3000'); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#!/usr/bin/env node | ||
'use strict'; | ||
|
||
const path = require('path'); | ||
const program = require('commander'); | ||
const fs = require('fs'); | ||
const convert = require('../utils/convert.js'); | ||
|
||
program.version('0.0.0', '-v --version') | ||
.arguments('[config_file]') | ||
.usage('[config_file]') | ||
.on('--help', () => { | ||
console.log('\n'); | ||
console.log('config_file Customize configuration file. Default to protobuf2swagger.config.js under current folder.') | ||
}) | ||
.parse(process.argv); | ||
|
||
const [configPath] = program.args; | ||
const cwd = process.cwd(); | ||
const DEFAULT_CONFIG_PATH = 'protobuf2swagger.config.js'; | ||
const config = require(path.resolve(cwd, configPath || DEFAULT_CONFIG_PATH)); | ||
|
||
|
||
(async () => { | ||
const content = await convert(config); | ||
const dist = config.dist ? path.resolve(cwd, config.dist) : cwd; | ||
fs.writeFileSync(dist, JSON.stringify(content, null, 2)); | ||
console.info('Converted schema written into ', dist); | ||
})(); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"name": "protobuf2swagger", | ||
"version": "0.0.0-alpha.1", | ||
"description": "Convert protobuf to swagger open api v3 format", | ||
"main": "index.js", | ||
"bin": { | ||
"protobuf2swagger": "./bin/protobuf2swagger.js" | ||
}, | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/JennieJi/protobuf2swagger" | ||
}, | ||
"keywords": [ | ||
"protobuf" | ||
], | ||
"author": "Jennie Ji <jennie.ji@hotmail.com>", | ||
"license": "MIT", | ||
"dependencies": { | ||
"commander": "^2.20.0", | ||
"protobufjs": "^6.8.8" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
function bakeRef(name) { | ||
return `#/components/schemas/${name}`; | ||
} | ||
|
||
module.exports = bakeRef; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
const protobuf = require('protobufjs'); | ||
const fs = require('fs'); | ||
const processPaths = require('./processPaths.js'); | ||
const processComponents = require('./processComponents'); | ||
|
||
const OPENAPI_VERSION = '3.0.0'; | ||
|
||
async function convert({ | ||
file, | ||
customSchema | ||
}) { | ||
// TODO: custom schema validate | ||
const rootProto = await protobuf.parse(fs.readFileSync(file).toString(), { | ||
alternateCommentMode: true | ||
}); | ||
const { paths: rawPaths, components: rawComponents } = customSchema; | ||
return { | ||
...customSchema, | ||
openapi: OPENAPI_VERSION, | ||
paths: processPaths(rawPaths), | ||
components: { | ||
...(rawComponents || {}), | ||
schemas: { | ||
...processComponents(getProtoByPath(rootProto)), | ||
...(rawComponents || {}).schemas, | ||
} | ||
} | ||
}; | ||
} | ||
|
||
function getProtoByPath(proto) { | ||
return proto.package | ||
.split('.') | ||
.reduce((data, path) => data.get(path), proto.root) | ||
.nested; | ||
} | ||
|
||
module.exports = convert; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
function enum2JSON(proto) { | ||
const { values, comments } = proto; | ||
return { | ||
type: "number", | ||
enum: Object.values(values), | ||
description: Object.keys(values).map(key => `${values[key]} - ${key} ${comments[key] ? `// ${comments[key]}` : ''}`).join('<br/>') | ||
}; | ||
} | ||
|
||
module.exports = enum2JSON; |
Oops, something went wrong.