【问题标题】:GraphQL resolver oddly returns some fields as nullGraphQL 解析器奇怪地将某些字段返回为 null
【发布时间】:2020-07-21 09:38:21
【问题描述】:

在简要概述中,我正在尝试解析用户列表。我有一个 Apollo 服务器,它用我自己的方式拼接了一个 accounts-js 架构。所以我扩展了 User 类型以包含一些额外的字段。不过,在这种情况下,我只能返回 SOME 字段,其余为 null。

getUsers: async (_, __, ctx) => {
    let action = await usersModel.find();
    console.log(action)
    return action;  
},

我的me 查询确实返回了所有数据,但没有返回单个空字段。

  extend input CreateUserInput {
    isAdmin: Boolean!
  }

  extend type User {
    isAdmin: Boolean
    profile: Profile
    keys: [Key]
  }

  type Profile {
    avatar: String
    bio: String
  }

  type Key {
    id: ID
    livenet: Boolean
    nickname: String
  }
    
  type Query {
    getUsers: [User]
    me: User
  }

不过,当我在解析器中 console.log(action) 查询 getUsers 时,这些是在我的控制台中返回的文档。

[ { profile: { bio: 'haha' },
    _id: 5f0a901bdcf725204446c949,
    isAdmin: true,
    services: { password: [Object], email: [Object] },
    createdAt: 1594527771625,
    updatedAt: 1594691054105,
    username: 'ayooo',
    emails: [ [Object] ],
    keys: [ [Object], [Object] ] },
  { profile: { bio: 'testing' },
    _id: 5f0a9439abfce521aba79b2c,
    isAdmin: false,
    services: { password: [Object], email: [Object] },
    createdAt: 1594528825858,
    updatedAt: 1594762680766,
    username: 'lol',
    emails: [ [Object] ],
    keys: [ [Object] ] } ]

如果我下载我的整体 GraphQL 架构,它看起来是这样的:

directive @auth on FIELD_DEFINITION | OBJECT
input AuthenticateParamsInput {
  access_token: String
  access_token_secret: String
  provider: String
  password: String
  user: UserInput
  code: String
}

input CreateUserInput {
  isAdmin: Boolean!
  username: String
  email: String
  password: String
}

type CreateUserResult {
  userId: ID
  loginResult: LoginResult
}

type EmailRecord {
  address: String
  verified: Boolean
}

type ImpersonateReturn {
  authorized: Boolean
  tokens: Tokens
  user: User
}

input ImpersonationUserIdentityInput {
  userId: String
  username: String
  email: String
}

type Key {
  id: ID
  livenet: Boolean
  exchange: String
  nickname: String
  apiKey: String
  apiSecret: String
}

type LoginResult {
  sessionId: String
  tokens: Tokens
  user: User
}

type Mutation {
  setBio(bio: String): ID
  setAvatar(avatar: String): ID
  changeUsername(username: String): ID
  setKey(
    livenet: Boolean
    exchange: String
    nickname: String
    apiKey: String
    apiSecret: String
  ): ID
  createUser(user: CreateUserInput!): CreateUserResult
  verifyEmail(token: String!): Boolean
  resetPassword(token: String!, newPassword: String!): LoginResult
  sendVerificationEmail(email: String!): Boolean
  sendResetPasswordEmail(email: String!): Boolean
  addEmail(newEmail: String!): Boolean
  changePassword(oldPassword: String!, newPassword: String!): Boolean
  twoFactorSet(secret: TwoFactorSecretKeyInput!, code: String!): Boolean
  twoFactorUnset(code: String!): Boolean
  impersonate(
    accessToken: String!
    impersonated: ImpersonationUserIdentityInput!
  ): ImpersonateReturn
  refreshTokens(accessToken: String!, refreshToken: String!): LoginResult
  logout: Boolean
  authenticate(
    serviceName: String!
    params: AuthenticateParamsInput!
  ): LoginResult
  verifyAuthentication(
    serviceName: String!
    params: AuthenticateParamsInput!
  ): Boolean
}

type Profile {
  avatar: String
  bio: String
}

type Query {
  getUsers: [User]
  getProfile: Profile
  serverTime: String
  me: User
  twoFactorSecret: TwoFactorSecretKey
  getUser: User
}

type Tokens {
  refreshToken: String
  accessToken: String
}

type TwoFactorSecretKey {
  ascii: String
  base32: String
  hex: String
  qr_code_ascii: String
  qr_code_hex: String
  qr_code_base32: String
  google_auth_qr: String
  otpauth_url: String
}

input TwoFactorSecretKeyInput {
  ascii: String
  base32: String
  hex: String
  qr_code_ascii: String
  qr_code_hex: String
  qr_code_base32: String
  google_auth_qr: String
  otpauth_url: String
}

type User {
  username: String
  isAdmin: Boolean
  profile: Profile
  keys: [Key]
  id: ID!
  emails: [EmailRecord!]
}

input UserInput {
  id: ID
  email: String
  username: String
}

请注意,getUser 或我的查询会返回所有请求的数据。对于我需要在前端查询的重要内容,getUsers 只会返回一点点,大部分为空。我正在尝试在我的管理面板的表格中列出用户。也许这不是最好的方法?有人告诉我!

与查询返回用户的megetUser 不同。 :/

【问题讨论】:

    标签: javascript typescript graphql apollo


    【解决方案1】:
    type Query {
        getUsers: [User]
        me: User
      }
    

    您的查询getUsers 返回User 类型的数组。

      extend type User {
        isAdmin: Boolean
        profile: Profile
        keys: [Key]
      }
    

    为什么是extend?是否存在更早的User 定义? ...无论如何graphQL 服务器只返回在返回类型中定义的字段。您的User 类型只有isAdminprofilekeys 属性。只会返回那些字段。

    解决方案:扩展您的 User 类型定义以获取其他存在于 DB 字段中。

    【讨论】:

    • 如上所示,isAdmin 被列为 User 扩展类型中的一个字段,在我查询 getUsers 时仍然返回 null。我还添加了用户名来尝试,但没有任何改变。返回的只有 id、[Keys] 和 [Profile]
    • 您是否在使用一些中间件(在 graphql 服务器上)来限制对字段的访问?
    • 我已经尝试过添加和不添加 @auth 到类型。我在想这只是因为结果是如何格式化的?虽然,这似乎是对的。对为什么不是所有字段都填充感到困惑:/
    • “缝合 accounts-js 架构的 Apollo 服务器”是什么意思?缝合/联合?如何连接?
    • 检查文档 - graphiql/playground 中的类型定义 - 可能某些类型没有按照您想要的方式合并(覆盖,未扩展?) - 更改 mergeTypeDefs 中的 args 顺序?
    【解决方案2】:

    所以在敲掉了很多其他的东西之后,我才意识到这是由于我没有完全定义我的猫鼬模式!

    
    mongoose.connect(process.env.MONGO_URI, {
      useNewUrlParser: true,
      useFindAndModify: false,
      useCreateIndex: true,
      useUnifiedTopology: true,
    });
    
    var usersSchema = new mongoose.Schema({
      username: String,
      isAdmin: Boolean,
      emails: [{ 
        verified: Boolean, 
        address: String 
      }],
      profile: {
        avatar: String,
        bio: String,
      },
      keys: [{ 
        nickname: String,
        exchange: String,
        livenet: Boolean,
        apiKey: String,
        apiSecret: String,
      }]
    });
    
    export const usersModel = mongoose.model('Users', usersSchema, 'users');
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-19
      • 1970-01-01
      • 1970-01-01
      • 2012-10-06
      • 1970-01-01
      • 2022-01-10
      • 2019-07-23
      相关资源
      最近更新 更多