Can’t convert {data: []} to Vector

I have a query for login:

query {
  loginUser(username: "Test 1", password: "hello")
}

which gives following in Playground:

{
  "data": null,
  "errors": [
    {
      "message": "Can't convert '\"fnED2f3OLXACBwPPrLxk4AYI-ETyHFHNN3eLFBhe2jdnACmipuo\"' to Vector",
      "path": [
        "loginUser"
      ],
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ]
}

I correctly receive a token but with the error message.
I reviewed this posting:


and added

@resolver(name: "login_user", paginated: true)

to the schema and uploaded it.
Now, with:

query {
  loginUser(username: "Test 1", password: "hello" )
  {
    data {
      secret
    }
  }
}

I get:

"data": null,
  "errors": [
    {
      "message": "Field 'data' of type 'String' must not have a sub selection. (line 3, column 5):\n    data {\n    ^",
      "locations": [
        {
          "line": 3,
          "column": 5
        }
      ]
    }
  ]
}

but with:

query {
  loginUser(username: "Test 1", password: "hello" )

}

I get:

{
  "data": null,
  "errors": [
    {
      "message": "Field 'loginUser' of type 'QueryLoginUserPage!' must have a sub selection. (line 2, column 3):\n  loginUser(username: \"Test 1\", password: \"hello\")\n  ^",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ]
}

This is perhaps because I haven’t implemented:

Map(
  Paginate(
    Filter(

etc. in the query, as per the posting. However, as a beginner, I don’t have the FQL experience to modify my function to this extent (and perhaps the ‘vector’ error is just a bug anyway: vector bug (?)).

  1. Is this still a bug and I just need to wait for a fix?
  2. Is there something I can do in the meantime?
    thanks …

hi @FreeRoss

would you provide the GraphQL schema and, in case. the function you are using?

Luigi

Sure. The schema:

type User 
 {  
    active : Boolean!
    username : String! @unique
    password : String! @unique
    ethaddress : String! @unique
    description : String
    email : String @unique 
    mobile : String @unique
    member_since: Int!
}

type Player 
 {  address : String! @unique
    rank : Int!
    challengeraddress : String
}

type Ranking
  { 
    active : Boolean!
    rankingname : String! @unique
    rankingdesc : String
    rankingowneraddr : String! @unique
    }

type UserJoinedRanking
  { 
    active : Boolean!
    rankingid : String!
    rankingname : String!
    useraddr : String!
    rankingowneraddr : String!
    }


type Mutation {
  createAndOrLoginUser(active: Boolean!, username: String!, password: String!, ethaddress: String!, description: String, email: String, mobile: String): String! @resolver(name: "create_andor_login_user")
  createNewPlayer(active: Boolean!, address: String!, rank: Int!, challengeraddress: String): Player! @resolver(name: "create_new_player")
  createNewRanking(active: Boolean!, rankingname : String!, rankingdesc : String, rankingowneraddr : String!): Ranking! @resolver(name: "create_new_ranking")
  createNewUser(active: Boolean!, username : String!, password : String!, ethaddress: String!, description: String, email: String, mobile: String): String! @resolver(name: "create_new_user")
  createNewUserJoinedRanking(active: Boolean!, rankingid : String!, rankingname : String!, useraddr: String!, rankingowneraddr : String!): UserJoinedRanking! @resolver(name: "create_new_userjoinedranking")
}

type Query {
  allUserNames: [String!]! @resolver(name: "all_user_names")
  allPlayerAddresses: [String!]! @resolver(name: "all_player_addresses")
  allPlayerRanks: [Int!]! @resolver(name: "all_player_ranks")
  allPlayerChallengerAddresses: [String!]! @resolver(name: "all_player_challenger_addresses")
  allPlayers: [Player] @resolver(name: "all_players")
  allRankings: [Ranking] @resolver(name: "all_rankings")
  allUserJoinedRanking: [UserJoinedRanking] @resolver(name: "all_userjoinedranking")
  allUsers: [User] @resolver(name: "all_users")
  usernameFromEthaddress(ethaddress: String!): [String!]! @resolver(name: "usernameFromEthaddress")
  loginUser(username: String!, password: String!): [String!]! @resolver(name: "login_user")
  findRankingById (rankingid: Int!): [Ranking!]! @resolver(name: "find_ranking_by_id")
}

the function FQL:

{
  name: "login_user",
  role: Role("login"),
  body: Query(
    Lambda(
      ["username", "password"],
      Let(
        {
          match: Match(Index("unique_User_username"), Var("username")),
          user: If(Exists(Var("match")), Get(Var("match")), "false"),
          login: Login(Select("ref", Var("user")), {
            password: Var("password")
          })
        },
        Select("secret", Var("login"))
      )
    )
  )
}

Role login:

{
  ref: Role("login"),
  ts: 1600844588120000,
  name: "login",
  privileges: [
    {
      resource: Collection("User"),
      actions: {
        read: true,
        write: false,
        create: false,
        delete: false,
        history_read: false,
        history_write: false,
        unrestricted_read: false
      }
    },
    {
      resource: Index("unique_User_username"),
      actions: {
        unrestricted_read: false,
        read: true
      }
    }
  ],
  membership: []
}

thanks …

Hi @FreeRoss,

would you provide the create_new_user function as well?

Thanks,

Luigi

Yes. Here:

{
  name: "create_new_user",
  role: Role("register"),
  body: Query(
    Lambda(
      [
        "active",
        "username",
        "password",
        "ethaddress",
        "description",
        "email",
        "mobile"
      ],
      Let(
        {
          user: Create(Collection("User"), {
            credentials: { password: Var("password") },
            data: {
              active: Var("active"),
              username: Var("username"),
              ethaddress: Var("ethaddress"),
              description: Var("description"),
              email: Var("email"),
              mobile: Var("mobile"),
              member_since: ToMillis(Now())
            }
          }),
          login: Login(Select("ref", Var("user")), {
            password: Var("password")
          })
        },
        Select("secret", Var("login"))
      )
    )
  )
}

Thanks …

I do not think you need to use paginated: true. You only want to use paginated: true if your FQL resolver function is returning a page (Fauna specific). That way fauna can correctly interpret your graphql schema types and during your schema upload they will actually perform a transformation on your type definitions in order to integrate it into fauna so you do not have to worry about it. This way you can define your result types as you normally would with any graphql framework and let fauna handle the fauna specific pagination types for you.

In your case I think the issue is that your FQL function is returning a String and in your graphql type definitions you’re telling your loginUser Query to expect an array of strings and the array is required. I think it should look like this.

loginUser(username: String!, password: String!): String! @resolver(name: "login_user")

Notice the change I made from [String!]! to String! on the return value. This way you can leave your FQL function returning the token as a String. The below should return your string as expected no pagination needed.

query {
  loginUser(username: "Test 1", password: "hello" )
}

If you want to have a sub selection in your Query you can do that as well! In my schema I created the below:

type LoginResult @embedded {
  token: String!
}

I use @embedded to let fauna know that this type def is not related to a collection. Then my login function I use this type instead of String!

loginUser(input: LoginUserInput): LoginResult! @resolver(name: "login_user")

Then the only change you make your FQL function is the last line.
From Select("secret", Var("login"))
To { token: Select("secret", Var("login")) }

Now your Query would look like this:

query {
  loginUser(username: "Test 1", password: "hello" )
  {
    token
  }
}

The only reason I do this is so that if one day in the future I want to return more than just a token on login I can expand my type defs and include a User type and perhaps get the user’s roles as soon as they login. It is not necessary but I wanted to show you how changing the return part of the FQL would affect the Graphql schema and query. All I did was return an object containing the token string vs only the token string itself. I hope this helps!!

1 Like

@yellowspaceboots
Thanks very much for the detailed answer, which is certainly helpful.
Frustratingly, my schema now won’t update (it did yesterday, from terminal within VSCode, at least). I cleared the browser cache, but that hasn’t resolved it.
I’m therefore unable to implement the small change to the schema you recommended above, which will, I expect, fix the immediate issue.
Assuming it does, thanks again, and your other points are noted.

@yellowspaceboots. I was asked by Jay to create a new db to test your solution. I did and it works. Thank you. This issue is solved and it is now a separate schema upload issue which we are resolving in another thread:
Instance data is not valid