In the past I had my little hastebin clone with ExpressJS and MongoDB on my personal web server.

I had since then moved to Vercel because my website is mostly static and I didn’t need a full web server on a VPS.

I missed my hastebin clone so I wanted to recreate it, luckily Vercel supports serverless functions which allows us to do some server side stuff.

Demo

Here’s a demo URL to show you the final product: ravener.vercel.app/paste/demo.cs

How it works

A serverless function sits on /api/paste which handles both GET and POST requests.

If it’s a GET request it looks for the querystring id and looks it up in the database and then syntax highlights it and sends the results.

If it’s a POST request it parses a JSON body and creates an entry in the database.

I’ll in more details about each component below.

The Language

I wrote this in Golang which Vercel’s runtimes supports.

For the syntax highlighter I used chroma it was just perfect.

Chroma could generate clean HTML that I liked over Highlight.js so that’s mainly why I selected Go for this task.

The syntax highlighting is done based on an extension in the URL. e.g in the demo above it had demo.cs the .cs gets picked up to decide which highlighter to use, in this case C#

The Database

For the database, I previously used MongoDB and I was thinking of using it again but decided to go with PostgreSQL instead, through ElephantSQL which is a cloud hosted PostgreSQL.

The free tier offers 20 MB and you can sign up and get started in just a minute. 20 MB may sound low but we are just storing basic text content and most of them can be easily wiped in the future if it ever comes close to full.

Their website is also pretty clean and I find it more pleasant to navigate compared to the MongoDB Atlas website.

MongoDB however offers 500 MB for their free tier so that’s one advantage but I just couldn’t be bothered, especially since I never used MongoDB with Go before.

Another point is the IDs of the pastes. When posting a paste you can choose to assign a custom ID or omit it to generate an ID based on time. I do this by encoding the current time into Base 36 which yields results like l0ow2mf7 and it’s good enough for our purposes.

When the ID is automatically generated I also mark the documents with another field called auto_id in the database, the idea is that the ones without a custom ID are going to be most of the time useless temporary snippets so this will allow me to easily filter and delete those entries when I need to. While the ones with a custom ID might potentially be linked to for longer periods of time.

Authentication

I wanted to limit this service for myself only, the whole idea was that I can share snippets of code under my own website so that I look cool :P

So obviously I had to restrict the POST requests to check for an Authorization header for the password and throw a 403 if it’s not correct.

Vercel Rewrites

Another step is the URL looks bad, to access a paste you have to type /api/paste?id=something

And from such an endpoint you wouldn’t expect a regular HTML page, do you?

Luckily vercel allows us to rewrite some URLs so I just add a vercel.json in the root of the project and add

{
  "rewrites": [
    { "source": "/paste/:id", "destination": "/api/paste" }
  ]
}

And that’s all it takes, Vercel automatically converts the :id parts into querystring values for the destination.

The Client

Finally I needed some tool to easily post snippets into the API so I just wrote another little Go script that can either read a file or read stdin (so I can pipe stuff to it) and POST it to the API and return the resulting URL.

And that’s it, I now have a custom paste service I can easily paste stuff into and share it anywhere.