Skip to content

JCreatesGH/personal-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

personal-api

CI Python License: MIT

Your own data API — now-playing, projects, and blog posts as clean JSON — plus a thin portfolio frontend that consumes it. Content lives as markdown + JSON on disk, so publishing a post is just adding a file.

screenshot

Run it

pip install -r requirements.txt
uvicorn app.main:app --reload      # http://localhost:8000  (portfolio + /docs)

API

Route Returns
GET /api/profile name, headline, links
GET /api/now now-playing / current activity (wire to Spotify/Last.fm in prod)
GET /api/projects project list
GET /api/posts post metadata (title, date, summary, tags); ?tag= to filter
GET /api/posts/{slug} full post incl. body
GET /api/tags every tag with its post count, most-used first
GET /feed.xml an RSS 2.0 feed of all posts

The single-post route reads exactly one file and rejects unsafe slugs (no path traversal). /feed.xml XML-escapes every field, so titles with & / < can't break the feed.

Add a blog post

Drop a markdown file in content/posts/ with front matter:

---
title: My new post
date: 2026-06-01
summary: One-line teaser.
tags: [typescript, react]
---
Post body here.

Posts are returned newest-first automatically.

Design

The content layer (app/content.py) is a set of pure functions over a directory — front-matter parsing, post loading, profile loading — so it's tested against a fixture folder without spinning up the server. The frontend is intentionally "dumb": it just fetches the API and renders.

Development

python -m pytest -q   # 19 tests (content parsing, tag/RSS helpers, traversal safety + API endpoints)

License

MIT

About

Your own data API (now-playing, posts, projects) plus a portfolio frontend that consumes it.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors