Photo by Kevin Ku
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:
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:
npm install -g create-react-app
)npm install -g graphcool
to install the CLI)Once you have everything, we can get started with our 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
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:
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:
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.
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
.
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.
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.
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.
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!