Skip to content

Commit

Permalink
Merge pull request #12 from vitwit/changeAPI
Browse files Browse the repository at this point in the history
Changed API to follow standard way of providing cli arguments, updated error cases
  • Loading branch information
anilcse authored Sep 21, 2019
2 parents 1254297 + 85d84f1 commit 58f9cf3
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 141 deletions.
27 changes: 13 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
# JS-SDKGen

JS-SDKGen is JavaScript API SDK Code generator, based on json file generated for api docs by Swagger or Goland or optionally your own json file with any shape with transform function. It just requires a apidoc definition (swagger/godac style supported now) and it generates the JavaScript SDK for you. Thus eliminate the work of writing your own SDK. It can run in both browser(a tool can be made) and node.
JS-SDKGen is JavaScript API SDK Code generator, based on json file generated for api docs by Swagger or apidocjs or optionally your own json file with any shape with transform function. It just requires a apidoc definition (swagger and apidocjs genenrated api docs aslo supported now) and it generates the JavaScript SDK for you. Thus eliminate the work of writing your own SDK. It can run in both browser(a tool can be made) and node.

clone the repo

```sh
npm install -g js-sdkgen
js-sdkgen jsonFilePath=api-docs.json --isSwagger/--isGo name=MySDK version=1.0.0 baseUrl=http://vitwit.com/api --headers accountId=true authorization=false
js-sdkgen --json-file=api-docs.json name=MySDK --version=1.0.0 base-url=http://vitwit.com/api --requiredHeaders accoundId,key --optionalHeaders name
```

Below are parameter available for node cli while generating SDK.

| param | use | optional or required |
| ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `jsonFilePath` | path of json | required (if not provided will look for 'api-docs.json' file in current directory) |
| `jsFilePath` | path of a js file which named exports two function `transformJson` and `transformOperations` | not required if json is already in below mentioned format or no operation's response data need to be transformed |
| `--isSwagger` | pass this flag if json file generated by swagger | required if json generated by swagger |
| `--isGo` | flag to be provided if json file generated using go docs | required if json generated by go docs |
| `baseUrl` | base url of your app, will be passed axios instance | required |
| `name` | it will be name of generated sdk class | optional |
| `version` | version of sdk | optional |
| `--headers OptionalHeader1=false MandatoryHeader1=true` | after `--headers` flag every field will be considered as a header, if passed true those will be required to pass when initiate the sdk class on frontend |
| param | alias | usage | optional or required |
| ------------------- | ----- | -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `--json-file` | `-f` | path of json | required (if not provided will look for 'api-docs.json' file in current directory) |
| `--js-file` | `-j` | path of a js file which named exports two function `transformJson` and `transformOperations` | not required if json is already in below mentioned format or no operation's response data need to be transformed | |
| `--base-url` | `-b` | base url of your app, will be passed axios instance | required |
| `--name` | `-n` | it will be name of generated sdk class | optional |
| `--version` | `-v` | version of sdk | optional |
| `--requiredHeaders` | `-r` | requirdHeaders params will berequired to pass when initiate the sdk class on frontend |
| `--optionalHeaders` | `-o` | |

any other parameter passed will be added to configs.headers which will be passed to axios instance. All the headers will be used as default headers for every request.

Expand Down Expand Up @@ -50,8 +49,8 @@ mySDK.getHeader("Header1");

Example cli parameters to set MandatoryHeader1, MandatoryHeader2 as required headers, you just need to keep `true` after the header name. If the variable is set to `false` or left blank, it will be considered as Optional Header by the program.

```js
js-sdkgen jsonFilePath=api-docs.json --isSwagger name=MySDK version=1.0.0 baseUrl=http://vitwit.com/api --headers MandatoryHeader1=true MandatoryHeader2=true OptionalHeader1=false OptionalHeader2
```sh
js-sdkgen --json-file api-docs.json --name=MySDK --version=1.0.0 --base-url=http://vitwit.com/api --requiredHeaders a,b,c --optionalHeaders d,e,f
```

these configs can overridden or more configs can be passed from frontend before intiating the class as below.
Expand Down
12 changes: 11 additions & 1 deletion package-lock.json

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

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
],
"license": "MIT",
"dependencies": {
"arg": "^4.1.1",
"chalk": "^2.4.2",
"cp": "^0.2.0",
"esm": "^3.2.18",
"listr": "^0.14.3"
},
Expand Down
120 changes: 50 additions & 70 deletions src/cli.js
Original file line number Diff line number Diff line change
@@ -1,86 +1,66 @@
import chalk from "chalk";
import arg from "arg";
import { createProject } from "./main";
import { printManPage } from "./utils";

function parseArgumentsIntoOptions(rawArgs) {
let flagsArr = []; // --isSwagger and --isGo
let headerParams = []; // any param after --headers
let requiredHeaders = []; // i.e --headers appid=true,
let optionalHeaders = [];
let othersArgs = {}; // all params before --headers except flags

const parseArgs = argArr => {
// here push complete "param=valueifany", later we modify this array to have only param, because value is just to know if it a required field
headerParams =
argArr.indexOf("--headers") >= 0
? argArr.splice(argArr.indexOf("--headers") + 1)
: [];

flagsArr = (argArr || []).filter(arg =>
["--isSwagger", "--isGo"].includes(arg)
);

const otherParams = (argArr || []).filter((arg, index) =>
argArr.indexOf("--headers") === -1
? true
: index < argArr.indexOf("--headers") && !arg.includes("--")
);

// get required fields
headerParams.forEach((arg, index) => {
const splitted = headerParams[index].split("=");
if (splitted[1]) {
requiredHeaders.push(splitted[0]);
}
let args;
try {
args = arg({
// Types
"--json-file": String, // --jsonFile <string> or --jsonFile=<string>
"--version": String,
"--js-file": String,
"--name": String,
"--base-url": String,
"--required-headers": [String],
"--optional-headers": [String],
"--help": Boolean,
// Aliases
"-f": "--json-file",
"-f": "--js-file",
"-v": "--version",
"-b": "--base-url",
"-h": "--help",
"-o": "--optional-headers",
"-r": "--required-headers",
"-h": "--help"
});
} catch (err) {
if (err.code === "ARG_UNKNOWN_OPTION") {
console.log(
`
%s ${err.message}
`,
chalk.red.bold("ERROR")
);
process.exit(1);
} else {
throw err;
}
}

// keep only params remove value
headerParams = headerParams.map(arg => arg.split("=")[0]);

optionalHeaders = headerParams.filter(
arg => requiredHeaders.indexOf(arg) < 0
);

// make a key-value obj of all other params before --headers
othersArgs = (otherParams || []).reduce(
(acc, current) => {
const splitFromEqual = (current || []).split("=");
const key = splitFromEqual[0];
const value = splitFromEqual[1];
return {
...acc,
[key]: value
};
},
{ jsonFilePath: "api-docs.json" }
);
};
parseArgs(rawArgs.slice(2));
if (args["--help"]) {
printManPage();
process.exit(1);
}

return {
...othersArgs,
requiredHeaders,
optionalHeaders,
flags: {
isGoGenerated: flagsArr.includes("--isGo"),
isSwaggerGenerated: flagsArr.includes("--isSwagger")
}
requiredHeaders: args["--required-headers"],
optionalHeaders: args["--optional-headers"],
name: args["--name"],
baseUrl: args["--base-url"],
version: args["--version"],
jsonFile: args["--json-file"],
jsFile: args["--js-file"]
};
}

export async function cli(args) {
let options = parseArgumentsIntoOptions(args);
if (options.flags.isGoGenerated && options.flags.isSwaggerGenerated) {
console.error(
"%s you provided both flags '--isGo' and '--isSwaggerGenerated' ",
chalk.red.bold("ERROR")
);
process.exit(1);
}
if (!options.jsonFilePath) {
console.error(
"%s json file is required else pass minus character to look for default 'api-docs.json' file",
chalk.red.bold("ERROR")
);

if (!options.jsonFile) {
console.error("%s --json-file is required", chalk.red.bold("ERROR"));
process.exit(1);
}
await createProject(options);
Expand Down
18 changes: 15 additions & 3 deletions src/codeStrings.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ const stringOne = ({
version,
baseUrl,
requiredHeaders,
optionalHeaders
optionalHeaders,
transformOperations
}) => {
return `
import axios from "axios";
${
transformOperations
? "import { transformOperations } from './transformOperations'"
: ""
}
export default class ${sdkName} {
constructor( headersObj ={}) {${
version ? "\n this.version =" : ""
Expand Down Expand Up @@ -55,6 +60,7 @@ export default class ${sdkName} {
_data,
_url,
_params = {},
transformResponse,
_pathParams = [],
headerConfigs = {}
}) {
Expand Down Expand Up @@ -82,6 +88,7 @@ export default class ${sdkName} {
url,
method,
data,
...(transformResponse ? { transformResponse } : {}),
...(Object.keys(_params).length ? { params: _params } : {}),
...(isFormData
? {
Expand Down Expand Up @@ -141,9 +148,12 @@ export default class ${sdkName} {
`;
};

const getTransformResString = key =>
`\n transformResponse:transformOperations['${key}'],`;
function functionSignature({
hasPathParams,
operationName,
transformResponse,
url,
requestMethod,
isFormData
Expand All @@ -159,7 +169,9 @@ function functionSignature({
_url: '${url}',${
requestMethod === "PUT" || requestMethod === "POST" ? "\n _data," : ""
}
_params,${hasPathParams ? "\n _pathParams," : ""}
_params,${hasPathParams ? "\n _pathParams," : ""}${
transformResponse ? getTransformResString(operationName) : ""
}
});
}
`;
Expand Down
Loading

0 comments on commit 58f9cf3

Please sign in to comment.