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 reserveImports 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
gofmtdoesn'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.