diff --git a/README.md b/README.md index 841dcca..e56d23c 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,16 @@ client.Query(context.Background(), &query, nil) fmt.Println(query.Me.Name) // Output: Luke Skywalker ``` -While your code is type-safe, there's nothing to check that the schema looks like you intend it to. In fact, perhaps here we're querying the GitHub API, in which the field is called `viewer`, not `me`, so this query will fail. Even more common than misusing the name of the field is mis-capitalizing it: the GraphQL convention is `myUrl` whereas the Go convention is `MyURL`, and it's easy to forget to use the right struct tag. (And if you remember, it adds up to a lot of boilerplate!) Other clients, such as [machinebox/graphql](https://github.com/machinebox/graphql), have even fewer guardrails to help you make the right query. +While your code is type-safe, there's nothing to check that the schema looks like you intend it to. In fact, perhaps here we're querying the GitHub API, in which the field is called `viewer`, not `me`, so this query will fail. Even more common than misusing the name of the field is mis-capitalizing it: the GraphQL convention is `myUrl` whereas the Go convention is `MyURL`, and it's easy to forget to use the right struct tag. (And if you remember, it adds up to a lot of boilerplate!) Other clients, such as [machinebox/graphql](https://github.com/machinebox/graphql), have even fewer guardrails to help you make the right query and use the result correctly. These problems should be entirely avoidable: GraphQL and Go are both typed languages; and GraphQL servers expose their schema in a standard, machine-readable format. We should be able to simply write a query `{ viewer { name } }`, have that automatically validated against the schema and turned into a Go struct which we can use in our code. In fact, there's already good prior art to do this sort of thing: [99designs/gqlgen](https://github.com/99designs/gqlgen) is a popular server library that does exactly this: it generates type-safe GraphQL resolvers from a schema. This is a proof-of-concept of a GraphQL client that does the same sort of thing: you specify the query, and it generates type-safe helpers that make your query. +## Usage + +See `example/`. + ## Major TODOs Query structures to support: @@ -33,3 +37,6 @@ Config options: - file locations (queries, generated, schema (or get via HTTP)) - use ctx or not, incl. complexities of how Khan uses context - HTTP calling convention (is there enough variation to matter?) + +Other: +- figure out and document go generate syntax diff --git a/example/README.md b/example/README.md index f62ea3f..a6a36c1 100644 --- a/example/README.md +++ b/example/README.md @@ -1,7 +1,34 @@ -Generate the schemas by getting a token from [GitHub](https://github.com/settings/tokens/new) (no scopes needed), then: +# example of genql + +## Getting a token +Get a token from [GitHub](https://github.com/settings/tokens/new) (no scopes needed). + +## Invoking the example + +To run the example: + +```sh +$ KEY= go run ./cmd/example/main.go +you are Ben Kraft +csilvers is Craig Silverstein ``` + +## Running genql + +It's already checked in to github, but to generate `generated.go`: +```sh +rm example/generated.go +go run ./cmd/genql/main.go example/genql.yaml +``` + +## Generating the schema files + +These are also checked in, but to update them: + +```sh npm install -g graphql-introspection-json-to-sdl curl -H "Authorization: bearer " https://api.github.com/graphql >example/schema.json graphql-introspection-json-to-sdl example/schema.json >example/schema.graphql ``` + TODO: something better diff --git a/example/generated.go b/example/generated.go index 173074d..9655469 100644 --- a/example/generated.go +++ b/example/generated.go @@ -1,3 +1,4 @@ +// Code generated by github.com/Khan/genql, DO NOT EDIT. package example import ( diff --git a/example/genql.yaml b/example/genql.yaml new file mode 100644 index 0000000..e6def54 --- /dev/null +++ b/example/genql.yaml @@ -0,0 +1,5 @@ +# These are the defaults. +package: example +schema: schema.graphql +queries: queries.graphql +generated: generated.go diff --git a/generate/config.go b/generate/config.go index 1ebf520..3acbbde 100644 --- a/generate/config.go +++ b/generate/config.go @@ -62,7 +62,7 @@ func ReadAndValidateConfig(filename string) (*Config, error) { } var config Config - err = yaml.Unmarshal(text, config) + err = yaml.Unmarshal(text, &config) if err != nil { return nil, fmt.Errorf("invalid config file %v: %v", filename, err) } @@ -72,5 +72,12 @@ func ReadAndValidateConfig(filename string) (*Config, error) { return nil, fmt.Errorf("invalid config file %v: %v", filename, err) } + // Make paths relative to config dir + // TODO: more principled typing here? + basename := filepath.Dir(filename) + config.Schema = filepath.Join(basename, config.Schema) + config.Queries = filepath.Join(basename, config.Queries) + config.Generated = filepath.Join(basename, config.Generated) + return &config, nil } diff --git a/generate/main.go b/generate/main.go index d73110e..554a788 100644 --- a/generate/main.go +++ b/generate/main.go @@ -46,6 +46,7 @@ func Main() { }() if len(os.Args) != 2 { + // TODO: omit config to get it from genql.yaml, or to use the defaults. err = fmt.Errorf("usage: %s genql.yaml", os.Args[0]) return } diff --git a/generate/operation.go.tmpl b/generate/operation.go.tmpl index 5a9d5a7..6552140 100644 --- a/generate/operation.go.tmpl +++ b/generate/operation.go.tmpl @@ -1,3 +1,4 @@ +// Code generated by github.com/Khan/genql, DO NOT EDIT. package {{.PackageName}} import (