Giter Site home page Giter Site logo

marwan-at-work / protoc-gen-twirpql Goto Github PK

View Code? Open in Web Editor NEW
51.0 4.0 6.0 1.75 MB

Generate A GraphQL Layer from A Twirp Server: https://twirpql.dev

License: Apache License 2.0

Go 100.00%
golang graphql graphql-server graphql-client graphiql twirp

protoc-gen-twirpql's Introduction

A Protoc plugin that generates a GraphQL layer on top of Twirp servers.

Status

There have been a few breaking changes in the upstream dependencies (protobufs and gqlgen) which makes this plugin a bit outdated if not flat out broken. So the go.mod file to pin the versions that would work with this library or feel free to open a PR upgrading to the latest of the two versions. See #9

Features

  • Generates a full GraphQL server implementation based on gqlgen

  • Marshals/Unmarshals ProtoBuf enums (ints) to GraphQL enums (strings).

  • Generates GraphQL Scalars for Protobuf map types that can be used as encoded json strings.

  • Exposes a GraphQL handler as well as a Graph(i)QL interface to make Twirp servers interactive.

  • Unit tests and end to end tests.

  • Twirp Server Hooks -> GraphQL Middleware

Why

RPC Frameworks such as Twirp have two big benefits:

  1. Automatic client generation
  2. Documentation-first APIs ensure your contract is not out of date.

This makes it really easy for multiple teams to start using your program right away. But before they use it, they need to learn how it works. This is where GraphQL does a better job.

Twirp and many other frameworks do not provide a friendly UI to discover and interact with their services. GraphQL comes with a very friendly UI that makes discovering an API quick, easy and fun. You get expressiveness and auto-completion out of the box.

By combining both technologies, my hope is that you get the best of both worlds.

Install

GO111MODULE=on go install marwan.io/protoc-gen-twirpql

Usage

For a full tutorial, click here.

protoc --go_out=. --twirp_out=. service.proto
protoc --twirpql_out=. service.proto

This will generate a subpackage that you can import and use as such:

package main

import (
    "net/http"

    "./twirpql"
    "./mytwirpserver"
)

func main() {
    s := mytwirpserver.New()
    http.Handle("/query", twirpql.Handler(s, nil))
    http.Handle("/play", twirpql.Playground("my service", "/query"))
}

Server Hooks

TwirpQL supports mapping the Error callback of twirp.ServerHooks to a GraphQL middleware.

All you have to do is the following:

    hooks := &twirpql.Handler{Error: myErrorHook}
    http.Handle("/query", twirpql.Handler(s, hooks))

And TwirpQL will call your hook if the underlying service implementation returned an error.

Workflow

TwirpQL expects the service.proto to have already been used to generate a .pb.go, and .twirp.go files in the same directory as the .proto file.

The plugin will generate a twirpql sub-package that contains the GraphQL layer with all types mapped to the original .pb.go file generated by your .proto file.

Multiple Services

Currently you can only specify one target file such as service.proto. In other words, the following is not allowed:

protoc --twirpql_out=. service.proto otherservice.proto

That said, service.proto can import multiple protofiles so breaking out your proto files should not be problem.

However, each TwirpQL generation is meant for one service declaration in a protocol buffer file. If a Protobuf file has one service declaration, that will be the one chosen. If the Protobuf file has multiple service declarations, then you must explicitly specify which service you'd like to generate a GraphQL layer for as such:

protoc --twirpql_out=service=SomeService:. service.proto

If you want to generate a GraphQL layer over multiple services, see here

protoc-gen-twirpql's People

Contributors

marwan-at-work avatar willabides avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

stanxii tmc metatexx

protoc-gen-twirpql's Issues

Doesn't seem to support float types from Protobuf

When generating the client from the protobuf file where a variable has type float, the client throws an error stating that the field in question doesn't exist. Also when reviewing the output of the generated files, I'm seeing that the client is generating an entire new resolver based on the object the float is associated with.

// filename: api.proto

service API {
   rpc GetSomething(GetSomethingRequest) returns (GetSomethingResponse);
}

message GetSomethingRequest {
  int64 id = 1;
}

message GetSomethingResponse {
    int64 id = 1;
    string name = 2;
    repeated Something;
}

message Something {
  int64 id = 1;
  float density = 2;   // type float associated to "Something" object
}
// Error message received when generating from this
panic: validation failed: packages.Load: /app/twirpql/resolver.go:132:15: r.API.Density undefined (type mySomething.API has no field or method Density)
/app/twirpql/resolver.go:132:28: undeclared name: req
// filename: resolver.go
// New resolver added here (this is similar in `generated.go`)

...

func (r *Resolver) Something() SomethingResolver {
	return &somethingResolver{r}
}

...

type somethingResolver struct{ *Resolver }

func (r *somethingResolver) Density(ctx context.Context, obj *api.Something) (float64, error) {
	return r.API.Density(ctx, req)
}

...

support deprecation

Do you plan to support field metadata such as isDeprecated/deprecationReason?

Generates invalid graphql for self-referential messages.

message SelfRef {
  SelfRef self_ref = 1;
}

generates

input SelfRef {
	self_ref: SelfRef!
}

which graphql-schema-linter flags as: Cannot reference Input Object "SelfRef" within itself through a series of non-null fields: "self_ref". invalid-graphql-schema

How to support optional response keys

Basically what the title states, but here's a bit more context and an example:

I have a response object that has some optional keys depending if data for the parent item exists. However, it seems that these fields can never be null as protoc-gen-twirpql is generating a graphQL schema file with these optional fields marked with a !.

Detailed context: I have an array of objects I'm pulling from one db table and then OUTER JOINING those objects to another table and it's very likely that some of the fields will be null. If they are null, I would like to not append keys to the parent object. See the example response body, I'm looking for.

# desired response body
data: {
  screens: [
    {
      id: 1,
      name: "Screen One"
    },
    {
      id: 2,
      name: "Screen Two",
      position: {
        x: 112,
        y: 53
      }
    }
  ]
}

In the desired response, you can see that screen 1 doesn't have corresponding coordinate data, so position is not there, while screen 2 does have coordinate data. But because the generated schema file is putting a ! on the position field, GraphQL is throwing a must not be null error.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.