Flask Service

Date
Clock 7 min read
Tag
#python #flask #rest api
Flask Service

This focused publication documents the primary backend service for SinPluma: the Python/Flask application that implements the product’s domain logic. It explains how the service is built, its purpose, the libraries and patterns used, a detailed inventory of endpoints (what they do and how they behave), and how the service uses Redis, MinIO and the MySQL InnoDB Cluster — including the reasons those systems are required.


1. Purpose and role in the platform

The Flask service is the canonical application API for SinPluma. It is the single source of business logic for:

  • user authentication and authorization,
  • author/profile management,
  • creation, editing, versioning and publishing of notebooks/pages,
  • media uploads (images embedded in content),
  • lightweight search and read APIs,
  • session & token lifecycle (revocation),
  • glue to auxiliary components (linguistics service) and to infrastructure (MinIO, Redis, MySQL).

Architecturally it is “the brain” that enforces invariants, performs transactional updates, and serves JSON endpoints consumed by the React SPA (and potential external clients).


2. How the service is built — project layout & runtime

2.1 Code layout (typical)

/flaskService /app /models # SQLAlchemy models (User, Notebook, Page, ImageMeta, etc.) /schemas # marshmallow schemas for request/response validation /resources # Flask-RESTful resources (endpoints) /auth # JWT helpers, auth decorators, token blacklist logic /storage # MinIO helper wrapper /db # DB session/engine configuration /utils # utility functions (pagination, errors) wsgi.py # gunicorn entry requirements.txt config.py # env-driven config (DB URI, Redis URL, MinIO credentials)

2.2 Runtime & deployment

  • WSGI server:gunicornruns the Flask app in production containers; multiple workers provide concurrency.
  • Containerization: the service is packaged in a Docker image and orchestrated in the repository with Docker Compose (or K8s in production migrations).
  • Configuration: environment variables configure DB endpoints, MinIO keys, Redis URL and JWT secrets.

3. Core libraries and why they were chosen

  • Flask — lightweight, explicit microframework for REST APIs.
  • Flask-RESTful — structured resource-based routing (class-based endpoints).
  • Flask-JWT-Extended — JWT issuance, refresh tokens and token verification.
  • Flask-SQLAlchemy + pymysql — ORM and DB connectivity to MySQL (InnoDB cluster).
  • marshmallow / flask-marshmallow — request input validation and response serialization.
  • Flask-Minio (or custom MinIO wrapper) — S3-compatible object storage integration.
  • flask-redis — Redis client integration for token blacklist and caching.
  • bcrypt — secure password hashing.
  • gunicorn — robust WSGI server for production concurrency.

4. Endpoint inventory — methods, paths, behavior and guarantees

Note: exact route names may vary by repository file names; these are the canonical semantics implemented.

4.1 Authentication & session

  • POST/api/auth/register
    • Purpose: Create a new user account.
    • Input:{ "username", "email", "password" }(validated by marshmallow).
    • Behavior: Hash password with bcrypt and createUserrow in DB inside a transaction.
    • Response:{ "id", "username", "email" }or JWT token.
  • POST/api/auth/login
    • Purpose: Authenticate user and issue JWT access tokens.
    • Input:{ "email", "password" }.
    • Behavior: Verify password. On success, issue JWT with JTI and expiry.
  • POST/api/auth/logout
    • Purpose: Revoke a token (blacklist).
    • Input: Authorization header with JWT.
    • Behavior: Store JWT JTI in Redis with TTL.
  • POST/api/auth/refresh
    • Purpose: Exchange refresh token for a new access token.

4.2 Users & Profiles

  • GET/api/users/{id}
    • Purpose: Fetch public profile metadata.
    • Auth: optional (public).
    • Behavior: Read from MySQL; response serialized via marshmallow.
  • PUT/api/users/{id}
    • Purpose: Update profile (display name, bio, avatar reference).
    • Auth: required and authorized (user must match).
    • Behavior: DB update in transaction.

4.3 Notebooks / Works (core content model)

  • GET/api/notebooks
    • Purpose: List user’s notebooks or public notebooks.
    • Query:?page=,?per_page=,?public=true
  • POST/api/notebooks
    • Purpose: Create a new notebook/draft resource.
    • Input:{ "title", "description", "metadata" }
    • Behavior: DB insert within transaction; returns created resource (id).
  • GET/api/notebooks/{notebook_id}
    • Purpose: Retrieve notebook metadata and page list.
  • DELETE/api/notebooks/{notebook_id}
    • Purpose: Remove or mark-as-deleted (soft-delete).

4.4 Pages & Revisions

  • GET/api/notebooks/{notebook_id}/pages/{page_id}
    • Purpose: Get content for a page (draft or published).
  • POST/api/notebooks/{notebook_id}/pages
    • Purpose: Add page to notebook.
    • Input:{ "title", "content", "order" }
  • PUT/api/notebooks/{notebook_id}/pages/{page_id}
    • Purpose: Update page content (save / autosave).
    • Input: page content + optionalautosaveflag.
  • GET/api/pages/{id}/revisions
    • Purpose: List past revisions for audit and rollback.

4.5 Publish / Unpublish

  • POST/api/notebooks/{id}/publish
    • Purpose: Mark notebook/pages as published.
  • POST/api/notebooks/{id}/unpublish
    • Purpose: Revoke public listing.

4.6 Media uploads

  • POST/api/uploads/images
    • Purpose: Upload image for profile or content embedding.
    • Input:multipart/form-datawith file and optional metadata.
    • Behaviour: Validate file, upload to MinIO, and createimage_metarow in MySQL.

4.7 Search & discovery

  • GET/api/search?q=...
    • Purpose: Basic content search (SQLLIKE).

4.8 Integrations / linguistics proxy

  • GET/api/lin/sentiment?sent=...
    • Purpose: Proxy or forward requests to the separate Linguistics service.

5. Communication with Redis, MinIO and the InnoDB cluster

5.1 Redis — what it stores and why Flask needs it

What is stored:

  • Token blacklist: JWT ID (JTI) and its expiry.
  • Short-lived caches: Frequently-read author snippets.
  • Transient locks: Rate-limiting counters.

5.2 MinIO (S3-compatible) — image storage

What is stored:

  • User avatars, embedded images, and binary objects referenced by writings.

Transaction semantics: The service writes to MinIO first and only then inserts DB metadata inside a DB transaction; on DB failure the object can be flagged for cleanup.

5.3 InnoDB Cluster (MySQL) — authoritative transactional store

What is stored in MySQL:

  • Users, credentials, notebooks, pages, revisions, and image metadata references.

How Flask connects: Flask uses SQLAlchemy with a connection URI pointing at the MySQL Router (e.g.,mysql+pymysql://root:root@inno_router:6446/SinPluma).


6. Operational & reliability patterns

  • Idempotency keys: Prevent duplicate side-effects on retries.
  • Connection pooling: SQLAlchemy parameters tuned to match worker counts.
  • Health checks: Liveness/readiness probes exposed for orchestrators.

7. Security considerations

  • Password hashing: bcrypt.
  • JWT usage: short-lived access tokens + Redis-backed blacklist.
  • Input validation: marshmallow schemas.
  • File validation: size and MIME type checks server-side.

8. Why the Flask service needs these components

  • MySQL InnoDB Cluster: Durability, revision history, and high availability.
  • MinIO: Offloads binary assets from the relational DB for better performance.
  • Redis: Optimized for ephemeral, auth-critical data with low latency.

9. Closing summary

The Flask service is the central, transactional API for SinPluma. Its design emphasizes data integrity via the InnoDB cluster, scalability via MinIO, and high-performance state management via Redis.