URLs should be designed to be shared. While building this blog engine, I was so focused on avoiding collisions between posts using uuid4 through nanoid, I forgot that links wouldn't have any meaning the the user. Fortunately I've seen a pattern with other small sites like Reddit.com or Etsy.com: include a URL friendly version of the title along with the regular page ID.
From https://example.com/watch/123↗ , you end up with https://example.com/watch/123/never-gonna-give-you-up↗ .
Let's fix it!
Converting Titles to Slugs
Creating a slug from the title is mainly done by converting characters to be URL safe, thus replacing or removing incompatible ones. Using encodeURIComponent↗ would be safe but not user friendly. á â à ä
encodeURIComponent encoded would become %C3%A1%20%C3%A2%20%C3%A0%20%C3%A4
, but a-a-a-a
is a better slug.
If you want an out of the box solution that works with many languages, using an npm library↗ like slugify↗ might be best. I only need to support Latin alphabet↗ based languages for now, a few line of codes will suffice:
Good enough!
Redirecting with Next.js
The slug should be an optional part of the URL: posts/{id}(/{slug})
. If the user tries to access the post without the slug, or with an incorrect slug, I will redirect them to the full URL.
Beyond dynamic routes, Next.js allows for catch all statements↗ with the [...folderName]
syntax.
Also it allows for redirects and error pages to be served in the initial generateMetadata
step↗, before the page is rendered.
Next.js uses exceptions to handle notFound()
and redirect()
.
The title is now part of the URL!
Observations
A small negative is that a malicious user could change the slug to something else and share it to misdirect others.
The process is backward and forward compatible: if links have been shared without the slug or if the title is changed, the user will be redirected to the right place.