DEV Community

Cover image for Building a Dynamic Profile Endpoint — GET /me (Node.js/Express + Cat Facts)
Yahaiii
Yahaiii

Posted on

Building a Dynamic Profile Endpoint — GET /me (Node.js/Express + Cat Facts)

I built a small Node.js/Express API with GET /me that returns a JSON profile object plus a live cat fact. The endpoint always returns a consistent schema, a UTC ISO-8601 timestamp, and fetches a new cat fact per request (2s timeout, graceful fallback).

Repository:

https://github.com/yahaiii/hng13-stage0-profile-endpoint

Tech stack

  • Node.js + Express
  • axios (external API fetch)
  • express-rate-limit + morgan (rate limiting + logging)
  • dotenv (env vars)
  • Jest + Supertest (tests)

Goals

The /me endpoint must:

  • Respond to GET /me with HTTP 200
  • Content-Type: application/json
  • Return JSON exactly in this shape:
{
  "status": "success",
  "user": {
    "email": "<your email>",
    "name": "<your full name>",
    "stack": "<your backend stack>"
  },
  "timestamp": "<current UTC time in ISO 8601 format>",
  "fact": "<random cat fact from Cat Facts API>"
}
Enter fullscreen mode Exit fullscreen mode
  • timestamp is the current UTC time in ISO 8601 and updates each request
  • fact is fetched from https://catfact.ninja/fact on every request (no caching)
  • Graceful fallback when external API is down

Implementation (high level)

  • Express app is exported from index.js. server.js starts the listener — this makes tests import the app directly for CI-friendly tests.
  • The /me route:
    • Reads EMAIL, FULL_NAME, STACK from .env
    • Timestamp: new Date().toISOString()
    • Calls https://catfact.ninja/fact with axios and a 2000ms timeout
    • On success: use response.data.fact
    • On error/timeout: fallback string "Cat fact unavailable at the moment."
    • Returns JSON with status: "success", user, timestamp, and fact
  • Basic rate limiting and request logging applied for public deployments

Example handler (illustrative):

// example snippet
const axios = require('axios');

async function getMe(req, res) {
  const user = {
    email: process.env.EMAIL || 'your-email@example.com',
    name: process.env.FULL_NAME || 'Your Full Name',
    stack: process.env.STACK || 'Node.js/Express'
  };

  const timestamp = new Date().toISOString();

  let fact = 'Cat fact unavailable at the moment.';
  try {
    const r = await axios.get('https://catfact.ninja/fact', { timeout: 2000 });
    if (r?.data?.fact) fact = r.data.fact;
  } catch (err) {
    console.error('Cat fact fetch failed:', err.message);
  }

  return res.json({ status: 'success', user, timestamp, fact });
}
Enter fullscreen mode Exit fullscreen mode

How I tested locally (PowerShell)

cd 'c:\path\to\the\project\'
npm install
copy .env.example .env
# edit .env -> set EMAIL and FULL_NAME (and STACK if desired)
npm start
# verify
curl http://localhost:3000/me
# run tests (no server start required; tests import the app)
npm test
Enter fullscreen mode Exit fullscreen mode

Challenges & tradeoffs

  • Returned HTTP 200 with a fallback fact when the external API fails. This keeps the consumer schema stable; alternative is a 502 when downstream fails.
  • Short 2s timeout avoids hanging requests; production may need retry/backoff or circuit breaker.
  • Integration tests call the real external API; for deterministic CI, mock axios responses.

What I learned

  • Exporting the app for tests simplifies CI and avoids starting/stopping servers.
  • Keep API response schemas stable for client reliability.
  • Simple defensive code (timeouts, fallbacks) improves resilience.

Next steps

  • Add axios mocks for deterministic unit tests
  • Improve observability (structured logs, tracing)
  • Add a short TTL cache if external API rate is a concern
  • Add GitHub Actions to run tests on push

Top comments (2)

Collapse
 
roshan_sharma_7deae5e0742 profile image
roshan sharma

Really solid work! The structure is clean, your fallback handling is thoughtful, and I like how you kept the schema consistent for reliability. Curious, did you run into any tricky issues with axios timeouts or environment variable loading during testing?

Collapse
 
yahaiii profile image
Yahaiii

Thanks @roshan_sharma_7deae5e0742 for pointing those out.

For axios timeouts, I wrapped the call in try/catch, set a 2s timeout, logged errors, and return a safe fallback so the JSON schema stays consistent.

And for the other issue with env loading in tests it was tackled by ensuring dotenv runs before any module reads process.env.

Fixed :D