GraphcoolDocs
FAQ

Validating and Transforming Mutation Input

Last updated a day ago Edit this page

Using Hook Functions for data transformation & validation

In this article, you'll learn how to use serverless functions to validate an email address and make sure it gets saved in the database in lowercase letters.

#Overview: Serverless Functions

Serverless Functions, also referred to as Functions as a Service (FaaS), enable developers to write and deploy independent pieces of functionality without having to deal with setting up and configuring the server environment.

In that sense, they are similar to microservices, where each function represents one microservice, but again, without the developer having to deal with configuration or deployment overhead. Instead, they can take advantage of the server infrastructures of FaaS providers such as AWS Lambda, Google Cloud Functions or StdLib.

#Graphcool Functions

When using Graphcool, you can use serverless functions to extend the functionality of your backend. A few common use cases are:

  • transforming data, e.g. removing the spaces from a credit card number
  • validating data, e.g. ensuring an email address is correct
  • call third-party services like Stripe or Mailgun

These are precisely the features that you can implement with serverless functions!

You generally have the choice between three different kinds of functions that serve slightly different purposes:

  • Subscription Functions: Execute a serverless function after a mutation happened in the backend
  • Hook Functions: Allows for transformation and validation of mutation input and response payload at various stage
  • Resolver Functions: Extend your GraphQL API with additional queries and mutations that cover any kind of functionality

The use case of sending a validating and transforming an email address is best implemented with hooks, so that's what we'll discuss in the remainder of this article.

#Getting Started with Hook Functions

A hook function consists of three elements that are specified in the graphcool.yml file:

  1. The operation the hook should be called for
  2. Whether the hook should be called before or after the operation
  3. The actual function handler that will be executed

In the following, we'll walk through each step in detail with the goal of using a hook to validate and transform the email address of a new user.

#0. Preparation

1

We're going to use the Graphcool CLI to initialize our service.

# Install the Graphcool CLI
npm install -g graphcool

# Create service
graphcool init

Next, we'll add a new Customer model type to our service definition.

2
1
2
3
4
5
type Customer @model {
  id: ID! @isUnique
  name: String!
  email: String!
}

#1. Setup the Hook Function

Now we're adding the hook function to the service definition.

3
1
2
3
4
5
6
functions:
  validateEmail:
    type: operationBefore
    operation: Customer.create
    handler:
      code: src/validateEmail.ts

As mentioned above, this new hook function validateEmail consists of three parts:

  • the operationBefore function type signifies that this is a hook function called before the operation finishes
  • the Customer.create operation signifies that this hook will be called when a customer is about to be created
  • the code handler is used for managed Graphcool functions in contrast to webhook handlers

#2. Write the Code

For hooks, it's important to note that we have an input and an output. The input is determined by the operation that we chose, so in our case it's a JSON object that follows the structure of the Customer:

1
2
3
4
5
type CustomerInput {
  id: ID!
  name: String!
  email: String!
}

The output has to be another JSON object and has either one of two fields:

  • data: When returning the data field we're communicating that the validation and transformation were successful and the data can "proceed".
  • error: If the validation fails, we can return an error in the JSON object along with a string that represents the error message.

With that knowledge, let's go and implement our function.

4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 1. Import npm modules
import * as validator from 'validator'
import { FunctionEvent } from 'graphcool-lib'

// 2. Define type of event data
interface EventData {
  id: string
  name: string
  email: string
}

export default async (event: FunctionEvent<EventData>) => {
  // 3. Transform Email to lowercase
  event.data.email = event.data.email.toLowerCase()

  // 4. Validate Email
  if (!validator.isEmail(event.data.email)) {
    return { error: `${event.data.email} is not a valid email!` }
  }

  // 5. Return transformed data
  return { data: event.data }
}

Let's try to understand the different parts of that function:

  1. We're importing a Javascript module that we'll use to validate the email address. Additionally, we're importing FunctionEvent from graphcool-lib for its type information.
  2. Here, we're defining the type of the input data. It's structured as mentioned above.
  3. Now we're transforming the email address to be all lowercase.
  4. Next we validate the email address and return a custom error if the validation fails.
  5. If we got to this point, we simply return the data that now contains the lowercase email address.

Next, we'll make sure the required modules are installed.

5
npm install --save validator graphcool-lib

This adds the dependencies to the package.json file.

#3. Deployment & Testing

Once you're done writing the function, you can deploy the changes to a new service:

graphcool deploy # select any shared-cluster

Afterwards, let's open the GraphQL Playground:

graphcool playground

We can use the Playground to send an actual mutation to your GraphQL API. A sample mutation could look as follows:

1
2
3
4
5
6
7
8
mutation {
  createCustomer(
    email: "NILAN@graph.cool"
    name: "Nilan"
  ) {
    email
  }
}

#Conclusion

In this article you learned how to setup a hook function using the Graphcool CLI. The function is called every time right before a new customer is created and ensures that the email address that was provided is actually valid and further transforms it to only have lowercase characters.

Was this page helpful?