More Related Content Similar to Graph ql api gateway Similar to Graph ql api gateway (20) Graph ql api gateway4. {
user(id: «1») {
name
}
dog(name: «A»){
nick
}
}
{
«user»: {
«name»: «UserName»
},
«dog»: {
«nick»: «Bobby»
}
}
Type: User
Type: Pet
Type: String
Type: String
Type: Query
5. GraphQL → GRPC Proxy writing process
GRPC Message
GraphQL
Output Object
GraphQL
Input Object
GRPC Service
GraphQL
Fields Array
GRPC Enum
GraphQL
Enum
Input Object
unmarshaler+
GRPC
Method
Method
Resolver
6. Message in .proto file VS Message in GraphQL Schema
message A {
int32 someField = 1;
int64 someAnotherField = 2;
string andAnotherOne = 3;
}
var GQLA = graphql.NewObject(graphql.ObjectConfig{
Name: "A",
Fields: graphql.Fields{
"someField": &graphql.Field{
Name: "someField",
Type: graphql.Int,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
switch src := p.Source.(type) {
case A:
return src.SomeField, nil
case *A:
return src.SomeField, nil
}
return nil, nil
},
},
"someAnotherField": &graphql.Field{
Name: "someAnotherField",
Type: graphql.Int,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
switch src := p.Source.(type) {
case A:
return src.SomeAnotherField, nil
case *A:
return src.SomeAnotherField, nil
}
return nil, nil
},
},
"andAnotherOne": &graphql.Field{
Name: "andAnotherOne",
Type: graphql.String,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
switch src := p.Source.(type) {
case A:
return src.AndAnotherOne, nil
case *A:
return src.AndAnotherOne, nil
}
return nil, nil
},
},
},
})
😞
10. p.P(`»`, field.GetName(), `": &`, graphQLPkg.Use(), `.Field{`)
p.In()
p.P(`Type: `, p.graphQLType(message, field, graphQLPkg, schemaPkg), `,`)
p.P(`Description: `, fieldGQL, `,`)
p.P(`Resolve: func(p `, graphQLPkg.Use(), `.ResolveParams) (interface{}, error) {`)
p.In()
p.P(`return nil, nil`)
p.Out()
p.P(`}}`)
p.Out()
fmt.Println() generated code
12. GoGo plugin problems
• Only two files in output
• Generator knows about only one .proto file and can’t
make composition
• Hard to debug
• Option-based configuration
13. .proto files parser
generate.yaml
vendor_path: «./vendor»
paths:
- «$GOPATH/src»
- «./vendor»
proto_files:
- path : «./a.proto»
- …
- path: «./b.proto»
schema:
Query:
- field: «a»
type: «SERVICE»
- field: «b»
type: «SERVICE»
Parser
Query {
a : AService,
b: BService,
}
AService {
meth1(req:Req) : MethResp,
meth2(req:Req) : SomeRes,
}
BService {
meth1(req:Req) : MethResp,
}
a.proto b.proto
Template
schema.go
./services/a.go
./services/b.go
proto2gql
17. Custom .proto files parser
generate.yaml
vendor_path: «./vendor»
paths:
- «$GOPATH/src»
- «./vendor»
proto_files:
- path : «./a.proto»
- …
- path: «./b.proto»
schema:
Query:
- field: «a»
type: «SERVICE»
- field: «b»
type: «SERVICE»
Query {
a : AService,
b: BService,
}
AService {
meth1(req:Req) : MethResp,
meth2(req:Req) : SomeRes,
}
BService {
meth1(req:Req) : MethResp,
}
Parser
a.proto b.proto
Template
schema.go
./services/a.go
./services/b.go
18. Normalizing data
generate.yaml
vendor_path: «./vendor»
paths:
- «$GOPATH/src»
- «./vendor»
proto_files:
- path : «./a.proto»
- …
- path: «./b.proto»
schema:
Query:
- field: «a»
type: «SERVICE»
- field: «b»
type: «SERVICE»
Query {
a : AService,
b: BService,
}
AService {
meth1(req:Req) : MethResp,
meth2(req:Req) : SomeRes,
}
BService {
meth1(req:Req) : MethResp,
}
.proto
parser
a.proto
b.proto
Template
schema.go
./services/a.go
./services/b.go
swagger
Parser
data
normalizer
data
normalizer
swagger1.yml
swagger2.yml
21. Conclusions
• Use templates in code generation
• Prepare data for templates in case of a possibility
of some other data-source
• Choose toolchain that will not frame you