gqlgen
gqlgen copied to clipboard
Generate imports wrong package and gives error
What happened?
When running go run github.com/99designs/gqlgen generate
the generated resolver functions imports the wrong package.
if I use the github.com/pkg/errors library in my resolvers and then later on I trigger the generate
command, gqlgen will remove this import and instead import the standard library's errors
package.
PRE go run github.com/99designs/gqlgen generate
// user.resolvers.go
import (
"context"
"github.com/pkg/errors"
"github.com/foo/bar/app"
)
func (r *queryResolver) Me(ctx context.Context) (*app.User, error) {
user,err := app.UserFromContext(ctx)
if err != nil {
return nil, errors.Wrap(err, "no user in context")
}
return user, nil
}
POST go run github.com/99designs/gqlgen generate
validation failed: packages.Load: /github.com/foo/bar/graph/resolver/user.resolvers.go: Wrap not declared by package errors
Updated generated file...
// user.resolvers.go
import (
"context"
"errors"
"github.com/foo/bar/app"
)
func (r *queryResolver) Me(ctx context.Context) (*app.User, error) {
user,err := app.UserFromContext(ctx)
if err != nil {
return nil, errors.Wrap(err, "no user in context")
}
return user, nil
}
So even though stdlib errors
pkg doesn't have a Wrap
function, it will still be added to the import statement rather than using the one that was previously declared github.com/pkg/errors
followed by reporting that the function is not declared in that package.
gqlconfig.yml
schema:
- "graph/schema/**/*.graphql"
exec:
filename: graph/generated/generated.go
package: generated
resolver:
layout: follow-schema
dir: graph/resolver
package: resolver
struct_tag: gql
omit_slice_element_pointers: true
autobind:
- github.com/foo/bar/app
What did you expect?
import / use the already declared package rather than attempting to import it's own
Minimal graphql.schema and models to reproduce
# schema/schema.graphql
schema {
query: Query
mutation: Mutation
}
type Query
type Mutation
# schema/types/user.graphql
extend type Query {
me: User
}
type User {
id: ID!
email: String!
name: String
}
versions
-
gqlgen version
? v0.11.3 -
go version
? 1.14 - dep or go modules? go mod
I have this problem too. import "github.com/pkg/errors" not work
+1 . Any plan?
https://github.com/99designs/gqlgen/blob/master/plugin/resolvergen/resolver.gotpl#L7
del this will resolve this issue. Why add lines:
{{ reserveImport "context" }}
{{ reserveImport "fmt" }}
{{ reserveImport "io" }}
{{ reserveImport "strconv" }}
{{ reserveImport "time" }}
{{ reserveImport "sync" }}
{{ reserveImport "errors" }}
{{ reserveImport "bytes" }}
As a hacky workaround until this gets fixed, I created a plugin to remove the line and re-run goimports after it generates the errant file.
package main
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"github.com/99designs/gqlgen/api"
"github.com/99designs/gqlgen/codegen"
"github.com/99designs/gqlgen/codegen/config"
)
type ImportsPlugin struct {
}
func (ImportsPlugin) Name() string {
return "Imports"
}
func (ImportsPlugin) GenerateCode(cfg *codegen.Data) error {
dir := cfg.Config.Resolver.Dir()
badLineRegexp := regexp.MustCompile(`\n\s*"errors"\n`)
return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !strings.HasSuffix(info.Name(), ".resolvers.go") {
return nil
}
f, err := ioutil.ReadFile(path)
if err != nil {
return err
}
if !badLineRegexp.Match(f) {
return nil
}
n := badLineRegexp.ReplaceAll(f, []byte("\n"))
err = ioutil.WriteFile(path, n, os.ModePerm)
if err != nil {
return err
}
c := exec.Command("go", "run", "golang.org/x/tools/cmd/goimports", "-w", path)
c.Stdout = os.Stdout
c.Stderr = os.Stderr
return c.Run()
})
}
func main() {
cfg, err := config.LoadConfigFromDefaultLocations()
if err != nil {
fmt.Fprintln(os.Stderr, "failed to load config", err.Error())
os.Exit(2)
}
err = api.Generate(cfg,
api.AddPlugin(ImportsPlugin{}),
)
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(3)
}
}
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
An alternative to @duckbrain his solution it to use gofmt
to update the imports. Just run the following at the root of your project after you (re-)generated the files:
gofmt -w -d -r '"errors" -> "github.com/pkg/errors"' **/*.go
+1
+1
This is still a problem however I've found what seems like a good workaround, simply import as
werrors "github.com/pkg/errors"
and it doesn't get changed to "errors"
.
@j0hnsmith it is a nice workaround, but it requires you to write a custom import in every file where you need that errors package. It will also not work with auto import tooling. Since you run the generation command anyway, it is easy to just run the gofmt
command to do the rewrite for you.
Ahh, I see. I'm totally new to gqlgen
, just running commands in a Makefile
. The command exits with status 1 so I assumed that it was unsuccessful however I now understand that the code was generated ok, I assume it's only the post generation validation step that fails (which can be corrected by running gofmt
).
@mtibben This is still a problem, can you reopen this issue to help others find it. Also would be good to add a .github/stale.yml with a exemptLabels
and add a doNotClose
label to prevent this issue from being closed.
The other reserveImport
s look reasonable however github.com/pkg/errors
is commonly used, what would the impact of removing {{ reserveImport "errors" }}
be?
Running gofmt
doesn't fix the imports for me :(
Running
gofmt
doesn't fix the imports for me :(
Did you ran this from the root without the werror
import?:
gofmt -w -d -r '"errors" -> "github.com/pkg/errors"' **/*.go
It is open again!! Thanks @mtibben 👍🏻
Lets improve on this one. I have a personal branch with some fixes that might be interesting to pull. It just switches to the github.com/pkg/errors package. Not sure if we need anything more than that?
@pjvds many users may not want to use "github.com/pkg/errors" and GQLGen has no way of knowing that github.com/pkg/errors is a drop-in replacement for errors. @j0hnsmith's workaround seems pretty reasonable to me.
The general problem is GQLGen may request an import who's name conflicts with an existing import. The best way I could think to solve the problem is add a configuration option to map imports to a replacement, kind of like a replace
directive in go.mod
, but it replaces the generated import. It would be up to the user to ensure the replaced package is compatible with GQLGen's usage of it.
See: https://github.com/99designs/gqlgen/blob/5ad012e3d7be1127706b9c8a3da0378df3a98ec1/codegen/templates/import.go#L43 where the import is handled.
Alternatively the specific problem was introduced by the resolvers template moving from panic("not implemented")
to panic(errors.Errorf("not implemented"))
.
Did you ran this from the root without the werror import?:
@pjvds I've realised the command I ran was incorrect, the one you provided does work for me.
After discussing it with a colleague who is more familiar with this stuff, we're going to go down the werrors
route as it's a 'one time' fix (per file) for what we have (until we add new schemas).
fmt aliase f
after gqlgen generate, f was deleted
hey guys, any update on this ?
I wonder why gqlgen
does insertions and deletions of the imports on its own in contrast to relying on golang.org/x/tools/imports
, which is purely made for this purpose, used with great success in most IDE/editors and is maintained by the Go maintainers.
The pruning happens in https://github.com/99designs/gqlgen/blob/master/internal/imports/prune.go and while golang.org/x/tools/imports
is used, it is forced to not touch the imports (see: https://github.com/99designs/gqlgen/blob/master/internal/imports/prune.go#L46). The respective commit (https://github.com/99designs/gqlgen/commit/732be3959b402bbd3b864c5f40f475640f1334c5) states "Don't let goimports guess import paths" in the commit message, but does not give a reason for this decision nor a reference to an issue.
Wouldn't this issue be resolved, if the line {{ reserveImport "errors" }}
(https://github.com/99designs/gqlgen/blob/master/plugin/resolvergen/resolver.gotpl#L7) is removed and golang.org/x/tools/imports
would not be be limited to formatting only?
hey guys, anyone found a fix for this ?
Bump. This is a genuine issue and none of the mentioned fixes are really satisfactory. I'm happy to work on a PR if someone can tell me it's okay to make a configuration option for replacing packages
Alternatively, would be nice to know why golang.org/x/tools/imports
was made to not touch imports and a custom implementation was made instead. I'll mention @vektah who is the author for the commit breml mentioned. Hopefully we can get this moving :slightly_smiling_face:
Bump. Been about 6 months since the last bump. Any have any updates? Has there been any traction on this fix or a workaround more suitable than gofmt
after generate
?
it seems that adding an alias to the import makes gqlgen ignore it, I use that as a workaround
it seems that adding an alias to the import makes gqlgen ignore it, I use that as a workaround
Adding an alias seems to make said aliased imports get removed entirely, in my case.
Edit: Spoke too soon, seems to work for some packages but not others. "github.com/99designs/gqlgen/graphql"
for example, if aliased, gets removed.