Skip to content

Commit

Permalink
Merge pull request #1 from nkmr-jp/feature-add-auth
Browse files Browse the repository at this point in the history
Add feature that POST request support and command line interface.
  • Loading branch information
nkmr-jp authored Aug 16, 2022
2 parents ba603fb + f1c25e7 commit a3a21f8
Show file tree
Hide file tree
Showing 8 changed files with 299 additions and 85 deletions.
65 changes: 52 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,53 @@ npm i -g @nkmr-jp/api-to-go
```

# Usage
add config file `.api-to-go.yml`.
```yaml
```sh
$ api-to-go --help
Usage: api-to-go [options] <url> [body]

Convert REST API's JSON payload to Golang struct.
Arguments:
url URL (required)
body HTTP request body. specify by json string or file(json|yml).
Options:
-v, --version output the current version
-H, --headers <string> http request headers. specify by json string or file(json|yml).
-X, --method <string> specify request method to use.
--config <string> location of client config files. (default: "./.api-to-go.yml")
-D, --debug enable debug mode
-h, --help display help for command
```
# Quick Start
Add config file `.api-to-go.yml`.
```yml
api.github.com:
docs:
- https://docs.github.com/en/rest
format:
- /users/{user}
- /users/{user}/repos
```
run command.
Run command.
```sh
cd [your project dir]
api-to-go https://api.github.com/users/github/repos
# > format: /users/{user}/repos
# > generated: api.github.com/users/user/repos.go
# > saved: api.github.com/users/user/repos_sample.json
# > Status: 200 OK
# > Request: GET https://api.github.com/users/github/repos
# > Format: /users/{user}/repos
# > Docs: https://docs.github.com/en/rest
# > Response Body:
# > - api.github.com/users/user/repos.go:1
# > - api.github.com/users/user/repos.json:1
```
check generated files and directories.
Generated files and directories.
```sh
tree -a .
# > .
Expand All @@ -33,19 +64,26 @@ check generated files and directories.
# > └── users
# > └── user
# > ├── repos.go
# > └── repos_sample.json
# > └── repos.json
```
check generated struct file `./api.github.com/users/user/repos.go`.
Generated struct file `./api.github.com/users/user/repos.go`.
```go
// Generated Code But Editable.
// Format The Code with `go fmt` or something and edit it manually to use it.
//
// Generated by: api-to-go (https://github.com/nkmr-jp/api-to-go).
package user
import "time"
// Repos is the go struct of api's payload.
//
// url: https://api.github.com/users/{user}/repos
// example: https://api.github.com/users/github/repos
// Repos represents the response body from an HTTP request.
//
// Status: 200 OK
// Request: GET https://api.github.com/users/github/repos
// Format: /users/{user}/repos
// Docs: https://docs.github.com/en/rest
type Repos []struct {
ID int `json:"id"`
NodeID string `json:"node_id"`
Expand Down Expand Up @@ -118,6 +156,7 @@ type Repos []struct {
License interface{} `json:"license"`
AllowForking bool `json:"allow_forking"`
IsTemplate bool `json:"is_template"`
WebCommitSignoffRequired bool `json:"web_commit_signoff_required"`
Topics []interface{} `json:"topics"`
Visibility string `json:"visibility"`
Forks int `json:"forks"`
Expand Down
69 changes: 17 additions & 52 deletions bin/api-to-go.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,20 @@
#! /usr/bin/env node
const fetch = require('node-fetch');
const fs = require('fs');
const jsonToGo = require('../vendor/json-to-go.js');
const buildPath = require('../src/buildPath');
const run = require('../src/run');
const {Command} = require('commander');
const program = new Command();
const packageJson = require('../package.json');

function run(url) {
const apiUrl = url.replace(/\/$/, '')
fetch(apiUrl)
.then(res => res.json())
.then(json => {
const url = new URL(apiUrl);
const path = buildPath(url)
const res = jsonToGo(JSON.stringify(json), path.struct);
const content = _buildContent(res.go, path, url)
fs.mkdirSync(path.dir, {recursive: true})
fs.writeFile(path.jsonFilePath, JSON.stringify(json, null, "\t"), (err) => {
if (err) throw err;
console.log(`saved: ${path.jsonFilePath}`)
});
fs.writeFile(path.goFilePath, content, (err) => {
if (err) throw err;
console.log(`generated: ${path.goFilePath}`)
});
}
);
}
// See: https://github.com/tj/commander.js
program
.name('api-to-go')
.version(packageJson.version,'-v, --version', 'output the current version')
.description(packageJson.description)
.argument('<url>', 'URL (required)')
.argument('[body]', 'HTTP request body. specify by json string or file(json|yml).')
.option('-H, --headers <string>', 'http request headers. specify by json string or file(json|yml).')
.option('-X, --method <string>', 'specify request method to use.')
.option('--config <string>', 'location of client config files.',"./.api-to-go.yml")
.option('-D, --debug', 'enable debug mode')
.action(run)

function _buildContent(struct, path, url) {
let content = `package ${path.pkg}\n\n`
if (struct.indexOf('time.') !== -1) {
content = `${content}import "time"\n\n`
}
let comment = `// ${path.struct} is the go struct of api's payload.`
if (path.path.pathFormat) {
comment += `\n//\n// url: ${url.origin}${path.path.pathFormat}`
comment += `\n// example: ${url.href}`
} else {
comment += `\n//\n// url: ${url.href}`
}
content = `${content}${comment}\n//\n${struct}`
return content
}

function _capitalize(str) {
const lower = str.toLowerCase();
return str.charAt(0).toUpperCase() + lower.slice(1);
}

if (process.argv.length !== 3) {
console.log("parameter is wrong.")
return
}

run(process.argv[2])
program.parse();
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"api-to-go": "bin/api-to-go.js"
},
"dependencies": {
"commander": "^9.4.0",
"js-yaml": "^4.1.0",
"node-fetch": "2"
},
Expand Down
25 changes: 8 additions & 17 deletions src/buildPath.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const yaml = require("js-yaml");
const fs = require("fs");
const {loadYaml, loadConfig} = require("./common");

function buildPath(url, configFile = "./.api-to-go.yml") {
function buildPath(url, configFile) {
const path = _buildPath(url, configFile)
const pathArr = path.replacedUrl.split("/")
const pkg = pathArr[pathArr.length - 2].replace(/\./g, '')
Expand All @@ -14,15 +13,16 @@ function buildPath(url, configFile = "./.api-to-go.yml") {
struct,
pkg,
dir,
jsonFilePath: `${dir}/${last}_sample.json`,
goFilePath: `${dir}/${last}.go`
jsonFilePath: `${dir}/${last}.json`,
goFilePath: `${dir}/${last}.go`,
paramJsonFilePath: `${dir}/${last}_param.json`,
paramGoFilePath: `${dir}/${last}_param.go`,
}
}

function _buildPath(url, configFile) {
const cfg = _loadConfig(configFile)
const hostCfg = cfg?.[url.hostname]
let ret ={
const hostCfg = loadConfig(url, configFile)
let ret = {
pathname: url.pathname,
pathFormat: null,
replacedPath: url.pathname,
Expand Down Expand Up @@ -63,7 +63,6 @@ function _replacePath(pathname, format) {
if (replacedArr.length === 0) return

const replacedPath = replacedArr.join("/")
console.log(`format: ${format}`)
return {
pathname: pathname,
pathFormat: format,
Expand All @@ -76,12 +75,4 @@ function _capitalize(str) {
return str.charAt(0).toUpperCase() + lower.slice(1);
}

function _loadConfig(configFile) {
try {
return yaml.load(fs.readFileSync(configFile, 'utf8'));
} catch (e) {
console.log(e);
}
}

module.exports = buildPath;
8 changes: 5 additions & 3 deletions src/buildPath.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ test('build path', () => {
const expected = {
"dir": "api.github.com/users/user",
"goFilePath": "api.github.com/users/user/repos.go",
"jsonFilePath": "api.github.com/users/user/repos_sample.json",
"jsonFilePath": "api.github.com/users/user/repos.json",
"paramGoFilePath": "api.github.com/users/user/repos_param.go",
"paramJsonFilePath": "api.github.com/users/user/repos_param.json",
"path": {
"pathFormat": "/users/{user}/repos",
"pathname": "/users/github/repos",
Expand All @@ -16,7 +18,7 @@ test('build path', () => {
}
const received = buildPath(
new URL("https://api.github.com/users/github/repos"),
"./.api-to-go.test.yaml"
"./.api-to-go.test.yml"
)
expect(received).toEqual(expected);
});
Expand All @@ -30,7 +32,7 @@ test('build path without format setting', () => {
}
const received = buildPath(
new URL("https://api.github.com/organizations"),
"./.api-to-go.test.yaml"
"./.api-to-go.test.yml"
)
expect(received.path).toEqual(expected);
});
53 changes: 53 additions & 0 deletions src/common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const yaml = require("js-yaml");
const fs = require("fs");
const path = require('path')

exports.loadJsonOrYaml = file => {
switch (path.extname(file)) {
case '.json':
return this.loadJson(file)
case '.yml':
return this.loadYaml(file)
case '.yaml':
return this.loadYaml(file)
default:
throw new Error(`${file} is not json or yaml file`);
}
}

exports.loadJson = file => {
return JSON.parse(this.loadFile(file));
};

exports.loadYaml = file => {
return yaml.load(this.loadFile(file));
}

exports.loadFile = file => {
if (!fs.existsSync(file)) {
throw new Error(`${file} is not exists.`);
}
return fs.readFileSync(file, 'utf8');
};

exports.isJsonString = str => {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
};

exports.isYamlString = str => {
try {
yaml.load(str);
} catch (e) {
return false;
}
return true;
};

exports.loadConfig = (url, configFile) => {
return this.loadYaml(configFile)?.[url.hostname]
}
Loading

0 comments on commit a3a21f8

Please sign in to comment.