diff --git a/tools/goctl/api/cmd.go b/tools/goctl/api/cmd.go index 7a190873..f5031b57 100644 --- a/tools/goctl/api/cmd.go +++ b/tools/goctl/api/cmd.go @@ -2,6 +2,7 @@ package api import ( "github.com/spf13/cobra" + "github.com/zeromicro/go-zero/tools/goctl/api/apigen" "github.com/zeromicro/go-zero/tools/goctl/api/dartgen" "github.com/zeromicro/go-zero/tools/goctl/api/docgen" @@ -157,7 +158,6 @@ func init() { tsCmd.Flags().StringVar(&tsgen.VarStringDir, "dir", "", "The target dir") tsCmd.Flags().StringVar(&tsgen.VarStringAPI, "api", "", "The api file") - tsCmd.Flags().StringVar(&tsgen.VarStringWebAPI, "webapi", "", "The web api file path") tsCmd.Flags().StringVar(&tsgen.VarStringCaller, "caller", "", "The web api caller") tsCmd.Flags().BoolVar(&tsgen.VarBoolUnWrap, "unwrap", false, "Unwrap the webapi caller for import") diff --git a/tools/goctl/api/tsgen/gen.go b/tools/goctl/api/tsgen/gen.go index c8c0a9d5..90640966 100644 --- a/tools/goctl/api/tsgen/gen.go +++ b/tools/goctl/api/tsgen/gen.go @@ -7,6 +7,7 @@ import ( "github.com/logrusorgru/aurora" "github.com/spf13/cobra" "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/tools/goctl/api/parser" "github.com/zeromicro/go-zero/tools/goctl/util/pathx" ) @@ -39,6 +40,10 @@ func TsCommand(_ *cobra.Command, _ []string) error { return errors.New("missing -dir") } + if len(webAPI) == 0 { + webAPI = "." + } + api, err := parser.Parse(apiFile) if err != nil { fmt.Println(aurora.Red("Failed")) @@ -51,6 +56,7 @@ func TsCommand(_ *cobra.Command, _ []string) error { api.Service = api.Service.JoinPrefix() logx.Must(pathx.MkdirIfNotExist(dir)) + logx.Must(genRequest(dir)) logx.Must(genHandler(dir, webAPI, caller, api, unwrapAPI)) logx.Must(genComponents(dir, api)) diff --git a/tools/goctl/api/tsgen/genpacket.go b/tools/goctl/api/tsgen/genpacket.go index 73ec4d79..6635220a 100644 --- a/tools/goctl/api/tsgen/genpacket.go +++ b/tools/goctl/api/tsgen/genpacket.go @@ -39,7 +39,7 @@ func genHandler(dir, webAPI, caller string, api *spec.ApiSpec, unwrapAPI bool) e importCaller = "{ " + importCaller + " }" } if len(webAPI) > 0 { - imports += `import ` + importCaller + ` from ` + "\"" + webAPI + "\"" + imports += `import ` + importCaller + ` from ` + `"./gocliRequest"` } if len(api.Types) != 0 { diff --git a/tools/goctl/api/tsgen/genrequest.go b/tools/goctl/api/tsgen/genrequest.go new file mode 100644 index 00000000..62706e1c --- /dev/null +++ b/tools/goctl/api/tsgen/genrequest.go @@ -0,0 +1,25 @@ +package tsgen + +import ( + _ "embed" + "os" + "path/filepath" + + "github.com/zeromicro/go-zero/tools/goctl/util/pathx" +) + +//go:embed request.ts +var requestTemplate string + +func genRequest(dir string) error { + abs, err := filepath.Abs(dir) + if err != nil { + return err + } + + filename := filepath.Join(abs, "gocliRequest.ts") + if pathx.FileExists(filename) { + return nil + } + return os.WriteFile(filename, []byte(requestTemplate), 0644) +} diff --git a/tools/goctl/api/tsgen/request.ts b/tools/goctl/api/tsgen/request.ts new file mode 100644 index 00000000..77d7124c --- /dev/null +++ b/tools/goctl/api/tsgen/request.ts @@ -0,0 +1,126 @@ +export type Method = + | 'get' + | 'GET' + | 'delete' + | 'DELETE' + | 'head' + | 'HEAD' + | 'options' + | 'OPTIONS' + | 'post' + | 'POST' + | 'put' + | 'PUT' + | 'patch' + | 'PATCH'; + +/** + * Parse route parameters for responseType + * + */ +const reg = /:[a-z|A-Z]+/g; + +export function parseParams(url: string): Array { + const ps = url.match(reg); + if (!ps) { + return []; + } + return ps.map((k) => k.replace(/:/, '')); +} + +/** + * Generate url and parameters + * @param url + * @param params + */ +export function genUrl(url: string, params: unknown) { + if (!params) { + return url; + } + + const ps = parseParams(url); + ps.forEach((k) => { + const reg = new RegExp(`:${k}`); + url = url.replace(reg, params[k]); + }); + + const path: Array = []; + for (const key of Object.keys(params)) { + if (!ps.find((k) => k === key)) { + path.push(`${key}=${params[key]}`); + } + } + + return url + (path.length > 0 ? `?${path.join('&')}` : ''); +} + +export async function request({ + method, + url, + data, + config = {} +}: { + method: Method; + url: string; + data?: unknown; + config?: unknown; +}) { + const response = await fetch(url, { + method: method.toLocaleUpperCase(), + credentials: 'include', + headers: { + 'Content-Type': 'application/json' + }, + body: data ? JSON.stringify(data) : undefined, + // @ts-ignore + ...config + }); + return response.json(); +} + +function api( + method: Method = 'get', + url: string, + req: any, + config?: unknown +): Promise { + if (url.match(/:/) || method.match(/get|delete/i)) { + url = genUrl(url, req.params || req.forms); + } + method = method.toLocaleLowerCase() as Method; + + switch (method) { + case 'get': + return request({method: 'get', url, data: req, config}); + case 'delete': + return request({method: 'delete', url, data: req, config}); + case 'put': + return request({method: 'put', url, data: req, config}); + case 'post': + return request({method: 'post', url, data: req, config}); + case 'patch': + return request({method: 'patch', url, data: req, config}); + default: + return request({method: 'post', url, data: req, config}); + } +} + +export const webapi = { + get(url: string, req: unknown, config?: unknown): Promise { + return api('get', url, req, config); + }, + delete(url: string, req: unknown, config?: unknown): Promise { + return api('delete', url, req, config); + }, + put(url: string, req: unknown, config?: unknown): Promise { + return api('get', url, req, config); + }, + post(url: string, req: unknown, config?: unknown): Promise { + return api('post', url, req, config); + }, + patch(url: string, req: unknown, config?: unknown): Promise { + return api('patch', url, req, config); + } +}; + +export default webapi \ No newline at end of file