Peter Jausovec

@pjausovec

Building URL shortener using React, Apollo and GraphQL — Part III

Photo by Chris Kristiansen (https://unsplash.com/@chriskristiansen)

Table of Contents

Part III: Creating serverless function for hashing

In this post we are going to take the hashing function we implemented in the previous post and move it to the Graphcool functions.

Functions need to be defined in the Graphcool service definition file (graphcool.yml). Graphcool supports the following function types that can be invoked either as webhooks or as managed functions:

Before and after operations (operationBefore/operationAfter)

For this to work, you need to specify the operation on a model for which the function should be invoked. For example: Link.update, Link.delete or Link.create. An example for when this type could be used is if we wanted to implement a feature that prevents certain users from creating more than X number of links. We could use the operationBefore on Link.create and run a function that checks how many links the user already created and either throw an error or allow the creation to happen.

Subscriptions

Subscription requires a subscription query that determines when the function should be triggered (e.g. when an object is created, updated or deleted). The backing function is then executed after the mutation happens. An example of this could be if we wanted to send a welcome email each time a new user signs-up.

Resolvers

Resolvers are the most powerful types as they allow you to come up with a new mutation and/or query definition. We will use resolvers in one of the upcoming post where we will create a mutation for signing up and logging in users as well as a query that returns a logged in user.

To be honest, we could probably use all of the options above to implement our hashing function. In short, here’s how we’d do it:

Option 1: Using operationBefore/operationAfter

We could use either of these two options. We would need to modify the CreateLinkMutation in CreateShortLink.js to remove the $hash variable as well as make the hash field optional in the schema. Next, we’d move the createHash function to the backend to either update the created link with a hash (if we use operationAfter) or create a hash and return it for the mutation to complete if we use operationBefore.

Option 2: Using a subscription

Just like we the above option, we need to remove the $hash variable from CreateLinkMutation and write a subscription query that fires when new Link is created — we already have that query, so we could update it like this:

subscription NewLinkCreatedSubscription {
Link(filter: { mutation_in: [CREATED] })
node {
id
}
}
}

In the handler function, we’d get the data returned from the subscription (id), next we’d get the count of all links, create a hash and finally update the existing Link with this mutation:

mutation UpdateLinkWithHash($id: String!, $hash: String!) {
updateLink(id: $id, hash: $hash) {
id
}
}

Option 3: Using a resolver

With a resolver, we would extend our existing API with a new mutation called createHashMutation . The function that would be executed when this mutation is called would go through similar things as if we’d use a subscription. Function would get the number of created links, generate a hash and then return that generated hash. Then, we could call our existing CreateLinkMutation and pass in the hash we from the createHashMutation .

Since we will use a resolver for authenticating users later, let’s use a subscription to implement this — option 2 it is!

Move the hash function to subscription

Follow the steps below to create a subscription and move the hashing function to the backend.

  1. Create the graphcool/src folder in your project root
  2. Add createShortLink.graphql file with the following subscription that fires each time a link is created and returns its id:
subscription {
Link(filter: { mutation_in: [CREATED] }) {
node {
id
}
}
}

3. Add createShortLink.js file that fires off each time a new link is created.

4. Install the dependencies for subscription function by running the following command from the graphcool folder where package.json file is:

$ npm install graphcool-lib --save

5. Update the graphcool.yml to reference the graphql and js file we created:

functions:
createShortLink:
type: subscription
query: src/createShortLink.graphql
handler:
code: src/createShortLink.js

6. Deploy the changes and create the subscription:

$ graphcool deploy
...
Subscription Functions
createShortLink
+ A new subscription with the name `createShortLink` is created.

A couple of small things before we try out the subscription:

  1. Remove createHash function, $hash variable from the mutation and GET_LINK_COUNT_QUERY from CreateShortLink.js. Below is the updated file:

2. Make the hash field in types.graphql optional, by removing the exclamation mark:

type Link @model {
id: ID! @isUnique
hash: String
url: String!
description: String
}

Run the graphcool deploy again to update the type and we are ready to test this out!

Fire up the web site (yarn start) if you don’t have it running already and try to create a new link — everything should work exactly like before, the only difference is that the hashing function is now being invoked as part of a subscription on the Link. To really make sure that this works, you can run graphcool logs to get the invocation logs from your function(s). It looks like this:

Testing the function

If there’s an error, you will also get error details in here. Second option for looking at the logs and function invocations is to go to the http://graph.cool , click on the Functions and then on the createShortLink function to get all the logs.

Function overview on Graph.cool

Another helpful command for testing the functions is the graphcool invoke-local command from the CLI. Instead of going through our web site to create new links, we can directly send a JSON payload to the function like this:

$ graphcool invoke-local --function createShortLink --json event.json

Where event.json can look like this:

{
"data": {
"Link": {
"node": {
"id": "LINK_ID"
}
}
}
}

This way you can test your function for bunch of scenarios that might be hard to test through the web site — e.g. invalid payloads, non-existent link IDs, etc.

Coming up

In the next post of the series we will work on getting some short URL stats — number of clicks. In order to do that, we will have to come up with a handler for links. For example: if we generate hash “ABC123”, we will need to write some code that’s going to execute when user visits “http://localhost:3000/ABC123” and translate that hash to an actual link and redirect the user to it. Once we have the handler we can start collecting click stats.

Thanks for Reading!

Any feedback on these series is more than welcome! You can also follow me on Twitter and GitHub. If you liked this and want to get notified when other parts are ready, you should subscribe to my newsletter!

More by Peter Jausovec

Topics of interest

More Related Stories