apib2go
Version:
Convert API Blueprint to golang routers
126 lines (107 loc) • 5.21 kB
JavaScript
'use strict';
var changeCase = require('change-case');
var helpers = require('./helpers').helpers;
module.exports = class GoEchoV2Api {
constructor(api) {
this.api = api;
this.goImports = [];
this.echoRouterParamNames = [];
this.echoRouterLines = [];
this.goLines = [];
}
generateApiCode() {
this.goImports = this.goImports.concat([
'net/http',
'strings',
'fmt',
'github.com/labstack/echo',
]);
this.api.resourceGroups.forEach(group => {
group.resources.forEach(resource => {
this.handleResource(resource);
});
});
}
handleResource(resource) {
let resourceGoStructName = changeCase.camelCase(resource.title);
let resourceGoInterfaceName = changeCase.pascalCase(resource.title);
this.echoRouterParamNames.push(`${resourceGoStructName}Resource ${resourceGoInterfaceName}Resource`);
let echoUrlFmt = resource.href;
echoUrlFmt = echoUrlFmt.replace(/\}/g, '');
echoUrlFmt = echoUrlFmt.replace(/\{/g, ':');
this.echoRouterLines.push(`ctrlAdder.AddPaths([]string{"${echoUrlFmt}"}, e, New${resourceGoInterfaceName}ResourceController(${resourceGoStructName}Resource))`);
let firstLetterOfCtrlName = resourceGoInterfaceName.toLowerCase()[0];
this.goLines.push(``);
this.goLines.push(`func New${resourceGoInterfaceName}ResourceController(resource ${resourceGoInterfaceName}Resource) *${resourceGoStructName}ResourceController {`);
this.goLines.push(` return &${resourceGoStructName}ResourceController {`);
this.goLines.push(` resource: resource,`);
this.goLines.push(` }`);
this.goLines.push(`}`);
this.goLines.push(`// ${resourceGoStructName}Resource from APIBlueprint Resource '${resource.title}'`);
this.goLines.push(`type ${resourceGoStructName}ResourceController struct {`);
this.goLines.push(` *BaseController`);
this.goLines.push(` resource ${resourceGoInterfaceName}Resource`);
this.goLines.push(`}`);
this.goLines.push(``);
this.goLines.push(`func (${firstLetterOfCtrlName} *${resourceGoStructName}ResourceController) SetBaseCtrl(base *BaseController) { ${firstLetterOfCtrlName}.BaseController = base }`);
resource.transitions.forEach(transition => {
this.handleTransition(transition, resourceGoStructName, resource.members);
});
}
handleTransition(transition, resourceGoStructName, resourceMembers) {
if (transition.httpTransactions.length !== 1) {
throw new Error(`Transition '${transition.title}' does not have exactly 1 httpTransaction, this is not currently supported`);
}
var firstHttpTx = transition.httpTransactions[0];
var methodUpper = firstHttpTx.request.method.toUpperCase();
let transitionMethodName = changeCase.pascalCase(transition.title);
var firstLetter = resourceGoStructName[0];
this.goLines.push(`// ${methodUpper} from APIBlueprint Transition '${transition.title}'`);
this.goLines.push(`func (${firstLetter} *${resourceGoStructName}ResourceController) ${methodUpper}(echoCtx echo.Context) error {`);
let methodCallParams = [];
resourceMembers.forEach(member => {
this.handleMemberGetFromQuery(member, methodCallParams);
});
if (firstHttpTx.request.requestContent) {
this.goLines.push(`var postData *${transitionMethodName}Input`);
this.goLines.push(`if err := echoCtx.Bind(postData); err != nil {`);
this.goLines.push(` return fmt.Errorf("Cannot parse body, error: %s", err.Error())`);
this.goLines.push(`}`);
methodCallParams.push(`postData`);
}
let joinedMethodParams = methodCallParams.join(', ');
this.goLines.push(` result, err := ${firstLetter}.resource.${transitionMethodName}(${joinedMethodParams})`);
this.goLines.push(` if err != nil {`);
this.goLines.push(` return err`);
this.goLines.push(` }`);
this.goLines.push(` return echoCtx.JSON(http.StatusOK, result)`);
this.goLines.push(`}`);
}
handleMemberGetFromQuery(member, methodCallParams) {
let goVar = `${changeCase.camelCase(member.key)}`;
let goVarStr = `${goVar}Str`;
this.goLines.push(` ${goVarStr} := strings.TrimSpace(echoCtx.Param("${member.key}"))`);
let goType = helpers.goFieldTypeFromJsType(member.valueType);
switch (goType) {
case "string":
this.goLines.push(`if ${goVarStr} == "" {`);
this.goLines.push(` return fmt.Errorf("Query param '${member.key}' is required")`);
this.goLines.push(`}`);
this.goLines.push(``);
methodCallParams.push(goVarStr);
break;
case "int64":
if (this.goImports.indexOf('strconv') === -1) {
this.goImports.push('strconv');
}
this.goLines.push(`${goVar}, err := strconv.ParseInt(${goVarStr}, 10, 64)`);
this.goLines.push(`if err != nil {`);
this.goLines.push(` return err`);
this.goLines.push(`}`);
methodCallParams.push(goVar);
break;
default:
throw new Error(`Query param for go type '${goType}' is not yet implemented.`);
}
}
}