๐Ÿ“ Blog API Playground

Try every endpoint. The right panel shows which server function ran and what SQL/JWT happened behind the scenes.

Swagger docs: docs ยท Source repo: blog-api/app/

๐Ÿ” Auth /auth

Token:
โ€” none yet โ€”

๐Ÿ“ฐ Posts /posts

๐Ÿ’ฌ Comments /comments

๐Ÿ“ก Activity log

Ready. Try registering a user โ†’

๐Ÿง  What happens on the server?

Every request lands on FastAPI in app/main.py, which routes it to a function based on the URL prefix:

  • /auth/* โ†’ app/routes/auth.py
  • /users/* โ†’ app/routes/users.py
  • /posts/* โ†’ app/routes/posts.py
  • /comments/* โ†’ app/routes/comments.py
๐Ÿ” What happens on register / login?
1. Pydantic validates JSON โ†’ UserCreate (schemas/user.py)
2. SQLAlchemy checks if username exists in `users` table
3. On register: password hashed with bcrypt (core/security.hash_password)
4. On login: verify_password(plain, hash)  โ†’  bcrypt compare
5. jwt_handler.create_access_token({"sub": username}) signs a JWT
   using SECRET_KEY + HS256 (config.py). Expires in 30 min.
6. Returns { access_token, token_type: "bearer" }
๐Ÿ›ก How is a protected endpoint checked?
1. FastAPI dependency get_current_user() runs before the route.
2. It reads "Authorization: Bearer <token>" header.
3. decode_jwt() verifies signature + expiry.
4. Looks up User row by `sub` claim.
5. Injects the User object into the route function as
   `current_user: User = Depends(get_current_user)`.
6. Route can now enforce ownership:
     if post.author_id != current_user.id: raise 403
๐Ÿ“ฐ What runs for POST /posts/?
routes/posts.py โ†’ create_post()
  โ”œโ”€ get_current_user()   โ†’ validates JWT
  โ”œโ”€ Post(**data, author_id=current_user.id)
  โ”œโ”€ db.add() + db.commit()   โ† SQLAlchemy INSERT
  โ””โ”€ returns Post โ†’ serialized by PostOut schema (from_attributes=True)
๐Ÿ’ฌ What runs for POST /comments/?
routes/comments.py โ†’ create_comment()
  โ”œโ”€ get_current_user()
  โ”œโ”€ Comment(post_id, content, author_id=current_user.id)
  โ”œโ”€ INSERT into `comments` (FK โ†’ posts.id, users.id)
  โ””โ”€ Response serialized by CommentOut
๐Ÿ—„ Where is data stored?
SQLite file  โ†’  blog.db  (see config.DATABASE_URL)
Tables auto-created on startup by:
  Base.metadata.create_all(bind=engine)   in app/main.py
Delete blog.db to reset everything.