28 Commits

Author SHA1 Message Date
Ben Kraft f600b6e5d3 Bump golangci-lint and (max) Go versions (#219)
Lint is failing with some inscrutable panic (on a commit with no code
changes). Let's try bumping the version in case they fixed it.

Additionally, the new version's github action uses Go 1.19, which means
it pulls in gofmt updates to match the new [doc-comment formatting rules][1].
So I added Go 1.19 to our list of versions to test (fixes #216)
and updated some of our doc-comments to format better in the
new world (mostly using the new link syntax).

[1]: https://go.dev/doc/comment

Test plan: make lint
2022-08-15 15:05:36 -07:00
salman-rb 39a980ab4e Add support for client that uses GET as transport mechanism (#186)
Current implementation always uses POST as the transport mechanism. Adding GET support enables usage of GET queries for caching simply via URL.

Some notes:
- I left the existing API for creating a new client as is, but the implementation could be much cleaner by introducing some sort of configuration struct when creating a new client
- The construction of the query parameters follows the logic from Apollo's client implementation, which can be found here https://github.com/apollographql/apollo-client/blob/8beb4820edc6352996e08f7f73bde3573f1eb666/src/link/http/rewriteURIForGET.ts
- Updated integration tests to use both sets of clients. Updating the tests to use a test suite would be cleaner
2022-04-13 16:16:27 -07:00
Jan-Hendrik Boll b2422452a1 Add GraphQL Extensions (#184)
This enables accessing the Extensions field, as defined in the response
format: https://spec.graphql.org/October2021/#sec-Response-Format

Extensions can be enabled using configuration option use_extensions.
This will change the return parameters of the generated client
functions. Making it a breaking change if enabled.

Since extensions are untyped as defined in the spec, the Client will
return an interface of type map[string]interface{}.
2022-03-30 13:48:01 -07:00
Ben Kraft 000f311254 Remove ioutil (#181)
In 1.16, it's now deprecated and replaced by `io` and `os`.  Let's
upgrade!

Test plan:
- make check
- git grep ioutil
2022-03-22 12:10:24 -07:00
Hasibul Hasan 5401a62dcb TYPO: Fixed variable name and position in interface definition. (#154)
I was also confused about the variable names (#153). But in this [commit](https://github.com/Khan/genqlient/commit/5995653583af6e8d42477652f7d51ac4201b9fe6) it is clear that the first var is output, second var is input. In this commit I have fixed the issue. Fixes #153
2021-11-05 09:21:45 -07:00
Steve Coffman 47e9cea72e Let the Doer Do it (#115)
* Let the Doer do it

Signed-off-by: Steve Coffman <steve@khanacademy.org>

* Address review feedback

Signed-off-by: Steve Coffman <steve@khanacademy.org>
2021-09-27 13:48:57 -04:00
Ben Kraft 8de55d352e Add support for binding with a custom marshal/unmarshal function (#104)
## Summary:
This is useful if you want to bind to a type you don't control (or use
for other things) but need different serialization than its default.
This is a feature gqlgen has and we've found it very useful.  For
example, in webapp we want to bind `DateTime` to `time.Time`, but its
default serialization is not compatible with Python, so currently we
have to bind to a wrapper type and cast all over the place, which is
exactly the sort of boilerplate genqlient is supposed to avoid.

For unmarshaling, the implementation basically just follows the existing
support for abstract types; instead of calling our own generated
helper, we now call your specified function.  This required some
refactoring to abstract the handling of custom unmarshalers generally
from abstract types specifically, and to wire in not only the
unmarshaler-name but also the `generator` (in order to compute the right
import alias).

For marshaling, I had to implement all that stuff over again; it's
mostly parallel to unmarshaling (and I made a few minor changes to
unmarshaling to make the two more parallel).  Luckily, after #103 I at
least only had to do it once, rather than implementing the same
functionality for arguments and for input-type fields.  It was still
quite a bit of code; I didn't try to be quite as completionist about the
tests as with unmarshal but still had to add a few.

Issue: https://github.com/Khan/genqlient/issues/38

## Test plan:
make check


Author: benjaminjkraft

Reviewers: StevenACoffman, dnerdy, benjaminjkraft, aberkan, jvoll, mahtabsabet, MiguelCastillo

Required Reviewers: 

Approved By: StevenACoffman, dnerdy

Checks:  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Lint,  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Lint

Pull Request URL: https://github.com/Khan/genqlient/pull/104
2021-09-24 11:16:01 -07:00
Ben Kraft 5995653583 Refactor argument-handling to use a struct (#103)
## Summary:
In this commit I refactor the argument-generation logic to move most of
the code out of the template and into the type-generator.  This logic
predates #51, and I didn't think to update it there, but I think it
benefits from similar treatment, for similar reasons.

Specifically, the main change is to treat variables as another struct
type we can generate, rather than handling them inline as a
`map[string]interface{}`.  Users still pass them the same way, but
instead of putting them into a `map[string]interface{}` and JSONifying
that, we generate a struct and put them there.

This turns out to simplify things quite a lot, because we already have a
lot of code to generate types.  Notably, the omitempty code goes from a
dozen lines to basically two, and fixes a bug (#43) in the process,
because now that we have a struct, `json.Marshal` will do our work for
us! (And, once we have syntax for it (#14), we'll be able to handle
field-level omitempty basically for free.)  More importantly, it will
simplify custom marshalers (#38, forthcoming) significantly, since we do
all that logic at the containing-struct level, but will need to apply it
to arguments.

It does require two breaking changes:

1. For folks implementing the `graphql.Client` API (rather than just
   calling `NewClient`): we now pass them variables as an `interface{}`
   rather than a `map[string]interface{}`.  For most callers, including
   Khan/webapp, this is basically a one-line change to the signature of
   their `MakeRequest`, and it should be a lot more future-proof.
2. genqlient's handling of the `omitempty` option has changed to match
   that of `encoding/json`, in particular it now never considers structs
   "empty".  The difference was never intentional (I just didn't realize
   that behavior of `encoding/json`); arguably our behavior was more
   useful but I think that's outweighed by the value of consistency with
   `encoding/json` as well as the simpler and more correct
   implementation (fixing #43 is actually quite nontrivial otherwise).
   Once we have custom unmarshaler support (#38), users will be able to
   map a zero value to JSON null if they wish, which is mostly if not
   entirely equivalent for GraphQL's purposes.

Issue: https://github.com/Khan/genqlient/issues/38
Issue: https://github.com/Khan/genqlient/issues/43

## Test plan:
make check

Author: benjaminjkraft

Reviewers: StevenACoffman, dnerdy, aberkan, jvoll, mahtabsabet, MiguelCastillo

Required Reviewers: 

Approved By: StevenACoffman, dnerdy

Checks:  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Lint,  Lint,  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14)

Pull Request URL: https://github.com/Khan/genqlient/pull/103
2021-09-22 17:16:36 -07:00
Ben Kraft 4d2058c617 Add a bunch more documentation (and rewrite README) (#86)
## Summary:
In this commit, I add a bunch more documentation of how to use
genqlient, including a getting started guide, and a FAQ that also acts
as a how-to shaped index of common configuration options and extension
points.  Much of this is adapted from the internal doc I wrote at Khan,
or reorganized from what was in the README.  Speaking of which, now that
there are better places for all the details, I rewrote the README to be
a bit more of an overview and index of other documentation.  (For now I
left the "unmaintained" notes, which I'll remove fairly soon once all
our ducks are in a row.)

Fixes #26, #39.

Issue: https://github.com/Khan/genqlient/issues/26
Issue: https://github.com/Khan/genqlient/issues/39

## Test plan:
make check, read the docs


Author: benjaminjkraft

Reviewers: mahtabsabet, benjaminjkraft, aberkan, dnerdy, jvoll, MiguelCastillo

Required Reviewers: 

Approved By: mahtabsabet

Checks:  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Lint,  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Lint

Pull Request URL: https://github.com/Khan/genqlient/pull/86
2021-09-14 11:05:11 -07:00
Steve Coffman 673840e495 Picking some nits that my IDE complained about (#91)
* Picking some nits that my IDE complained about

Signed-off-by: Steve Coffman <steve@khanacademy.org>

* Update graphql/util.go

Co-authored-by: Ben Kraft <benkraft@khanacademy.org>

* revert to original for comment

Signed-off-by: Steve Coffman <steve@khanacademy.org>

Co-authored-by: Ben Kraft <benkraft@khanacademy.org>
2021-09-14 13:42:47 -04:00
Ben Kraft f99c10d6fd Add support for concrete-typed named fragments (#75)
## Summary:
In previous commits I added support to genqlient for interfaces and
inline fragments.  This means the only query structures that remain are
named fragments and their spreads, e.g.
```
fragment MyFragment on MyType { myField }
query MyQuery { getMyType { ...MyFragment } }
```
Other than mere completionism, these are potentially useful for code
sharing: you can spread the same fragment multiple places; and then
genqlient can notice that and generate the same type for each.  (They
can even be shared between different queries in the same package.)

In this commit I add support for named fragments of concrete
(object/struct, not interface) type, spread into either concrete or
abstract scope.  For genqlient's purposes, these are a new "root"
type-name, just like each operation, and are then embedded into the
appropriate struct.  (Using embeds allows their fields to be referenced
as fields of the containing type, if convenient.  Further design
considerations are discussed in DESIGN.md.)

This requires new code in two main places (plus miscellaneous glue),
both nontrivial but neither particularly complex:
- We need to actually traverse both structures and generate the types
  (in `convert.go`).
- We need to decide which fragments from this package to send to the
  server, both for good hyigene and because GraphQL requires we send
  only ones this query uses (in `generate.go`).
- We need a little new wiring for options -- because fragments can be
  shared between queries they get their own toplevel options, rather
  than inheriting the query's options.

Finally, this required slightly subtler changes to how we do
unmarshaling (in `types.go` and `unmarshal.go.tmpl`).  Basically,
because embedded fields' methods, including `UnmarshalJSON`, get
promoted to the parent type, and because the JSON library ignores their
fields when shadowed by those of the parent type, we need a little bit
of special logic in each such parent type to do its own unmarshal and
then delegate to each embed.  This is similar (and much simpler) to
what we did for interfaces, although it required some changes to the
"method-hiding" trick (used for both).  It's only really necessary in
certain specific cases (namely when an embedded type has an
`UnmarshalJSON` method or a field with the same name as the embedder),
but it's easier to just generate it always.  This is all described in
more detail inline.

This does not support fragments of abstract type, which have their own
complexities.  I'll address those, which are now the only remaining
piece of #8, in a future commit.

Issue: https://github.com/Khan/genqlient/issues/8

## Test plan:
make check


Author: benjaminjkraft

Reviewers: dnerdy, benjaminjkraft, aberkan, MiguelCastillo

Required Reviewers: 

Approved By: dnerdy

Checks:  Lint,  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Test (1.13),  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Test (1.13),  Lint,  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Test (1.13),  Lint

Pull Request URL: https://github.com/Khan/genqlient/pull/75
2021-09-09 09:39:30 -07:00
Ben Kraft 700392315a Enable golangci-lint (#49)
## Summary:
It would be nice to have some linting beyond `go vet`!  Now we do.  I
started by copying the config from Khan/webapp.  I did remove a couple
of staticcheck checks that I didn't feel were useful.  (Note also that
exportloopref is the replacement for scopelint in newer golangci-lint.)

Included are all the needed lint fixes; most are stylistic but the
changes in the example are a (minor) bugfix.

Fixes #22.
Issue: https://github.com/Khan/genqlient/issues/22

## Test plan:
make check

Author: benjaminjkraft

Reviewers: aberkan, dnerdy, benjaminjkraft, csilvers, MiguelCastillo

Required Reviewers: 

Approved by: aberkan, dnerdy

Checks:  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Test (1.13),  Lint,  Test (1.17),  Test (1.16),  Test (1.15),  Test (1.14),  Test (1.13),  Lint

Pull request URL: https://github.com/Khan/genqlient/pull/49
2021-08-20 10:39:12 -07:00
Ben Kraft f1914cd9ef log response body, not request body, on non-200 2021-04-22 10:14:26 -07:00
Ben Kraft b399e0d740 move TODOs into issues 2021-04-21 19:05:38 -07:00
Ben Kraft d880512499 set content-type header 2021-04-05 12:50:30 -07:00
Ben Kraft fbf00f3bef add option to export all operations 2021-04-01 13:11:23 -07:00
Ben Kraft 27ee3c2dbd fixes while integrating into webapp 2021-03-30 17:53:31 -07:00
Ben Kraft cbebeaaed4 rename in code 2021-03-30 12:41:37 -07:00
Ben Kraft 2c52314494 set opname 2021-03-30 11:27:43 -07:00
Ben Kraft e3f6afeb78 more documentation in client.go, simplify unmarshaling slightly 2021-03-25 14:26:25 -07:00
Ben Kraft f136758db4 misc bits of documentation 2021-03-25 14:13:14 -07:00
Ben Kraft 937540d244 make client an interface 2021-03-25 14:08:12 -07:00
Ben Kraft 59ca841a6b start of wiring for configurable context 2021-03-22 19:09:17 -07:00
Ben Kraft a42c9b8166 clean up various TODOs and comments 2021-03-22 18:11:51 -07:00
Ben Kraft bf5d04939e WIP on config 2020-01-03 11:02:31 -08:00
Ben Kraft 9746c818fd genql: quick hack at variables 2020-01-02 17:52:55 -08:00
Ben Kraft 7f6ab70ee3 wire auth to example, fix wire format, it's aliiiiiive! 2019-12-25 21:33:12 -05:00
Ben Kraft 4d880a701e move a bunch of the logic from generated into client 2019-12-25 16:26:32 -05:00