UDFs meets node, shortage of how-to's

Hello,

Im seeing a lot of high quality documentation on how to use the Shell, Functions, and GraphQL from the FaunaDB Dashboard. Love it.

I see a distinct lack of documentation for carrying this knowledge over into Node.

An amazing example that Ive learned a ton from, but have no idea how to translate into Node: Instant GraphQL Backend with Fine-grained Security Using FaunaDB | CSS-Tricks

Search for this part:

Update(Function(“login_user”), {

Ok, I want to call that from the backend (running node). How would I go about that?

The simple example here does not work, I am missing some theory:

My UDF looks like:

    Query(
      Lambda(
        ["input"],
        Create(Collection("Users"), {
          data: { username: Select("username", Var("input")) },
          credentials: { password: Select("password", Var("input")) }
        })
      )
    )

My attempt to call it looks like this:

var r = await q.Call('createUser', ['lolsauce', 'abc123'] )

Ive tried passing in:

  • an object

  • comma separated list

  • an array within an object

  • data:{username:‘abc’, password:‘abc123’}

and a whole lot more.

Im pretty sure Im not passing the arguments right, but also thinking there may be something up with createUser. If you look at that first link, he creates a UDF with the name ‘create_user’

    type Mutation {
      createUser(input: CreateUserInput): User! @resolver(name: "create_user")
      loginUser(input: LoginUserInput): String! @resolver(name: "login_user")
    }

but then later makes a function named createUser.

So my questions are:

  • Which one do you call from node?

  • What args do you pass?

  • How do you pass them?

  • Is there a section of documentation Im missing that ties FQL to Node code?

Thank you,

-Jason

Hey Jason,

when you say ‘doesnt work’. Could you provide the error that is returned?

That is explained in the drivers.

Function and Update are FQL functions exposed from the driver. Take a look at the driver docs to see how to expose the functions.
Either

var faunadb = require('faunadb'), q = faunadb.query

And then use q.Function / q.Update
Or expose the functions as follows:

const { Function, Update } = q

**However. ** For Map/Update that’s not a good idea since Function is a javascript keyword. Therefore, use q.Function or q.Map for those functions.

The error:

raw: { call: 'create_user', arguments: Expr { raw: [Object] } } }

The js code:

var r = await q.Call('create_user', {username: 'jason', password:"abc123"} )

The UDF:

Query(
  Lambda(
    ["input"],
    Create(Collection("User"), {
      data: { username: Select("username", Var("input")) },
      credentials: { password: Select("password", Var("input")) }
    })
  )
)

edit: none of these work

var r = await client.query(
      //q.Call('create_user', { data: ['jason',"abc123"] } )
      //q.Call('create_user', {data: [{ username: 'jason', password: "abc123"}]} )
      //q.Call('create_user', {data: { username: 'jason', password: "abc123"}} )
      //q.Call('create_user', {input: { username: 'jason', password: "abc123"}} )
      //q.Call('create_user', 'jason', "abc1231" )
      //q.Call('create_user', ['jason',"abc1232"] )
      //q.Call('create_user', [{username: 'jason', password:"abc1233"}] )
      //q.Call('create_user', {username: 'jason', password:"abc1234"} )
      //q.Call('create_user', ['lolsauce', 'abc1235'] )
      //q.Call(q.Function('create_user', q.Database('minotaur')), [{username:`testun33`, password:'testpw'}])
    )

edit2: there does not seem to be any way to call FQL functions / UDFs from the backend. No matter what you pass, its like the UDF just derps out. If I cant find an answer in an hour or 2 Im going to have to look at other solutions.

There certainly is, though I am not doubting you are having issues. I can try to help.

Can you share the CreateUserInput and LoginUserInput input types?

if it looks like

input CreateUserInput {
  username: String
  password: String
}

Then this should work

import { Client, query as q } from 'faunadb'

const client = new Client({
  secret: MYSECRET // assuming this has `create` privileges on the User collection
})

client.query(q.Call('create_user', { username: 'jason', password: 'abc1234' } ))
  .then(res => console.log(res)) // or do whatever with the response

If you are still getting errors, stringify the WHOLE response.

Also, if you want to inspect what the value of input var is then you can use Abort to inspect it. Update the UDF to something like this:

Query(
  Lambda(
    ['input'],
    Abort(Format('%@', Var('input'))
  )
)

Then call and see what you get.