
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.