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

Written by pjausovec | Published 2017/12/28
Tech Story Tags: javascript | react | graphql | graphcool | tutorial

TLDRvia the TL;DR App

Photo by Kevin Ku

Table of Contents

Part I: Setup and displaying short URLs using GraphQL

In this series of post I’ll explain how to build a simple URL shortener using React, Apollo and GraphQL (Graphcool). GitHub repo the project is located here.

The idea behind the URL shortener is simple — the shortener takes a long URL such as www.example.com/thisisalongurl and shortens it to http://goo.gl/ABC. When shortened URL is accessed, the service expands it to the original URL and redirects you there. The algorithm I’ll use to calculate the hash (short URL) is explained here.

Here are some of the bigger areas and features we will implement:

  • Setup and displaying short URLs using GraphQL (this post)
  • Creating short URLs
  • Short URL stats (number of clicks, etc.)
  • Expiring the URLs (e.g. no clicks in X weeks/months/years)
  • User authentication

Technologies used

We are going to use React and Apollo on the frontend and Graphcool on the backend.

Prerequisites

Here are the prerequisites and tools I’ll be using to work on this project:

Once you have everything, we can get started with our project!

Creating the project

I’ll name this project Shortly as I am not too good with naming things. It doesn’t matter what you name it, I just want to make sure that if you see that name anywhere throughout the tutorial, you know what I am referring to.

Open your terminal in your projects folder and start by running create-react-app to scaffold a new React website:

$ create-react-app shortly

I am not going to worry too much about styling, but in case I decide to add some CSS later, I’ll probably use the Tachyons library. You can add the link tag to the /public/index.html file:

<link rel="stylesheet" href="https://unpkg.com/tachyons/css/tachyons.min.css">

To make sure all went well, go inside the folder an run yarn start — if all is good, you should see the default React website open in your default browser.

Default React website

Setting up GraphQL

I am using the Graphcool CLI to set up and initialize the GraphQL project. The initialization command creates a bunch of files, so let’s create a subfolder in our root project folder first. Make sure you run graphcool login before running the init command.

$ cd shortly$ mkdir graphcool && cd graphcool$ graphcool init

Creating a new Graphcool service in .... ✔

Written files:├─ types.graphql├─ src│ ├─ hello.js│ └─ hello.graphql├─ graphcool.yml└─ package.json...

The Graphcool CLI creates the following files:

  • graphcool.yml — configuration file for the Graphcool service that references your types, serverless functions and defines permissions
  • types.graphql — defines the data model for your Graphcool service
  • src folder — holds code for your serverless functions

Let’s delete the src folder and remove the references to any file in that folder from the graphcool.yml file, so the file look like this (I removed the comments as well):

types: ./types.graphqlpermissions:

  • operation: "*"

Similarly, remove the User type from the types.graphql file and add the Link type we will use to store the short links. We are going to stawrt with a very simple model and add more to it later.

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

The definition above is pretty self-explanatory — for each link we have a unique ID, a string hash, a string URL and an optional description. If you’re wondering about what the exclamation mark on the fields those, well it makes that field required. You can read more about modelling data in Graphcool here.

Finally, we need to create the actual service and push the changes we made by running the deploy command. You’d run the same command each time you make a change to your types or functions:

$ graphcool deploy

If you’re creating a new project, you’ll get prompted to pick a cluster where you want to deploy the service, target name (prod) and your service name (Shortly).

A couple of seconds later, the CLI will give you an overview of what was added/deployed, as well as the GraphQL endpoints. We will use the Simple API endpoint in our React website to connect to the GraphQL.

Setting up Apollo

In this section we are going to install Apollo packages to the React website and use it to connect to the GraphQL endpoint. First, we need to install Apollo packages we’ll be using:

$ yarn add apollo-client-preset react-apollo graphql-tag graphql

Once that’s installed we can configure the Apollo client to connect to our GraphQL endpoint and use a higher-order component to wrap the App component with the ApolloProvider.

  1. Add import statements to index.js:

import { ApolloProvider } from 'react-apollo';import { ApolloClient } from 'apollo-client';import { HttpLink } from 'apollo-link-http';import { InMemoryCache } from 'apollo-cache-inmemory'

2. Create the ApolloClient instance — replace the [SERVICE_ID] value with the one you got when you deployed the Graphcool service, or just run graphcool info to show that information again.

const client = new ApolloClient({link: new HttpLink('https://api.graph.cool/simple/v1/[SERVICE_ID]'),cache: new InMemoryCache(),});

3. Create a higher-order component to wrap the App component:

const withApolloProvider = Comp => (<ApolloProvider client={client}>{Comp}</ApolloProvider>);

ReactDOM.render(withApolloProvider(<App />),document.getElementById('root'));

The higher-order component withApolloProvider is a function that takes a component, wraps it inside the ApolloProvider and returns a new component.

Building React components

Let’s add the prop-types library, so we get runtime type checking to React props. It’s a great way to ensure you’re passing correct props to your components.

$ yarn add prop-types

We are going to start with a Link and LinkList components for displaying a hardcoded (for now) array of links.

  1. Create the src/components folder and a Link.js file. This file will represent a single link.

We are passing a single link prop to the component and displaying it inside a div.

2. Create a LinkList.js —this component will be used to display a list of links (at this step we use a hardcoded array of links and once we switch over to GraphQL, we will remove it)

3. Finally, let’s update App.js and render the LinkList component we created:

Open the browser, navigate to http://localhost:3000 and confirm you can see the hardcoded links.

Displaying links from an array

Reading links from GraphQL

In order to get the data from GraphQL we need to write a GraphQL query to fetch all links. This is the query we will be using:

const ALL_LINKS_QUERY = gql`query AllLinksQuery {allLinks {idurldescriptionhash}}`;

The gql is a helper function from react-apollo and we use it to define the GraphQL query. The allLinks query was automatically generated by Graphcool and we can use it to fetch multiple nodes. The query name (AllLinksQuery) is our name for the query and the values inside the allLinks are the fields we want GraphQL to return.

Another query that is automatically generated for our type is aLink query. With it, we can query for a single node by id.

For example:

query SingleLink {Link (id: "someid") {urldescription}}

You can read more about the Query API here.

Now that we have our ALL_LINKS_QUERY, we can use the graphql container to wrap the LinkList component. When query finishes executing, the results will be in the component’s props object. Here’s the updated code in LinkList.js :

Let’s explain what’s happening with the above code starting at the top.

Lines 4–16We imported gql and graphql and defined the ALL_LINKS_QUERY.

Lines 20–31We are using the loading and error properties on the query name prop to check if the data was fetch or if there was an error fetching the data. In those cases we either return a simple div with “Loading” or “Error” text (these should probably be components, so you can re-use them throughout your site). If query is done loading and there’s no errors we get the data (allLinks) and as a final check we return a div that’s say “No links…” if there aren’t any links returned.

Line 41Using graphql container, we are combining the component and the query. We are also specifying the name for the query (allLinksQuery) that ends up being the prop name that Apollo adds to our component.

At this point, you can navigate to http://localhost:3000 to get the No links message. Let’s use the Graphcool’s playground to add a couple of links. From the command line, run graphcool playground to open the playground. Alternatively, you can go to http://graph.cool and open the playground UI from there.

To create a new Link we are going to write GraphQL mutation. Copy the mutation below to the Graphcool playground:

mutation CreateLinkMutation {createLink(description:"First link from GraphQL",url:"http://example.com",hash:"somehash") {id}}

As with the queries, Graphcool create a createLink mutation for us — we provide the values for required fields and return an id of the created Link. Click the play button on the playground to execute the query and the mutation result should be similar to this:

{"data": {"createLink": {"id": "cjbr3vlnqhg1a0152fx0qpdel"}

Notice how it contains the value of the id field — we could also return any other field value by simply adding a field name to the mutation.

Now if you go back to the React app and refresh, you should see the Loading message first and then finally after query loads, you will see the link you created.

Link from the GraphQL

This is end of Part I. In the upcoming post, I will add a React component for creating new links using GraphQL mutations, implement a simple hash algorithm as a Graphcool serverless function.

Thanks for Reading!

You can 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!


Published by HackerNoon on 2017/12/28