Hacker News new | comments | show | ask | jobs | submit login
Show HN: Generating GraphQL servers for Go (github.com)
172 points by vektah 4 months ago | hide | past | web | favorite | 29 comments

I feel that, in typed languages, the only GraphQL oriented code you should be writing is the schemas and the resolvers. Manually implementing the models in your language's type system seems unnecessary and is a recipe for mistakes and drift between the schemas and those types.

At Samsara our golang graphql implementation (https://github.com/samsarahq/thunder) works this way. We write out resolver functions using plain old go types and use some reflection magic at startup to compute the graphql type information.

Our docs are a bit spare at the moment, but this means with code like:

  type User struct {
    Id int64
    Name string

  func rootUser(ctx context.Context, args struct { id int64 }) (*User, error) {
    // ...

  schemaRoot.FieldFunc("user", rootUser);
We can derive the graphql SDL types automatically (looking at the arguments and return values) and use them with other graphql tooling, but it saves folks time from writing out a separate schema and keeping it in sync.

I think I would rather write types and derive schemas. Not sure if it were possible to derive resolvers?

There's a good argument that GraphQL can become the single SDL you use to define the API of many services written in many different languages. In this sense, it makes sense to write GraphQL and generate the language constructs; kind of an "outside->in" approach. If you're codegening your API from language constructs, the API will inevitably begin to use patterns that make sense in your language, not patterns that are universal to GraphQL or your entire system.

That being said, I don't agree with it. I'm not a fan of GraphQL for inter-service communication; it makes sense at the internet API boundary, but once you're inside your service mesh I prefer something simpler and easier to test, like gRPC.

How would you represent more complex types? It would work fine if your models are flat and containing only POD, but if it contains something like GeoJSON (from Postgres for example), it would be pretty difficult to ensure that the serialization works properly.

I'd imagine any decent library would provide an escape hatch around the codegen, so you can specify your own types if you'd like.

The other option is to only write the Go types, then use codegen to generate the GraphQL schemas. In a way, I prefer this because it keeps everything in the same language, using all of the great tooling Go has.

There is some prior art for this; the Juniper [1] Rust library.

[1] https://github.com/graphql-rust/juniper

It's worth keeping in mind that GraphQL often finds itself in organisations that use multiple languages. A trend we have seen starting to emerge over the last 6 months is that backend teams write core business logic in languages like Java or Python and want to expose this as GraphQL microservices.

Then you either have a central team responsible for the public GraphQL API. They will typically write a server in Javascript that composes all the microservices. Or alternatively you have multiple product teams that all want separate GraphQL APIs tailored to their use case. They too typically use Javascript for the server.

When multiple languages are involved it turns out to be really useful to be able to use GraphQL SDL as the canonical representation and use code-gen on each stack. This is the use case GraphQL binding is intended for: https://github.com/graphql-binding/graphql-binding

I explored going type first before writing this and you could get pretty close.

The details get hard though, how do you represent unions vs enums? even knowing what implements an interface? default arguments? directives?

graphql is just one representation of your applications data, it shouldn't dictate your models.

I'm thinking about adding something that generates a model if it doesn't exist, but after its generated it becomes the users problem to keep it in sync.

> recipe for mistakes and drift between the schemas and those types.

The type system enforces there is no drift, it won't compile if its not perfect.

Not to derail the discussion, but I just got started using GraphQL myself. I've been using Apollo and just started looking at Graphcool. I was wondering if anyone knows of an offline first solution for GraphQL on mobile (ios and android, native or nativescript compatible)?

I was hoping to use Apollo on all platforms but it seems I would need to use a custom solution for mobile while on web there's some choices (for offline first): https://github.com/apollographql/apollo-cache-asyncstorage/i...

Currently I'm planning to go with couchdb/couchbase-lite for mobile but I would prefer a graphql solution. I'm also investigating AWS AppSync which appears to have offline support, but I haven't read that deeply into it yet: https://aws.amazon.com/appsync/

Hi faizshah. I created RxDB ( https://github.com/pubkey/rxdb ), an offline-first-database (javascript) which works for your requirements, but only with the couchdb-stack.

I did many attempts to create a graphQL-plugin which streams graphql-data into an the offline-first store. But this is not completely solvable because of the lacking graphQL-streaming-capabilities. The thing is, when the users goes offline for an hour an then online again, there is no way to get the changes of the last hour out of graphQL which means the user then would either have missing updates or has to redownload the full state again. The current streaming-api of graphQL requires a stable connection and is so not useable for offline-first.

Thanks for the info and the reply, this seems like a great solution for me for nativescript and I like the docs and feature set. But it's a little heavyweight for web, is there a lite version or a way to create a custom build?

Yes there is an option to do custom builds. https://pubkey.github.io/rxdb/custom-build.html

It is my understanding that AppSync doesn't really support offline first yet. I would encourage you to keep an eye on efforts by the community such as Apollo repo you linked or the Khan Academy project mentioned in it.

If you need something _now_ you are probably better of looking outisde the GraphQL ecosystem though.

You should also consider what your need is. If you need true offline support (ie, you have an app that needs to fully function for days without internet) then that is a very different scenario from just needing to have a bit of data cached for the duration of a subway ride.

Thanks for the info, I just need to allow the client to queue up mutations offline (duration of a subway ride) and then notify the user visually of merge conflicts when we are back online. I don't need true offline support or live collaboration, just a very soft eventual consistency. I just don't want to worry about this while I'm working on core features for launch so I would like a premade solution.

When you say "offline first" do you just mean "local db"? You'd rather use GQL over SQL or some other query lang?

Not just a local db but an eventually consistent cache of remote whose data can be mutated offline and synced back into remote with some kind of conflict resolution. Examples here: http://offlinefirst.org/sync/

In the context of GraphQL I'm talking about a GraphQL client that has offline caching and supports syncing offline mutations. But I could also use something like pouch+couch: https://blog.couchbase.com/introduction-offline-data-storage...

This is super cool. It looks very similar to graphql-binding https://github.com/graphql-binding/graphql-binding

GraphQL Bindings are generated from a GraphQL schema and provides static typing in various languages. Right now code-gen for typescript is supported. Scroll down a bit on https://www.prismagraphql.com/ for a short video demonstrating how this works in practice.

I'm very happy that more projects are exploring code-gen for GraphQL.

Background: I've been using Typescript + graphql-yoga/apollo-server/express + Prisma to create a GraphQL server. I'm not familiar with golang.

I found this interesting. So just to check my understanding, does this auto generate the routing for the incoming GraphQL queries and mutations? Then you implement the resolvers / db components?

I'm also interested in hearing your thoughts on the maturity of the golang GraphQL ecosystem?

I've mostly been looking at the JS space and there's a lot of tooling. Having said that my experience has been that it's easy to write a simple GraphQL server but it gets complicated fast. I've been using Prisma which does a lot of the heavy lifting for you. It's relatively new so does come with trade-offs.

I think its still pretty early days, the easy stuff is fine. Once you throw in data loading or subscriptions you quickly run out of docs or find that its just flat out unsupported.

I'm hoping to change that though :)

Check out https://dgraph.io/ . I haven't had the chance to use it yet, but I have been following its development for a while. Definitely worth looking into.

Looks interesting. Shame the syntax is GraphQL-like but not pure GraphQL.

Looks like GraphQL compatibility is on the roadmap for 2018


Yeah, it takes your schema and your models and generates as much of the resolver graph as it can, then leaves you with an interface to implement for the bits it cant (usually trips back to the db).

This only generates the server and you need to write your own resolvers, connect to database, ... Prisma on the other hand handle everything out of the box for you.

Thanks. Yeah that's what I thought.

On Prisma, I have a graphql-yoga server which sits in front of Prisma. My server has its own schema and api and it handles auth, permissions and business logic

Yeah, would be more for existing apps that already have a bunch of domain logic.

Is it production ready?

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact