Make your links human-friendly
Published: 2022-07-06 11:22:19

The reality of long URLs is supposed to be light years behind us. However, I still encounter them on almost every website. It is hard to figure out the best URL-shortener code that would also track how many times the link was opened. 

Using Redwood JS Framework which combines some of the most popular and advanced frameworks, I am going to create such a service.

Initialise the project by following the official Get Started tutorial:
[](https://redwoodjs.com/docs/quick-start)

Initialize git

```
git init
```

The first step is to add a new data table to `api/db/schema.prisma`

```
datasource db {
  provider = "sqlite"
  url      = env("DATABASE_URL")
}

generator client {
  provider      = "prisma-client-js"
  binaryTargets = "native"
}

model WebLink {
  id           Int    @id @default(autoincrement())
  shortId      String @unique
  url          String
  viewedAmount Int    @default(0)
}
```

Next, the Prisma framework can help us create a SQL migration for the sqlite. I recommend using postgresql in production.

`yarn rw prisma migrate dev`

Redwood did a great job with the scaffold feature that generates a CRUD (Create, Retrieve, Update, Delete) code for React by running just one command.

`yarn rw g scaffold web-link`

Run the development mode
`yarn redwood dev`

You will see that we have not finished the home page yet; however, four pages have already been generated:
`/web-links/new`
`/web-links/{id:Int}/edit`
`/web-links/{id:Int}`
`/web-links`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8uoh8aejqcx4wavnqc74.png)

Let's open `http://localhost:8910/web-links` and create a new data record.

Now we want to add a new query to the Graphql API:
`api/src/graphql/webLinks.sdl.js`

Add `webLinkByShortId(shortId: String!): WebLink @requireAuth` to the SDL schema

```
export const schema = gql`
  type WebLink {
    id: Int!
    shortId: String!
    url: String!
    viewedAmount: Int!
  }

  type Query {
    webLinks: [WebLink!]! @requireAuth
    webLink(id: Int!): WebLink @requireAuth
+   webLinkByShortId(shortId: String!): WebLink @requireAuth
  }

  input CreateWebLinkInput {
    shortId: String!
    url: String!
    viewedAmount: Int!
  }

  input UpdateWebLinkInput {
    shortId: String
    url: String
    viewedAmount: Int
  }

  type Mutation {
    createWebLink(input: CreateWebLinkInput!): WebLink! @requireAuth
    updateWebLink(id: Int!, input: UpdateWebLinkInput!): WebLink! @requireAuth
    deleteWebLink(id: Int!): WebLink! @requireAuth
  }
```

The next step is creating a function that will resolve this for us:
open `api/src/services/webLinks/webLinks.js`

```
import { db } from 'src/lib/db'

export const webLinks = () => {
  return db.webLink.findMany()
}

export const webLink = ({ id }) => {
  return db.webLink.findUnique({
    where: { id },
  })
}

export const createWebLink = ({ input }) => {
  return db.webLink.create({
    data: input,
  })
}

export const updateWebLink = ({ id, input }) => {
  return db.webLink.update({
    data: input,
    where: { id },
  })
}

export const deleteWebLink = ({ id }) => {
  return db.webLink.delete({
    where: { id },
  })
}

+ export const webLinkByShortId = async ({ shortId }) => {
+   await db.webLink.update({
+     where: { shortId },
+     data: { viewedAmount: { increment: 1 } },
+   })
+   return db.webLink.findUnique({ where: { shortId } })
+ }
```
I used the Redwood generator to generate a page.
`yarn redwood g page Redirect`

Update `web/src/Routes.js`. Make sure that the new route is the last on the list since it uses dynamic params.

```
  - <Route path="/redirect" page={RedirectPage} name="redirect" />
  + <Route path="/{shortId}" page={RedirectPage} name="redirect" />
```

Now we want to generate a cell. This is the way Redwood recommends working with data:
`yarn redwood g cell redirect`

Modify `web/src/components/RedirectCell/RedirectCell.js`

```
- export const QUERY = gql`
-  query FindRedirectQuery($id: Int!) {
-    redirect: redirect(id: $id) {
-      id
-    }
-  }
- `

+ export const QUERY = gql`
+   query FindWebLink($shortId: String!) {
+     link: webLinkByShortId(shortId: $shortId) {
+       id
+       url
+     }
+   }
+ `

- export const Success = ({ redirect }) => {
-   return <div>{JSON.stringify(redirect)}</div>
- }


+ export const Success = ({ link }) => {
+   React.useEffect(() => {
+     if (!link) return
+
+     window.location = link.url
+   }, [link])
+
+   return 'redirecting...'
+ }


```

As a result, if you click on `[/kcuobL](http://localhost:8910/kcuobL)`, the link will take you to `https://google.com`.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aoa89dxgx8dh6n6uvhjz.jpg)

Voila. There is more than just a URL shortener in your hands. It is a marketing tool that can help your company's specialists to organise a huge part of their work online.