mirror of
https://github.com/foomo/gotsrpc.git
synced 2025-10-16 12:35:35 +00:00
async client flavor added
This commit is contained in:
parent
dcc105e15f
commit
a8855fa401
40
README.md
40
README.md
@ -38,6 +38,8 @@ Will generate client and server side go and TypeScript code. Have fun!
|
||||
```yaml
|
||||
---
|
||||
modulekind: commonjs
|
||||
# if you want an async api vs classic callbacks - here you are
|
||||
tsclientflavor: async
|
||||
targets:
|
||||
demo:
|
||||
services:
|
||||
@ -59,6 +61,44 @@ mappings:
|
||||
out: /tmp/test-files-demo-nested.ts
|
||||
...
|
||||
```
|
||||
#### an async example
|
||||
|
||||
How to use async clients in this case with axios:
|
||||
|
||||
```TypeScript
|
||||
import axios, { AxiosPromise } from "axios";
|
||||
import { ServiceClient as ExampleClient } from "./some/generated/client";
|
||||
|
||||
// axios transport
|
||||
let getTransport = endpoint => async <T>(method, args = []) => {
|
||||
return new Promise<T>(async (resolve, reject) => {
|
||||
try {
|
||||
let axiosPromise: any = await axios.post<T>(
|
||||
endpoint + encodeURIComponent(method),
|
||||
JSON.stringify(args),
|
||||
);
|
||||
return resolve(axiosPromise.data);
|
||||
} catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let client = new ExampleClient(getTransport(ExampleClient.defaultEndpoint));
|
||||
|
||||
export async function test() {
|
||||
try {
|
||||
let result = await client.getResult();
|
||||
console.log("here is the result", result);
|
||||
} catch (e) {
|
||||
// e => network?
|
||||
// e => json
|
||||
// e => domain error type
|
||||
console.error("something went wrong ...", e);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### oldschool TypeScript
|
||||
|
||||
|
||||
5
build.go
5
build.go
@ -110,7 +110,7 @@ func Build(conf *config.Config, goPath string) {
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
ts, err := RenderTypeScriptServices(conf.ModuleKind, services, conf.Mappings, scalarTypes, target)
|
||||
ts, err := RenderTypeScriptServices(conf.ModuleKind, conf.TSClientFlavor, services, conf.Mappings, scalarTypes, target)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, " could not generate ts code", err)
|
||||
os.Exit(3)
|
||||
@ -128,7 +128,8 @@ func Build(conf *config.Config, goPath string) {
|
||||
fmt.Fprintln(os.Stderr, " could not write service file", target.Out, updateErr)
|
||||
os.Exit(3)
|
||||
}
|
||||
err = RenderStructsToPackages(structs, conf.Mappings, constants, scalarTypes, mappedTypeScript)
|
||||
|
||||
err = renderTypescriptStructsToPackages(conf.ModuleKind, structs, conf.Mappings, constants, scalarTypes, mappedTypeScript)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "struct gen err for target", name, err)
|
||||
os.Exit(4)
|
||||
|
||||
@ -27,11 +27,10 @@ var GoTSRPC;
|
||||
};
|
||||
};
|
||||
})(GoTSRPC || (GoTSRPC = {})); // close
|
||||
var GoTSRPC;
|
||||
(function (GoTSRPC) {
|
||||
var Demo;
|
||||
(function (Demo) {
|
||||
var FooClient = (function () {
|
||||
var FooClient = /** @class */ (function () {
|
||||
function FooClient(endPoint, transport) {
|
||||
if (endPoint === void 0) { endPoint = "/service/foo"; }
|
||||
if (transport === void 0) { transport = GoTSRPC.call; }
|
||||
@ -45,7 +44,7 @@ var GoTSRPC;
|
||||
return FooClient;
|
||||
}());
|
||||
Demo.FooClient = FooClient;
|
||||
var DemoClient = (function () {
|
||||
var DemoClient = /** @class */ (function () {
|
||||
function DemoClient(endPoint, transport) {
|
||||
if (endPoint === void 0) { endPoint = "/service/demo"; }
|
||||
if (transport === void 0) { transport = GoTSRPC.call; }
|
||||
@ -64,6 +63,9 @@ var GoTSRPC;
|
||||
DemoClient.prototype.helloInterface = function (anything, anythingMap, anythingSlice, success, err) {
|
||||
this.transport(this.endPoint, "HelloInterface", [anything, anythingMap, anythingSlice], success, err);
|
||||
};
|
||||
DemoClient.prototype.helloScalarError = function (success, err) {
|
||||
this.transport(this.endPoint, "HelloScalarError", [], success, err);
|
||||
};
|
||||
DemoClient.prototype.mapCrap = function (success, err) {
|
||||
this.transport(this.endPoint, "MapCrap", [], success, err);
|
||||
};
|
||||
|
||||
4
code.go
4
code.go
@ -42,5 +42,9 @@ func (c *code) app(str string) *code {
|
||||
}
|
||||
|
||||
func (c *code) string() string {
|
||||
if c.line != "" {
|
||||
c.lines = append(c.lines, c.line)
|
||||
c.line = ""
|
||||
}
|
||||
return strings.Join(c.lines, "\n")
|
||||
}
|
||||
|
||||
@ -65,16 +65,19 @@ type Mapping struct {
|
||||
type TypeScriptMappings map[string]*Mapping
|
||||
|
||||
type ModuleKind string
|
||||
type TSClientFlavor string
|
||||
|
||||
const (
|
||||
ModuleKindDefault ModuleKind = "default"
|
||||
ModuleKindCommonJS ModuleKind = "commonjs"
|
||||
ModuleKindDefault ModuleKind = "default"
|
||||
ModuleKindCommonJS ModuleKind = "commonjs"
|
||||
TSClientFlavorAsync TSClientFlavor = "async"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ModuleKind ModuleKind
|
||||
Targets map[string]*Target
|
||||
Mappings TypeScriptMappings
|
||||
ModuleKind ModuleKind
|
||||
TSClientFlavor TSClientFlavor
|
||||
Targets map[string]*Target
|
||||
Mappings TypeScriptMappings
|
||||
}
|
||||
|
||||
func LoadConfigFile(file string) (conf *Config, err error) {
|
||||
@ -93,6 +96,11 @@ func loadConfig(yamlBytes []byte) (conf *Config, err error) {
|
||||
err = errors.New("could not parse yaml: " + yamlErr.Error())
|
||||
return
|
||||
}
|
||||
switch conf.TSClientFlavor {
|
||||
case "", TSClientFlavorAsync:
|
||||
default:
|
||||
err = errors.New("unknown ts client flavor: " + conf.TSClientFlavor + " must be empty or " + TSClientFlavorAsync)
|
||||
}
|
||||
switch conf.ModuleKind {
|
||||
case ModuleKindCommonJS, ModuleKindDefault:
|
||||
case "":
|
||||
|
||||
2
model.go
2
model.go
@ -23,6 +23,7 @@ type StructType struct {
|
||||
}
|
||||
|
||||
type Value struct {
|
||||
IsError bool `json:",omitempty"`
|
||||
IsInterface bool `json:",omitempty"`
|
||||
Scalar *Scalar `json:",omitempty"`
|
||||
ScalarType ScalarType `json:",omitempty"`
|
||||
@ -88,6 +89,7 @@ type Method struct {
|
||||
}
|
||||
|
||||
type Struct struct {
|
||||
IsError bool
|
||||
Package string
|
||||
Name string
|
||||
Fields []*Field
|
||||
|
||||
@ -259,11 +259,13 @@ func Read(goPaths []string, packageName string, serviceMap map[string]string) (s
|
||||
|
||||
func fixFieldStructs(fields []*Field, structs map[string]*Struct, scalars map[string]*Scalar) {
|
||||
for _, f := range fields {
|
||||
|
||||
if f.Value.StructType != nil {
|
||||
// do we have that struct or is it a hidden scalar
|
||||
name := f.Value.StructType.FullName()
|
||||
_, strctExists := structs[name]
|
||||
s, strctExists := structs[name]
|
||||
if strctExists {
|
||||
f.Value.IsError = s.IsError
|
||||
continue
|
||||
}
|
||||
scalar, scalarExists := scalars[name]
|
||||
|
||||
@ -15,13 +15,27 @@ func readStructs(pkg *ast.Package, packageName string) (structs map[string]*Stru
|
||||
structs = map[string]*Struct{}
|
||||
trace("reading files in package", packageName)
|
||||
scalarTypes = map[string]*Scalar{}
|
||||
errorTypes := map[string]bool{}
|
||||
for _, file := range pkg.Files {
|
||||
err = extractTypes(file, packageName, structs, scalarTypes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = extractErrorTypes(file, packageName, errorTypes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// jsonDump(scalarTypes)
|
||||
for name, structType := range structs {
|
||||
_, isErrorType := errorTypes[name]
|
||||
if isErrorType {
|
||||
structType.IsError = true
|
||||
}
|
||||
}
|
||||
//jsonDump(errorTypes)
|
||||
//jsonDump(scalarTypes)
|
||||
//jsonDump(structs)
|
||||
return
|
||||
}
|
||||
|
||||
@ -291,8 +305,36 @@ func readFieldList(fieldList []*ast.Field, fileImports fileImportSpecMap) (field
|
||||
return
|
||||
}
|
||||
|
||||
func extractErrorTypes(file *ast.File, packageName string, errorTypes map[string]bool) (err error) {
|
||||
for _, d := range file.Decls {
|
||||
if reflect.ValueOf(d).Type().String() == "*ast.FuncDecl" {
|
||||
funcDecl := d.(*ast.FuncDecl)
|
||||
if funcDecl.Recv != nil && len(funcDecl.Recv.List) == 1 {
|
||||
firstReceiverField := funcDecl.Recv.List[0]
|
||||
if "*ast.StarExpr" == reflect.ValueOf(firstReceiverField.Type).Type().String() {
|
||||
starExpr := firstReceiverField.Type.(*ast.StarExpr)
|
||||
if "*ast.Ident" == reflect.ValueOf(starExpr.X).Type().String() {
|
||||
ident := starExpr.X.(*ast.Ident)
|
||||
if funcDecl.Name.Name == "Error" && funcDecl.Type.Params.NumFields() == 0 && funcDecl.Type.Results.NumFields() == 1 {
|
||||
returnValueField := funcDecl.Type.Results.List[0]
|
||||
refl := reflect.ValueOf(returnValueField.Type)
|
||||
if refl.Type().String() == "*ast.Ident" {
|
||||
returnValueIdent := returnValueField.Type.(*ast.Ident)
|
||||
if returnValueIdent.Name == "string" {
|
||||
errorTypes[packageName+"."+ident.Name] = true
|
||||
}
|
||||
//fmt.Println("error for:", ident.Name, returnValueIdent.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func extractTypes(file *ast.File, packageName string, structs map[string]*Struct, scalarTypes map[string]*Scalar) error {
|
||||
trace("reading file", file.Name.Name)
|
||||
fileImports := getFileImports(file, packageName)
|
||||
for name, obj := range file.Scope.Objects {
|
||||
if obj.Kind == ast.Typ && obj.Decl != nil {
|
||||
|
||||
121
typescript.go
121
typescript.go
@ -95,7 +95,7 @@ func renderStructFields(fields []*Field, mappings config.TypeScriptMappings, sca
|
||||
|
||||
}
|
||||
|
||||
func renderStruct(str *Struct, mappings config.TypeScriptMappings, scalarTypes map[string]*Scalar, ts *code) error {
|
||||
func renderTypescriptStruct(str *Struct, mappings config.TypeScriptMappings, scalarTypes map[string]*Scalar, ts *code) error {
|
||||
ts.l("// " + str.FullName())
|
||||
ts.l("export interface " + str.Name + " {").ind(1)
|
||||
renderStructFields(str.Fields, mappings, scalarTypes, ts)
|
||||
@ -103,92 +103,14 @@ func renderStruct(str *Struct, mappings config.TypeScriptMappings, scalarTypes m
|
||||
return nil
|
||||
}
|
||||
|
||||
func renderService(skipGoTSRPC bool, moduleKind config.ModuleKind, service *Service, mappings config.TypeScriptMappings, scalarTypes map[string]*Scalar, ts *code) error {
|
||||
clientName := service.Name + "Client"
|
||||
|
||||
ts.l("export class " + clientName + " {").ind(1)
|
||||
|
||||
if moduleKind == config.ModuleKindCommonJS {
|
||||
if skipGoTSRPC {
|
||||
ts.l("constructor(public endPoint:string = \"" + service.Endpoint + "\", public transport:(endPoint:string, method:string, args:any[], success:any, err:any) => void) { }")
|
||||
} else {
|
||||
ts.l("static defaultInst = new " + clientName + ";")
|
||||
ts.l("constructor(public endPoint:string = \"" + service.Endpoint + "\", public transport = call) { }")
|
||||
}
|
||||
|
||||
} else {
|
||||
ts.l("static defaultInst = new " + clientName + ";")
|
||||
ts.l("constructor(public endPoint:string = \"" + service.Endpoint + "\", public transport = GoTSRPC.call) { }")
|
||||
}
|
||||
|
||||
for _, method := range service.Methods {
|
||||
|
||||
ts.app(lcfirst(method.Name) + "(")
|
||||
// actual args
|
||||
//args := []string{}
|
||||
callArgs := []string{}
|
||||
|
||||
argOffset := 0
|
||||
for index, arg := range method.Args {
|
||||
if index == 0 && arg.Value.isHTTPResponseWriter() {
|
||||
trace("skipping first arg is a http.ResponseWriter")
|
||||
argOffset = 1
|
||||
continue
|
||||
}
|
||||
if index == 1 && arg.Value.isHTTPRequest() {
|
||||
trace("skipping second arg is a *http.Request")
|
||||
argOffset = 2
|
||||
continue
|
||||
}
|
||||
}
|
||||
argCount := 0
|
||||
for index, arg := range method.Args {
|
||||
if index < argOffset {
|
||||
continue
|
||||
}
|
||||
if index > argOffset {
|
||||
ts.app(", ")
|
||||
}
|
||||
ts.app(arg.tsName() + ":")
|
||||
arg.Value.tsType(mappings, scalarTypes, ts)
|
||||
callArgs = append(callArgs, arg.Name)
|
||||
argCount++
|
||||
}
|
||||
if argCount > 0 {
|
||||
ts.app(", ")
|
||||
}
|
||||
ts.app("success:(")
|
||||
// + strings.Join(retArgs, ", ") +
|
||||
|
||||
for index, retField := range method.Return {
|
||||
retArgName := retField.tsName()
|
||||
if len(retArgName) == 0 {
|
||||
retArgName = "ret"
|
||||
if index > 0 {
|
||||
retArgName += "_" + fmt.Sprint(index)
|
||||
}
|
||||
}
|
||||
if index > 0 {
|
||||
ts.app(", ")
|
||||
}
|
||||
ts.app(retArgName + ":")
|
||||
retField.Value.tsType(mappings, scalarTypes, ts)
|
||||
}
|
||||
|
||||
ts.app(") => void")
|
||||
ts.app(", err:(request:XMLHttpRequest, e?:Error) => void) {").nl()
|
||||
ts.ind(1)
|
||||
// generic framework call
|
||||
ts.l("this.transport(this.endPoint, \"" + method.Name + "\", [" + strings.Join(callArgs, ", ") + "], success, err);")
|
||||
ts.ind(-1)
|
||||
ts.app("}")
|
||||
ts.nl()
|
||||
}
|
||||
ts.ind(-1)
|
||||
ts.l("}")
|
||||
return nil
|
||||
}
|
||||
func RenderStructsToPackages(structs map[string]*Struct, mappings config.TypeScriptMappings, constants map[string]map[string]*ast.BasicLit, scalarTypes map[string]*Scalar, mappedTypeScript map[string]map[string]*code) (err error) {
|
||||
func renderTypescriptStructsToPackages(
|
||||
moduleKind config.ModuleKind,
|
||||
structs map[string]*Struct,
|
||||
mappings config.TypeScriptMappings,
|
||||
constants map[string]map[string]*ast.BasicLit,
|
||||
scalarTypes map[string]*Scalar,
|
||||
mappedTypeScript map[string]map[string]*code,
|
||||
) (err error) {
|
||||
|
||||
codeMap := map[string]map[string]*code{}
|
||||
for _, mapping := range mappings {
|
||||
@ -204,8 +126,12 @@ func RenderStructsToPackages(structs map[string]*Struct, mappings config.TypeScr
|
||||
err = errors.New("missing code mapping for go package : " + str.Package + " => you have to add a mapping from this go package to a TypeScript module in your build-config.yml in the mappings section")
|
||||
return
|
||||
}
|
||||
packageCodeMap[str.Name] = newCode(" ").ind(1)
|
||||
err = renderStruct(str, mappings, scalarTypes, packageCodeMap[str.Name])
|
||||
packageCodeMap[str.Name] = newCode(" ")
|
||||
// fmt.Println("--------------------------->", moduleKind == config.ModuleKindCommonJS)
|
||||
if !(moduleKind == config.ModuleKindCommonJS) {
|
||||
packageCodeMap[str.Name].ind(1)
|
||||
}
|
||||
err = renderTypescriptStruct(str, mappings, scalarTypes, packageCodeMap[str.Name])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -230,7 +156,11 @@ func RenderStructsToPackages(structs map[string]*Struct, mappings config.TypeScr
|
||||
if done {
|
||||
continue
|
||||
}
|
||||
constCode := newCode(" ").ind(1).l("// constants from " + packageName).l("export const GoConst = {").ind(1)
|
||||
constCode := newCode(" ")
|
||||
if moduleKind != config.ModuleKindCommonJS {
|
||||
constCode.ind(1)
|
||||
}
|
||||
constCode.l("// constants from " + packageName).l("export const GoConst = {").ind(1)
|
||||
//constCode.l()
|
||||
mappedTypeScript[packageName][goConstPseudoPackage] = constCode
|
||||
constPrefixParts := split(packageName, []string{"/", ".", "-"})
|
||||
@ -289,9 +219,9 @@ func ucFirst(str string) string {
|
||||
return constPrefix
|
||||
}
|
||||
|
||||
func RenderTypeScriptServices(moduleKind config.ModuleKind, services ServiceList, mappings config.TypeScriptMappings, scalarTypes map[string]*Scalar, target *config.Target) (typeScript string, err error) {
|
||||
func RenderTypeScriptServices(moduleKind config.ModuleKind, tsClientFlavor config.TSClientFlavor, services ServiceList, mappings config.TypeScriptMappings, scalarTypes map[string]*Scalar, target *config.Target) (typeScript string, err error) {
|
||||
ts := newCode(" ")
|
||||
if !SkipGoTSRPC {
|
||||
if !SkipGoTSRPC && tsClientFlavor == "" {
|
||||
|
||||
if moduleKind != config.ModuleKindCommonJS {
|
||||
ts.l(`module GoTSRPC {`)
|
||||
@ -337,7 +267,12 @@ func RenderTypeScriptServices(moduleKind config.ModuleKind, services ServiceList
|
||||
if !target.IsTSRPC(service.Name) {
|
||||
continue
|
||||
}
|
||||
err = renderService(SkipGoTSRPC, moduleKind, service, mappings, scalarTypes, ts)
|
||||
switch tsClientFlavor {
|
||||
case config.TSClientFlavorAsync:
|
||||
err = renderTypescriptClientAsync(service, mappings, scalarTypes, ts)
|
||||
default:
|
||||
err = renderTypescriptClient(SkipGoTSRPC, moduleKind, service, mappings, scalarTypes, ts)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -10,5 +10,4 @@ func TestSplit(t *testing.T) {
|
||||
t.Fatal("expected", expected, "got", actual)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
94
typescriptclient.go
Normal file
94
typescriptclient.go
Normal file
@ -0,0 +1,94 @@
|
||||
package gotsrpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/foomo/gotsrpc/config"
|
||||
)
|
||||
|
||||
func renderTypescriptClient(skipGoTSRPC bool, moduleKind config.ModuleKind, service *Service, mappings config.TypeScriptMappings, scalarTypes map[string]*Scalar, ts *code) error {
|
||||
clientName := service.Name + "Client"
|
||||
|
||||
ts.l("export class " + clientName + " {").ind(1)
|
||||
|
||||
if moduleKind == config.ModuleKindCommonJS {
|
||||
if skipGoTSRPC {
|
||||
ts.l("constructor(public endPoint:string = \"" + service.Endpoint + "\", public transport:(endPoint:string, method:string, args:any[], success:any, err:any) => void) { }")
|
||||
} else {
|
||||
ts.l("static defaultInst = new " + clientName + ";")
|
||||
ts.l("constructor(public endPoint:string = \"" + service.Endpoint + "\", public transport = call) { }")
|
||||
}
|
||||
|
||||
} else {
|
||||
ts.l("static defaultInst = new " + clientName + ";")
|
||||
ts.l("constructor(public endPoint:string = \"" + service.Endpoint + "\", public transport = GoTSRPC.call) { }")
|
||||
}
|
||||
|
||||
for _, method := range service.Methods {
|
||||
|
||||
ts.app(lcfirst(method.Name) + "(")
|
||||
// actual args
|
||||
//args := []string{}
|
||||
callArgs := []string{}
|
||||
|
||||
argOffset := 0
|
||||
for index, arg := range method.Args {
|
||||
if index == 0 && arg.Value.isHTTPResponseWriter() {
|
||||
trace("skipping first arg is a http.ResponseWriter")
|
||||
argOffset = 1
|
||||
continue
|
||||
}
|
||||
if index == 1 && arg.Value.isHTTPRequest() {
|
||||
trace("skipping second arg is a *http.Request")
|
||||
argOffset = 2
|
||||
continue
|
||||
}
|
||||
}
|
||||
argCount := 0
|
||||
for index, arg := range method.Args {
|
||||
if index < argOffset {
|
||||
continue
|
||||
}
|
||||
if index > argOffset {
|
||||
ts.app(", ")
|
||||
}
|
||||
ts.app(arg.tsName() + ":")
|
||||
arg.Value.tsType(mappings, scalarTypes, ts)
|
||||
callArgs = append(callArgs, arg.Name)
|
||||
argCount++
|
||||
}
|
||||
if argCount > 0 {
|
||||
ts.app(", ")
|
||||
}
|
||||
ts.app("success:(")
|
||||
// + strings.Join(retArgs, ", ") +
|
||||
|
||||
for index, retField := range method.Return {
|
||||
retArgName := retField.tsName()
|
||||
if len(retArgName) == 0 {
|
||||
retArgName = "ret"
|
||||
if index > 0 {
|
||||
retArgName += "_" + fmt.Sprint(index)
|
||||
}
|
||||
}
|
||||
if index > 0 {
|
||||
ts.app(", ")
|
||||
}
|
||||
ts.app(retArgName + ":")
|
||||
retField.Value.tsType(mappings, scalarTypes, ts)
|
||||
}
|
||||
|
||||
ts.app(") => void")
|
||||
ts.app(", err:(request:XMLHttpRequest, e?:Error) => void) {").nl()
|
||||
ts.ind(1)
|
||||
// generic framework call
|
||||
ts.l("this.transport(this.endPoint, \"" + method.Name + "\", [" + strings.Join(callArgs, ", ") + "], success, err);")
|
||||
ts.ind(-1)
|
||||
ts.app("}")
|
||||
ts.nl()
|
||||
}
|
||||
ts.ind(-1)
|
||||
ts.l("}")
|
||||
return nil
|
||||
}
|
||||
159
typscriptclientasync.go
Normal file
159
typscriptclientasync.go
Normal file
@ -0,0 +1,159 @@
|
||||
package gotsrpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/foomo/gotsrpc/config"
|
||||
)
|
||||
|
||||
func renderTypescriptClientAsync(service *Service, mappings config.TypeScriptMappings, scalarTypes map[string]*Scalar, ts *code) error {
|
||||
clientName := service.Name + "Client"
|
||||
|
||||
ts.l("export class " + clientName + " {")
|
||||
|
||||
ts.ind(1)
|
||||
//ts.l(`static defaultInst = new ` + clientName + `()`)
|
||||
//ts.l(`constructor(public endpoint = "` + service.Endpoint + `") {}`)
|
||||
ts.l(`public static defaultEndpoint = "` + service.Endpoint + `";`)
|
||||
ts.l("constructor(")
|
||||
ts.ind(1)
|
||||
ts.l("public transport:<T>(method: string, data?: any[]) => Promise<T>")
|
||||
ts.ind(-1)
|
||||
ts.l(") {}")
|
||||
|
||||
for _, method := range service.Methods {
|
||||
ts.app("async " + lcfirst(method.Name) + "(")
|
||||
callArgs := []string{}
|
||||
argOffset := 0
|
||||
for index, arg := range method.Args {
|
||||
if index == 0 && arg.Value.isHTTPResponseWriter() {
|
||||
trace("skipping first arg is a http.ResponseWriter")
|
||||
argOffset = 1
|
||||
continue
|
||||
}
|
||||
if index == 1 && arg.Value.isHTTPRequest() {
|
||||
trace("skipping second arg is a *http.Request")
|
||||
argOffset = 2
|
||||
continue
|
||||
}
|
||||
}
|
||||
argCount := 0
|
||||
for index, arg := range method.Args {
|
||||
if index < argOffset {
|
||||
continue
|
||||
}
|
||||
if index > argOffset {
|
||||
ts.app(", ")
|
||||
}
|
||||
ts.app(arg.tsName() + ":")
|
||||
arg.Value.tsType(mappings, scalarTypes, ts)
|
||||
callArgs = append(callArgs, arg.Name)
|
||||
argCount++
|
||||
}
|
||||
ts.app("):")
|
||||
|
||||
throwLastError := false
|
||||
//lastErrorName := ""
|
||||
|
||||
returnTypeTS := newCode(" ")
|
||||
returnTypeTS.app("{")
|
||||
innerReturnTypeTS := newCode(" ")
|
||||
innerReturnTypeTS.app("{")
|
||||
firstReturnType := ""
|
||||
//firstReturnFieldName := ""
|
||||
countReturns := 0
|
||||
countInnerReturns := 0
|
||||
errIndex := 0
|
||||
responseObjectPrefix := ""
|
||||
responseObject := "let responseObject = {"
|
||||
|
||||
for index, retField := range method.Return {
|
||||
countInnerReturns++
|
||||
retArgName := retField.tsName()
|
||||
|
||||
if len(retArgName) == 0 {
|
||||
retArgName = "ret"
|
||||
if index > 0 {
|
||||
retArgName += "_" + fmt.Sprint(index)
|
||||
}
|
||||
}
|
||||
if index > 0 {
|
||||
returnTypeTS.app("; ")
|
||||
innerReturnTypeTS.app("; ")
|
||||
}
|
||||
|
||||
innerReturnTypeTS.app(strconv.Itoa(index) + ":")
|
||||
retField.Value.tsType(mappings, scalarTypes, innerReturnTypeTS)
|
||||
|
||||
if index == len(method.Return)-1 && retField.Value.IsError {
|
||||
throwLastError = true
|
||||
//lastErrorName = retArgName
|
||||
errIndex = index
|
||||
} else {
|
||||
if index == 0 {
|
||||
firstReturnTypeTS := newCode(" ")
|
||||
retField.Value.tsType(mappings, scalarTypes, firstReturnTypeTS)
|
||||
firstReturnType = firstReturnTypeTS.string()
|
||||
//firstReturnFieldName = retArgName
|
||||
}
|
||||
countReturns++
|
||||
returnTypeTS.app(retArgName + ":")
|
||||
responseObject += responseObjectPrefix + retArgName + " : response[" + strconv.Itoa(index) + "]"
|
||||
retField.Value.tsType(mappings, scalarTypes, returnTypeTS)
|
||||
}
|
||||
responseObjectPrefix = ", "
|
||||
}
|
||||
responseObject += "};"
|
||||
returnTypeTS.app("}")
|
||||
innerReturnTypeTS.app("}")
|
||||
if countReturns == 0 {
|
||||
ts.app("Promise<void> {")
|
||||
} else if countReturns == 1 {
|
||||
ts.app("Promise<" + firstReturnType + "> {")
|
||||
} else if countReturns > 1 {
|
||||
ts.app("Promise<" + returnTypeTS.string() + "> {")
|
||||
}
|
||||
ts.nl()
|
||||
|
||||
ts.ind(1)
|
||||
|
||||
innerCallTypeString := "void"
|
||||
if countInnerReturns > 0 {
|
||||
innerCallTypeString = innerReturnTypeTS.string()
|
||||
}
|
||||
|
||||
call := "this.transport<" + innerCallTypeString + ">(\"" + method.Name + "\", [" + strings.Join(callArgs, ", ") + "])"
|
||||
if throwLastError {
|
||||
ts.l("let response = await " + call)
|
||||
|
||||
ts.l("let err = response[" + strconv.Itoa(errIndex) + "];")
|
||||
//ts.l("delete response." + lastErrorName + ";")
|
||||
ts.l("if(err) { throw err }")
|
||||
if countReturns == 1 {
|
||||
ts.l("return response[0]")
|
||||
} else if countReturns == 0 {
|
||||
//ts.l("return response;")
|
||||
} else {
|
||||
ts.l(responseObject)
|
||||
ts.l("return responseObject;")
|
||||
}
|
||||
} else {
|
||||
if countReturns == 1 {
|
||||
ts.l("return (await " + call + ")[0]")
|
||||
} else {
|
||||
ts.l("let response = await " + call)
|
||||
ts.l(responseObject)
|
||||
ts.l("return responseObject;")
|
||||
}
|
||||
}
|
||||
|
||||
ts.ind(-1)
|
||||
ts.app("}")
|
||||
ts.nl()
|
||||
}
|
||||
ts.ind(-1)
|
||||
ts.l("}")
|
||||
return nil
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user