Khan / Khan/genqlient

[Meta] Document and improve support for Hasura & Dgraph schemas

Open
#272 8 comments 1 reaction 0 assignees View on GitHub
documentation enhancement needs design
Dominant language
Go
Stars
1.3k
Forks
143
Avg merge
4h 50m
Merged PRs (30d)
1

Description

We seem to have a lot of users using genqlient to query a [Hasura](https://hasura.io/docs/latest/index/)-generated schema, and they aren't having a great time of it; a lot of bugs and feature requests have come up over time. It would be good for us to take the time to do something a little more holistic, to see what support should look like. We can then document that, fix any gaps, etc. Similar issues may apply to [Dgraph](https://dgraph.io/), and other tools with large generated schemas.

Specific feature requests can go in specific issues, this is more of a meta-issue to think about how we should support hasura, and to document the same.

## The Problems

From reading all the issues mentioning Hasura, it seems like the main thing is the [query syntax](https://hasura.io/docs/latest/queries/postgres/query-filters/#the-where-argument) which has several interesting properties (discussed in #149 and #260):
- it generates complex and often self-referential types
- you usually only want to set a few fields of the very large input objects
- it distinguishes implicit and explicit null ([example](https://github.com/hasura/graphql-engine/blob/master/CHANGELOG.md#support-for-null-values-in-boolean-expressions))

These conflict badly with genqlient's defaults, and arguably with mapping the types to Go itself. (Some of these issues also apply to [mutation inputs](https://hasura.io/docs/latest/mutations/postgres/insert/#insert-a-single-object), but those are a bit closer to normal mutation inputs, and you probably use them in fewer places. Some of them also apply to other styles of input objects too, but hasura's are the most complex by far.)

There are also some other specific problems, which are more orthogonal but any documentation should mention too:
- hasura type names (both input and output) are non-idiomatic: #206

And some other things to document:
- a list of good bindings for hasura types

From #206, the lunasec folks have a decently large [example schema](https://github.com/lunasec-io/lunasec/blob/master/lunatrace/gogen/schema.graphql) as an example. There's also a [schema](https://github.com/Khan/genqlient/files/7437100/schema.graphql.zip) in #149. It could be interesting to have some tests against full hasura-generated schemas, or even integration tests against a hasura backend, to see how this looks.

## What should we generate?

Some thinking out loud.

First of all, one theory -- already very possible -- is to say you just want to [write your input object in the query](https://github.com/Khan/genqlient/issues/260#issuecomment-1533975590). This is obviously less flexible, which in the common case is arguably good but doesn't scale well if you want to construct your queries with arbitrary Go logic, and doesn't handle certain cases like arbitrary-length lists of objects (although short of jsonb and arbitrary-length boolean it's not clear those really exist -- this is SQL after all). LunaSec is using this in several places ([example](https://github.com/lunasec-io/lunasec/blob/master/lunatrace/gogen/gql/graphql/vulnerability.graphql#L2)).

Another theory is to just look at what (existing or plausible) options make hasura work better. I think `use_struct_references` is kinda close already; but that doesn't handle builtins. Global `omitempty` is a way out, but kinda a foot-gun for things like booleans. (LunaSec is doing that, via a fork.) Global `omitempty`-and-`pointer` is also an option -- hasura seems to now consider explicit null an error at least for all inputs if I'm understanding right? although on [updates](https://hasura.io/docs/latest/mutations/postgres/update/#update-all-objects) you might need it -- but that's annoying for builtins too. The problem is Go doesn't give us a lot to work with here for a "one-of" where you can't necessarily assume the go zero value is unused!

If we think a bit farther afield, I wonder about an API where we have separate constructors for each field you might want to set? It looks like you never per se need to set more than one (you can use an `_and` instead). So it would look something like
```go
function QueryAuthorInputWhereNameEquals(string) QueryAuthorInput
function QueryAuthorInputAnd(...QueryAuthorInput) QueryAuthorInput
```
And then the particulars of how we implement `QueryAuthorInput` aren't as important. That's not the most composable -- the and syntax in particular is a bit ugly -- but maybe that's ok. You could always go back to the old way for special cases.

## How should we configure?

Depending what we end up generating, we can look at how to configure genqlient to do so. One option is to figure out what a plugin would look like (#237). Another option is to have a special `hasura: true` config that does what you want, but probably better is to just document "here's a good set of defaults for hasura". We can see based on what it makes sense to generate.

## Your feedback is welcome!

Hasura users, please let us know which of these ideas sound good to you, whether you have any other problems, etc.! And if your schema/queries are open source, posting those would help me see what you're trying to do.

Contributor guide

Open the contributing guide

Research direction

Start by reviewing the Hasura query-syntax links and the related discussions in #149, #260, and #206, then examine the example schemas from LunaSec and #149. Compare the proposed generation and configuration approaches, including #237, and identify what support should be documented or tested. Done means the project has an agreed Hasura support approach, documented guidance, and any resulting gaps addressed.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, graphql
Domain
backend-api-design, documentation, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.