Mutate document by external ID with GraphQL

I’m new to FaunaDB and GraphQL. I followed this netlify.com blog article which includes creating users in Netlify Identity, and then storing some user info in FaunaDB, with an index to make Users findable via Netlify’s Identity ID. It went great:

So with the example running in the browser, a user is logged in via Netlify Identity, and then Netlify functions manage the actual interactions with FaunaDB. My understanding is that when using Netlify functions with Netlify Identity, the Netlify function is aware of which user is communicating with it via a JWT in a bearer token coming from the browser, which contains the Netlify ID.

I’d now like to update a user in Faunadb via GraphQL via a Netlify function (which the above guide does not cover). Uploading the schema to Faunadb automatically creates a mutation that lets me update a user via its Ref ID, but in the Netlify function I don’t have a ref ID, I have a Netlify Identity ID. I’m trying to figure out the best way to be able to update the user given the Netlify ID. Some possibilities I’ve thought of include:

  1. Create the additional custom mutations myself in the schema – which I’d like to avoid if possible
  2. Setting the User’s Ref ID to be the Netlify ID, which seems to be possible using FQL but I can’t figure out if there’s a way to do it via GraphQL
  3. Storing Faunadb’s Ref ID number as custom data in Netlify Identity when the User is created, which would then also be available to the Netlify function
  4. Making a separate GraphQL call first to retrieve the Ref ID, which is not ideal because then there are multiple calls when it seems like there should just be one

So none of these possible solutions seem great, but I guess #3 would be the simplest. But, is there something else you’d recommend, or something I’m missing?

Thanks!

And re: option #1, adding my own mutations: I don’t mind adding them per se, it’s just that then I have to add a hierarchy of input types that faunadb’s schema receiver was going to generate anyway, and having to add so much extra redundant stuff for what seems like one tiny change, makes me think I’m going in the wrong direction.

Could faunadb’s schema transformer be altered to see something like:

type User {
    netlify_id: ID! @unique
    score: Int!
    lives: Int!
}

and take the hint that ID! @unique means we’ll want to be able to update a user using

type Mutation {
    UpdateUserByNetlifyID(netlify_id: ID!, data: UserInput!): User
}

in addition to what it’s setting up automatically:

type Mutation {
    updateUser(id: ID!, data: UserInput!): User
}

?

Best,
Justin

1 Like

@this_justin Welcome to Fauna Forums!!

To summarize, you have Netlify ID and want to use it in all the mutations instead of Fauna Ref ID. The default mutations which are created with the schema import does not help you with that. Instead, you will have to implement a custom directive @resolvers.

This resolver would create a FQL User Defined Function (UDF) and should accept Netlify ID as input parameter and use an Index User_By_NetlifyID which should be created behind the scenes.

This is also another option where you would use Fauna Ref ID for GraphQL mutations.

Hope this helps.

Hi Jay,

Thanks for pointing me in the right direction! I will check out resolvers.

Best,
Justin

@this_justin here are some good reads with examples to explain @resolver directive.

And a good series of blogs to explain and implement UDFs in FQL

Finally, apologize for the delay in response and do continue to post your questions here and we are happy to answer them for you.

Just to answer a few other questions, you are correct that this is not possible from GraphQL.

If possible this would probably be ideal but I’m not familiar enough with Netlify functions to tell you more.

I would also look into resolvers and update that user via an FQL User defined function by defining a resolver. That depends of course how hard you want to stick to pure GraphQL.

I got here trying to accomplish something very similar. I went for the approach #1 you suggested. For anyone else that lands here with the same problem, this is how I solved it:

My schema

type Mutation {
  updateUserByExternalId(externalId: ID!, data: UserInput!): User @resolver(name: "update_user_by_external_id")
}

My resolver

Update(Function("update_user_by_external_id"), {
  "body": Query(
    Lambda(["id", "data"],
      Update(
        Select(
          ["ref"],
          Get(
            Match(
              Index("externalId"),
              Var("id")
            )
          )
        ),
        {
          data: Var("data")
        }
      )
    )
  )
})

My query

mutation($externalId: ID!, $firstName: String, $lastName: String) {
  updateUserByExternalId(externalId: $externalId, data:{firstName: $firstName, lastName: $lastName}) {
    externalId
    firstName
    lastName
    email
  }
}

I am new to FaundaDb and not sure if it follows best practice. Any feedback would be appreciated.

2 Likes