Skip to contentJMRG
All projects
COMPLETED

Portfolio API

Private REST API that serves every piece of content on jmrg.dev: posts, projects and the per-language CMS documents. Fastify 5 over HTTP/2, Mongoose 9 and separate public and admin queries, with Clerk authentication on every route except the health check and the preflight.

Node.js · TypeScript · Fastify · MongoDB · Mongoose · Clerk · Zod · Docker

What it solves

The previous portfolio kept data and interface in a single deployment: changing one blog post meant rebuilding the whole website. Here content has its own service, with its own contract and its own lifecycle, and the frontend merely consumes it.

Decisions worth explaining

The API is private end to end. Every request requires a token, public reads such as the blog listing included. The health check and the CORS preflight are exempt, the latter because it cannot carry credentials by definition. The frontend issues its requests from the server, so that token never reaches the browser.

Public and admin queries are not the same query. The public listing filters by published state and trims the fields nobody consumes; the admin one returns the whole document.

Opt-in pagination. With no parameters the listing returns a plain array; with page and limit, an envelope carrying its metadata. Ordering breaks ties by identifier, because sorting on date alone repeated documents across pages whenever two shared the same one.

One document per language

Every piece of content exists once per language, keyed by the pair identifier and locale. Languages are deliberately asymmetric: an article can ship in Spanish before it has an English version. The frontend declares only the languages that actually exist in its alternate tags, rather than advertising a translation that would return a 404.

Stack

Layer Technology
Runtime Node 24, strict TypeScript
HTTP Fastify 5 over HTTP/2
Persistence MongoDB with Mongoose 9
Auth Clerk, with an e-mail allowlist for the admin panel
Validation Zod at the edge of every route
Errors Problem Details (RFC 9457)