Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/marwan-at-work/protoc-gen-twirpql

Generate A GraphQL Layer from A Twirp Server: https://twirpql.dev
https://github.com/marwan-at-work/protoc-gen-twirpql

golang graphiql graphql graphql-client graphql-server twirp

Last synced: about 1 month ago
JSON representation

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

Awesome Lists containing this project

README

        

#

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 https://github.com/marwan-at-work/protoc-gen-twirpql/issues/9

## Features

- [x] Generates a full GraphQL server implementation based on [gqlgen](https://github.com/99designs/gqlgen)

- [x] Marshals/Unmarshals ProtoBuf enums (ints) to GraphQL enums (strings).

- [x] Generates GraphQL Scalars for Protobuf map types that can be used as encoded json strings.

- [x] Exposes a GraphQL handler as well as a Graph(i)QL interface to make Twirp servers interactive.

- [x] Unit tests and end to end tests.

- [x] 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

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

## Usage

### For a full tutorial, [click here](https://twirpql.dev/docs/install).

```bash
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:

```golang
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:

```golang
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:

```bash
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:

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

If you want to generate a GraphQL layer over multiple services, see [here](https://twirpql.dev/docs/multiple-services)