Cross
Cross

Reputation: 835

GQGEN: Nested entities are not captured by the resolver

I'm very new to graphQL so I'm trying to create an api using library "gqlgen". But I faced with the problem.

I have 2 tables: user and balance which are related by one-to-one relationship, so I want to get balance nested in user model in response. But GetBalanceResolver method are not even called.

So here's my schema:

type User {
  id: Int!
  firstname: String!
  lastname: String!
  phoneNumber: String!
  balance: Balance
}

type Query {
  getUser(id: Int!): User
  getBalance(id: Int!): Balance
}

type Balance {
  id: Int!
  balanceValue: Float!
}

Here's resolver:

type Resolver struct {
    Repo *UserRepo
}

// GetUser is the resolver for the getUser field.
func (r *queryResolver) GetUser(ctx context.Context, id int) (*model.User, error) {
    user := r.Repo.GetUser(int64(id))
    log.Println("hello")
    return &model.User{
        ID:          int(user.Id),
        Firstname:   user.Firstname,
        Lastname:    user.Lastname,
        PhoneNumber: user.PhoneNumber,
    }, nil
}

// GetBalance is the resolver for the getBalance field.
func (r *queryResolver) GetBalance(ctx context.Context, id int) (*model.Balance, error) {
    balance := r.Repo.GetBalance(int64(id))
    return &model.Balance{
        ID:           int(balance.Id),
        BalanceValue: balance.BalanceValue,
    }, nil
}

// Query returns QueryResolver implementation.
func (r *Resolver) Query() QueryResolver {
    return &queryResolver{r}
}

type queryResolver struct{ *Resolver }

type mutationResolver struct {
    *Resolver
}

Here's userRepo:

type IUserRepo interface {
    GetUser(uid int64) *models.UserModel
}

type UserRepo struct {
}

func (r *UserRepo) GetUser(uid int64) *models.UserModel {
    fmt.Println(uid)
    user := &models.UserModel{}
    query := `SELECT user_id, firstname, lastname, phone_number FROM user_schema.user_account WHERE user_id = $1`
    err := constant.Db.QueryRowContext(context.Background(), query, uid).Scan(&user.Id, &user.Firstname, &user.Lastname, &user.PhoneNumber)
    if err != nil {
        panic(err)
    }
    return user
}

func (r *UserRepo) GetBalance(bid int64) *models.BalanceModel {
    balance := &models.BalanceModel{}
    query := `SELECT balance_id, balance_value FROM user_schema.balance WHERE user_id = $1`
    rows, err := constant.Db.Query(query, bid)
    if err != nil {
        panic(err)
    }
    rows.Scan(&balance.Id, &balance.BalanceValue)
    if err := rows.Err(); err != nil {
        panic(err)
    }
    return balance
}

And here's the gqlgen.yml:

schema:
  - graph/*.graphqls
exec:
  filename: graph/generated.go
  package: graph

model:
  filename: graph/model/models_gen.go
  package: model

resolver:
  layout: follow-schema
  dir: graph
  package: graph
  filename_template: "{name}.resolvers.go"

models:
  ID:
    model:
      - github.com/99designs/gqlgen/graphql.ID
      - github.com/99designs/gqlgen/graphql.Int
      - github.com/99designs/gqlgen/graphql.Int64
      - github.com/99designs/gqlgen/graphql.Int32
  Int:
    model:
      - github.com/99designs/gqlgen/graphql.Int
      - github.com/99designs/gqlgen/graphql.Int64
      - github.com/99designs/gqlgen/graphql.Int32

And here's the request that I provide in graphql playground:

query {
  getUser(id: 1) {
    firstname,
    lastname,
    balance {
      id,
      balanceValue
    }
  }
}

Response:

{
  "data": {
    "getUser": {
      "firstname": "vvvvv",
      "lastname": "aaaa",
      "balance": null
    }
  }
}

So what can be the problem? If you know, please, tell me, I'd really appreciate it!

Upvotes: 5

Views: 188

Answers (1)

Michel Floyd
Michel Floyd

Reputation: 20256

You're equating query resolvers with field resolvers. Yes, they are both resolvers, but what triggers them is different.

A query resolver is triggered by, you guessed it, a query. Your model defines 2 queries, getUser and getBalance.

A field resolver resolves a field within a type. Your User type includes the balance field but you haven't expressed how to resolve balance when a User object is being requested.

I believe you'll need to create a model for your User type and include the resolver for the balance field there.

Upvotes: 0

Related Questions