oapi-codegen icon indicating copy to clipboard operation
oapi-codegen copied to clipboard

Feature/graphql

Open ticruz38 opened this issue 5 years ago • 4 comments

We at my company rely heavily on oapi-codegen to generate our rest services from openapi yaml files. Our frontend team is used to graphql to communicate with our services, so we put together an option that let us generate the same set of endpoints as graphql endpoints. This pull request put together the basics to translate REST to graphql.

We generate the .gql files, the server, the GraphQL Scalars (Date and DateTime) and the resolvers. No additional code is needed to enable the graphql server except those few lines in main.go

// plug in the graphql endpoint
schema, err := graph.New("YOUR_REST_URL")
if err != nil {
	panic(err)
}
srv := handler.GraphQL(graph.NewExecutableSchema(*schema))
e.Any("/playground", echo.WrapHandler(handler.Playground("YOUR_GRAPH_NAME", "/graphql")))
e.Any("/graphql", echo.WrapHandler(srv))

Currently missing features are:

  • the Enum types
  • File uploads
  • Unions types

We use https://github.com/99designs/gqlgen to build the graphql servers

The graphql generator needs oapi-codegen types and client code to be present. So an example of how to use this feature currently would be:

//go:generate oapi-cg -generate types -package api -o api/types.gen.go openapi/openapi.yml
//go:generate oapi-cg -generate client -package api -o api/client.gen.go openapi/openapi.yml
//go:generate oapi-cg -generate graphql -package api openapi/openapi.yml

The last line is the graphql generator, -package has a different signification here, it basically tells graphql generator where to pick its existing types (client and types).

As the configuration get more tricky we may need to use a configuration file, but that's a different subject, for now I will make the cli more explicit for graphql generation in a future commit.

The graphql generation is always generated under /graph folder at the root of the repo, with the graph package name set.

ticruz38 avatar Apr 28 '20 14:04 ticruz38

Hi! This is pretty cool! We do something similar, and I was wondering if you'd done any comparison between your code's GraphQL schema (generated by your code from your openAPI spec) and the graphQL schema generated from other processes?

The GraphQL schema we use for oapi-codegen is generated using openapi-to-graphql from our OpenAPIv3 spec. Unfortunately, it does not support OpenAPIv3 YAML input, so we have to convert to JSON first if our spec is in yaml. Swagger Editor or yq does this for us.

npm init -f
npm i -D openapi-to-graphql-cli
npx openapi-to-graphql --fillEmptyResponses ./todoOA3.json --save ./todoGQL.yaml

StevenACoffman avatar May 23 '20 19:05 StevenACoffman

Hi, Well the problem with openapi-to-graphql is that you get a node GraphQL server that handle much less queries/seconds, you also get 2 different server implementation. With that solution you are sure that for each release, you are in sync between your api and your GraphQL. My GraphQL schema follow the nomenclature used by oapi-codegen, here are the difference with OTG:

  • fields starting by a number are preceded by "N" instead of "_" with OTG
  • fields start with an uppercase (although this is not ideal, I will try to change that)
  • for mutation, if the body is a reference to a type, we add the suffix "Input" to that type, this is the same as OTG. If the body is not a ref, then we create a new one with OPERATION_NAME + TYPE_OF_BODY, I'm not sure how OTG handle this, I have an example with a multipart body, OTG would send a string as argument when I send a normal GraphQL object with Multipart suffix.

Finally, my implementation is less complete, with lack of support for enum, unions, file upload, subscriptions (via callback) and nested data (using links) all of this is possible to achieve without much hassle, I just need time. I also added Federation support by default, to aggregate different schema together. I will add some examples comparing schema generated with OTG and OAPI-codegen, in examples folder You are welcome to try it and let me know if you encounter any problems

ticruz38 avatar May 25 '20 08:05 ticruz38

Yeah, after we have converted our OpenAPI spec to a GraphQL schema file, we actually use gqlgen from the GraphQL schema to generate a golang server. gqlgen is fairly mature and also supports federation. My interest is in eliminating the node.Js portion, and making the GraphQL schema more similar to the OpenAPI spec as you described. I'll definitely check it out!

StevenACoffman avatar May 25 '20 13:05 StevenACoffman

I see, well you will have to implement the resolvers yourself, and the types generated by gqlgen will be redundant with the ones from oapi-codegen. I do use gqlgen under the hoods, but I reuse the go types generated by oapi-codegen, and the resolvers are auto generated as well, this is meant to add one line to the go generate to enable both GraphQL and swagger without hand coding anything.

ticruz38 avatar May 25 '20 15:05 ticruz38