Category: Uncategorized

  • Python Django Rest Framework Drf Tutorial

    Python Django REST Framework (DRF) tutorial – If you’re a Python developer looking to expose your Django models as powerful, standards‑compliant APIs, you’ve landed in the right place. In this step‑by‑step guide we’ll walk through everything you need to know to build, test, and secure a RESTful API with Django REST Framework. From project setup to serializers, viewsets, routers, authentication, and best‑practice tips, this tutorial covers the full stack so you can launch production‑ready endpoints in minutes.

    Why Choose Django REST Framework?

    • Built for Django: DRF integrates seamlessly with Django’s ORM, authentication system, and admin.
    • Rich feature set: Automatic URL routing, browsable API, pagination, filtering, and content negotiation.
    • Extensible: Plug‑in custom renderers, parsers, throttling, and permission classes.
    • Strong community: Extensive documentation, tutorials, and third‑party packages.

    Project Setup – Getting the Foundations Right

    1. Create a virtual environment

    python -m venv env
    source env/bin/activate   # On Windows use `env\Scripts\activate`
    

    2. Install Django and DRF

    pip install django djangorestframework
    

    3. Start a new Django project

    django-admin startproject myapi
    cd myapi
    python manage.py startapp blog
    

    4. Register apps

    Add 'rest_framework' and your new 'blog' app to INSTALLED_APPS in myapi/settings.py:

    INSTALLED_APPS = [
        # default Django apps …
        'rest_framework',
        'blog',
    ]
    

    Modeling Data – The First Building Block

    Let’s create a simple Post model to represent blog entries.

    # blog/models.py
    from django.db import models
    
    class Post(models.Model):
        title   = models.CharField(max_length=200)
        body    = models.TextField()
        author  = models.CharField(max_length=100)
        created = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return self.title
    

    Run migrations to create the table:

    python manage.py makemigrations
    python manage.py migrate
    

    Serializers – Converting Django Objects to JSON

    A serializer defines how model instances are turned into JSON (or other formats) and vice‑versa.

    # blog/serializers.py
    from rest_framework import serializers
    from .models import Post
    
    class PostSerializer(serializers.ModelSerializer):
        class Meta:
            model  = Post
            fields = ['id', 'title', 'body', 'author', 'created']
    

    Views – The Logic Behind Each Endpoint

    DRF provides several view styles. For most CRUD APIs, ModelViewSet is the most concise.

    # blog/views.py
    from rest_framework import viewsets
    from .models import Post
    from .serializers import PostSerializer
    
    class PostViewSet(viewsets.ModelViewSet):
        """
        API endpoint that allows posts to be viewed or edited.
        """
        queryset = Post.objects.all().order_by('-created')
        serializer_class = PostSerializer
    

    Routing – Mapping URLs to Views Automatically

    Using DefaultRouter DRF can generate a full set of routes (list, create, retrieve, update, delete) with a single line.

    # blog/urls.py
    from django.urls import path, include
    from rest_framework.routers import DefaultRouter
    from .views import PostViewSet
    
    router = DefaultRouter()
    router.register(r'posts', PostViewSet)
    
    urlpatterns = [
        path('', include(router.urls)),
    ]
    

    Don’t forget to include the app’s URLs in the project’s root:

    # myapi/urls.py
    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('api/', include('blog.urls')),   # <-- API root
    ]
    

    Testing the API – The Browsable Interface

    Start the development server:

    python manage.py runserver
    

    Navigate to http://127.0.0.1:8000/api/posts/. DRF’s browsable API lets you:

    • View a list of posts in JSON or HTML.
    • Submit POST, PUT, PATCH, and DELETE requests directly from the browser.
    • Inspect request/response headers for debugging.

    Adding Authentication and Permissions

    Secure your API by enabling token‑based authentication and restricting actions.

    1. Install the token package

    pip install djangorestframework-simplejwt
    

    2. Update settings

    # myapi/settings.py
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework_simplejwt.authentication.JWTAuthentication',
        ),
        'DEFAULT_PERMISSION_CLASSES': (
            'rest_framework.permissions.IsAuthenticatedOrReadOnly',
        ),
    }
    

    3. Create token endpoints

    # myapi/urls.py (add below existing patterns)
    from rest_framework_simplejwt.views import (
        TokenObtainPairView,
        TokenRefreshView,
    )
    
    urlpatterns += [
        path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
        path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    ]
    

    4. Test with curl

    # Obtain a token
    curl -X POST -H "Content-Type: application/json" \
         -d '{"username":"admin","password":"adminpwd"}' \
         http://127.0.0.1:8000/api/token/
    
    # Use the token to create a post
    curl -X POST -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
         -H "Content-Type: application/json" \
         -d '{"title":"First Post","body":"Hello DRF!","author":"Alice"}' \
         http://127.0.0.1:8000/api/posts/
    

    Advanced Features You’ll Love

    • Pagination: Set PAGE_SIZE in settings or use LimitOffsetPagination per view.
    • Filtering: Integrate django-filter to enable URL‑based query parameters (e.g., ?author=Alice).
    • Versioning: Prefix URLs with /v1/, /v2/ or use Accept‑Header versioning for backward compatibility.
    • Custom Actions: Add @action‑decorated methods in a viewset for non‑CRUD endpoints (e.g., /posts/{id}/publish/).

    Best Practices for a Production‑Ready DRF API

    1. Separate serializers from models: Keep business logic out of serializers; use validate_* methods for field‑level checks.
    2. Use viewsets and routers: Reduces boilerplate and guarantees a consistent URL scheme.
    3. Limit exposure: Apply IsAdminUser or custom permission classes to sensitive endpoints.
    4. Document with OpenAPI/Swagger: Install drf-yasg or drf-spectacular to generate interactive API docs.
    5. Cache expensive queries: Leverage Django’s cache framework or DRF’s CacheResponseMixin for read‑heavy resources.
    6. Write tests: Use APITestCase to assert response codes, data shapes, and permission enforcement.
    7. Monitor performance: Enable Django’s django‑silk or external APM tools to track latency.

    Deploying Your DRF Application

    When you’re ready to go live, follow these deployment steps:

    • Choose a WSGI server such as gunicorn or uwsgi.
    • Place the app behind a reverse proxy (NGINX or Apache) for static file handling and SSL termination.
    • Set DEBUG = False and configure ALLOWED_HOSTS.
    • Use a PostgreSQL or MySQL database for production instead of SQLite.
    • Configure environment variables for secret keys, database credentials, and JWT signing keys.

    Conclusion

    Building a robust API with Python Django REST Framework is both fast and scalable. By following this tutorial you’ve learned how to set up a Django project, define models, serialize data, expose CRUD endpoints with viewsets, secure them with JWT authentication, and adopt best practices for production readiness. Whether you’re creating a mobile backend, a microservice, or a public API, DRF gives you the tools to deliver clean, maintainable, and performant RESTful services. Keep experimenting with

  • Python Flask E-Commerce Cart Management

    Building a robust e‑commerce platform with Python Flask starts with a solid shopping cart. A well‑designed cart not only improves conversion rates but also sets the stage for smooth checkout, inventory tracking, and personalized user experiences. In this guide we’ll walk through everything you need to know to implement Flask e‑commerce cart management—from project setup and data modeling to session handling, database persistence, and security best practices. Whether you’re a solo developer or part of a growing team, the patterns and code snippets below will help you create a scalable, SEO‑friendly cart that keeps customers coming back.

    Why Flask Is a Great Choice for E‑Commerce Cart Management

    • Lightweight core: Flask gives you full control over the cart logic without unnecessary bloat.
    • Extensible ecosystem: Plug‑in extensions like Flask‑Login, Flask‑SQLAlchemy, and Flask‑Session handle authentication, ORM, and server‑side sessions out of the box.
    • SEO‑ready routing: Clean URL structures and customizable view functions make it easy to expose cart pages to search engines.
    • Community support: A vibrant community means plenty of tutorials, code examples, and security patches.

    Project Setup: Getting the Basics Right

    Before diving into cart logic, set up a clean Flask environment. Follow these steps to create a reproducible starter project.

    mkdir flask_shop
    cd flask_shop
    python -m venv venv
    source venv/bin/activate  # Windows: venv\Scripts\activate
    pip install Flask Flask-Login Flask-Session Flask-SQLAlchemy
    

    Next, create the minimal app structure:

    flask_shop/
    │
    ├─ app/
    │   ├─ __init__.py
    │   ├─ models.py
    │   ├─ routes.py
    │   └─ cart.py
    │
    ├─ migrations/
    ├─ static/
    └─ templates/
    

    Initialize the Flask Application

    # app/__init__.py
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    from flask_login import LoginManager
    from flask_session import Session
    
    db = SQLAlchemy()
    login_manager = LoginManager()
    sess = Session()
    
    def create_app():
        app = Flask(__name__)
        app.config['SECRET_KEY'] = 'replace-with-strong-secret'
        app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///shop.db'
        app.config['SESSION_TYPE'] = 'filesystem'   # server‑side session
    
        db.init_app(app)
        login_manager.init_app(app)
        sess.init_app(app)
    
        with app.app_context():
            from . import routes, models, cart
            db.create_all()
    
        return app
    

    Designing the Cart Model

    There are two common approaches to cart storage:

    1. Session‑based cart: Fast, no DB writes until checkout. Ideal for guest users.
    2. Database‑backed cart: Persists across devices and sessions, perfect for logged‑in customers.

    We’ll implement a hybrid model that stores a lightweight CartItem list in the session and syncs it to the database once the user logs in or proceeds to checkout.

    SQLAlchemy Cart Tables

    # app/models.py
    from . import db
    from flask_login import UserMixin
    
    class User(UserMixin, db.Model):
        id = db.Column(db.Integer, primary_key=True)
        email = db.Column(db.String(120), unique=True, nullable=False)
        password = db.Column(db.String(255), nullable=False)
        cart_items = db.relationship('CartItem', backref='owner', lazy=True)
    
    class Product(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(150), nullable=False)
        price = db.Column(db.Numeric(10, 2), nullable=False)
        stock = db.Column(db.Integer, default=0)
    
    class CartItem(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        product_id = db.Column(db.Integer, db.ForeignKey('product.id'), nullable=False)
        user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
        quantity = db.Column(db.Integer, default=1)
    
        product = db.relationship('Product')
    

    Managing the Cart with Flask Sessions

    The Flask‑Session extension stores data server‑side, which avoids the size limits of client‑side cookies and keeps cart information secure.

    Utility Functions for Cart Operations

    # app/cart.py
    from flask import session, current_app
    from .models import db, Product, CartItem, User
    
    def _get_cart():
        """Return the current cart dict from the session."""
        return session.setdefault('cart', {})
    
    def add_to_cart(product_id, quantity=1):
        cart = _get_cart()
        pid = str(product_id)
        cart[pid] = cart.get(pid, 0) + quantity
        session.modified = True
    
    def remove_from_cart(product_id):
        cart = _get_cart()
        pid = str(product_id)
        if pid in cart:
            del cart[pid]
            session.modified = True
    
    def update_quantity(product_id, quantity):
        cart = _get_cart()
        pid = str(product_id)
        if quantity <= 0:
            remove_from_cart(product_id)
        else:
            cart[pid] = quantity
            session.modified = True
    
    def clear_cart():
        session.pop('cart', None)
        session.modified = True
    
    def sync_cart_to_db(user_id):
        """Persist session cart to the database for a logged‑in user."""
        user = User.query.get(user_id)
        if not user:
            return
    
        # Remove existing items to avoid duplicates
        CartItem.query.filter_by(user_id=user.id).delete()
    
        for pid, qty in _get_cart().items():
            item = CartItem(user_id=user.id,
                            product_id=int(pid),
                            quantity=qty)
            db.session.add(item)
        db.session.commit()
        clear_cart()
    

    Routes: Adding, Updating, and Viewing Cart Items

    # app/routes.py
    from flask import render_template, request, redirect, url_for, flash
    from flask_login import login_user, logout_user, login_required, current_user
    from . import create_app, db
    from .models import Product, User
    from .cart import add_to_cart, remove_from_cart, update_quantity, sync_cart_to_db
    
    app = create_app()
    
    @app.route('/')
    def index():
        products = Product.query.all()
        return render_template('index.html', products=products)
    
    @app.route('/cart')
    def view_cart():
        cart = session.get('cart', {})
        items = []
        total = 0
        for pid, qty in cart.items():
            product = Product.query.get(int(pid))
            if product:
                subtotal = float(product.price) * qty
                total += subtotal
                items.append({'product': product, 'quantity': qty, 'subtotal': subtotal})
        return render_template('cart.html', items=items, total=total)
    
    @app.route('/cart/add/', methods=['POST'])
    def add(product_id):
        qty = int(request.form.get('quantity', 1))
        add_to_cart(product_id, qty)
        flash('Product added to cart.', 'success')
        return redirect(url_for('view_cart'))
    
    @app.route('/cart/remove/', methods=['POST'])
    def remove(product_id):
        remove_from_cart(product_id)
        flash('Product removed from cart.', 'info')
        return redirect(url_for('view_cart'))
    
    @app.route('/cart/update/', methods=['POST'])
    def update(product_id):
        qty = int(request.form.get('quantity', 1))
        update_quantity(product_id, qty)
        flash('Cart updated.', 'success')
        return redirect(url_for('view_cart'))
    
    @app.route('/checkout')
    @login_required
    def checkout():
        sync_cart_to_db(current_user.id)
        flash('Cart saved to your account. Proceed to payment.', 'success')
        return redirect(url_for('order_summary'))
    

    Persisting Cart Data for Logged‑In Users

    When a user logs in, you should merge any existing session cart with items already stored in the database. This ensures a seamless experience across devices.

    Login Hook to Merge Carts

    # app/routes.py (add to login view)
    from .cart import _get_cart, sync_cart_to_db
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        # ... authentication logic ...
        if user and check_password_hash(user.password, password):
            login_user(user)
            # Merge session cart into DB
            sync_cart_to_db(user.id)
            return redirect(url_for('index'))
        # render login template on failure
    

    Security Considerations for Cart Management

    • CSRF protection: Use Flask‑WTF or the built‑in csrf_token to guard all POST routes.
    • Input validation: Cast quantities to int and enforce positive values.
    • Stock checks: Before adding or updating a cart item, verify that product.stock >= requested_quantity to prevent overselling.
    • Session fixation: Regenerate the session ID after login with session.regenerate() (or Flask‑Login’s login_user(..., fresh=True)).
    • Data sanitization: Never trust client‑side price values; always recalculate totals on the server using the product’s price from the DB.

    Testing the Cart: Unit and Integration Strategies

    Automated tests catch regressions early and give confidence when refactoring. Below is a simple pytest example for the cart utilities.

  • Python Flask Real-Time Chat With Socketio

    Looking to add a live, interactive chat feature to your web app without the hassle of complex JavaScript frameworks? Python Flask real-time chat with SocketIO gives you a lightweight, scalable solution that works across browsers and mobile devices. In this guide we’ll walk through everything you need to build a fully functional chat application—from setting up the Flask server and integrating SocketIO, to handling rooms, user authentication, and deploying to production. By the end, you’ll have a ready‑to‑use codebase and a solid understanding of how real‑time communication works under the hood.

    Why Choose Flask and SocketIO for Real‑Time Chat?

    • Flask’s simplicity: A micro‑framework that lets you focus on business logic without boilerplate.
    • SocketIO compatibility: Provides a WebSocket‑like API that automatically falls back to long‑polling when necessary, ensuring reliable delivery.
    • Python ecosystem: Leverage familiar libraries (e.g., Flask‑Login, SQLAlchemy) for authentication and persistence.
    • Scalable architecture: Works seamlessly with message brokers like Redis or RabbitMQ for multi‑worker deployments.

    Project Structure Overview

    my_chat_app/
    ├─ app.py                 # Flask entry point
    ├─ requirements.txt       # Python dependencies
    ├─ templates/
    │   └─ index.html         # Main chat UI
    ├─ static/
    │   ├─ css/
    │   │   └─ style.css
    │   └─ js/
    │       └─ chat.js
    └─ models.py              # (optional) DB models for users, messages
    

    Step‑by‑Step Implementation

    1. Install Required Packages

    Open your terminal and create a virtual environment. Then install Flask, Flask‑SocketIO, and a message broker client (Redis is a popular choice).

    python -m venv venv
    source venv/bin/activate   # Windows: venv\Scripts\activate
    pip install Flask Flask‑SocketIO python‑engineio[gevent] redis
    

    2. Create the Flask Application (app.py)

    The core of our chat lives in app.py. Below is a minimal but production‑ready setup.

    from flask import Flask, render_template, request, session, redirect, url_for
    from flask_socketio import SocketIO, emit, join_room, leave_room
    import os
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'dev_secret')
    socketio = SocketIO(app, cors_allowed_origins="*")  # Enable CORS for simplicity
    
    # -------------------- Routes --------------------
    @app.route('/', methods=['GET', 'POST'])
    def index():
        if request.method == 'POST':
            username = request.form.get('username')
            if username:
                session['username'] = username
                return redirect(url_for('chat'))
        return render_template('index.html')
    
    @app.route('/chat')
    def chat():
        if 'username' not in session:
            return redirect(url_for('index'))
        return render_template('chat.html', username=session['username'])
    
    # -------------------- SocketIO Events --------------------
    @socketio.on('join')
    def handle_join(data):
        room = data['room']
        join_room(room)
        emit('status', {'msg': f"{session['username']} has entered the room."}, room=room)
    
    @socketio.on('message')
    def handle_message(data):
        room = data['room']
        msg = data['msg']
        emit('message', {'user': session['username'], 'msg': msg}, room=room)
    
    @socketio.on('leave')
    def handle_leave(data):
        room = data['room']
        leave_room(room)
        emit('status', {'msg': f"{session['username']} has left the room."}, room=room)
    
    if __name__ == '__main__':
        # For production, use a proper WSGI server (e.g., gunicorn) and a message queue.
        socketio.run(app, debug=True)
    

    3. Build the Front‑End (templates/chat.html)

    The HTML page loads SocketIO’s client library, connects to the server, and handles UI updates.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Flask Real‑Time Chat</title>
        <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
        <script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
    </head>
    <body>
        <div class="chat-container">
            <h2>Welcome, {{ username }}!</h2>
            <div id="room-select">
                <input type="text" id="room-input" placeholder="Enter room name">
                <button id="join-btn">Join</button>
            </div>
            <div id="chat-box" class="hidden">
                <ul id="messages"></ul>
                <input id="msg-input" autocomplete="off" placeholder="Type a message..." />
                <button id="send-btn">Send</button>
                <button id="leave-btn">Leave</button>
            </div>
        </div>
    
        <script src="{{ url_for('static', filename='js/chat.js') }}"></script>
    </body>
    </html>
    

    4. Client‑Side JavaScript (static/js/chat.js)

    The script manages socket events, UI toggles, and message rendering.

    document.addEventListener('DOMContentLoaded', () => {
        const socket = io();
    
        const joinBtn   = document.getElementById('join-btn');
        const leaveBtn  = document.getElementById('leave-btn');
        const sendBtn   = document.getElementById('send-btn');
        const roomInput = document.getElementById('room-input');
        const msgInput  = document.getElementById('msg-input');
        const chatBox   = document.getElementById('chat-box');
        const messages  = document.getElementById('messages');
    
        let currentRoom = null;
    
        // ---------- Helper ----------
        const addMessage = (text, type='msg') => {
            const li = document.createElement('li');
            li.className = type;
            li.textContent = text;
            messages.appendChild(li);
            messages.scrollTop = messages.scrollHeight;
        };
    
        // ---------- Join ----------
        joinBtn.onclick = () => {
            const room = roomInput.value.trim();
            if (!room) return;
            socket.emit('join', {room});
            currentRoom = room;
            chatBox.classList.remove('hidden');
            addMessage(`You joined "${room}"`, 'status');
        };
    
        // ---------- Leave ----------
        leaveBtn.onclick = () => {
            if (!currentRoom) return;
            socket.emit('leave', {room: currentRoom});
            addMessage(`You left "${currentRoom}"`, 'status');
            chatBox.classList.add('hidden');
            currentRoom = null;
        };
    
        // ---------- Send ----------
        sendBtn.onclick = () => {
            const msg = msgInput.value.trim();
            if (!msg || !currentRoom) return;
            socket.emit('message', {room: currentRoom, msg});
            msgInput.value = '';
        };
    
        // ---------- Receive ----------
        socket.on('message', data => {
            addMessage(`${data.user}: ${data.msg}`);
        });
    
        socket.on('status', data => {
            addMessage(data.msg, 'status');
        });
    });
    

    5. Styling the Chat (static/css/style.css)

    A clean UI improves user retention. Below is a minimal CSS snippet that keeps the focus on the conversation.

    body {
        font-family: Arial, sans-serif;
        background: #f4f7f9;
        margin: 0;
        padding: 20px;
    }
    .chat-container {
        max-width: 600px;
        margin: auto;
        background: #fff;
        border-radius: 8px;
        padding: 20px;
        box-shadow: 0 2px 8px rgba(0,0,0,.1);
    }
    #messages {
        list-style: none;
        padding: 0;
        max-height: 300px;
        overflow-y: auto;
        margin-bottom: 10px;
    }
    #messages li {
        padding: 5px 10px;
        border-radius: 4px;
    }
    #messages li.msg { background: #e1f5fe; }
    #messages li.status { color: #777; font-style: italic; }
    .hidden { display: none; }
    

    Advanced Features You Can Add

    • Persisted chat history: Store messages in a database (e.g., PostgreSQL) and load recent logs when a user joins a room.
    • Private messaging: Create one‑to‑one rooms using unique identifiers and emit events only to those sockets.
    • Authentication middleware: Use Flask‑Login to protect the chat routes and attach user IDs to socket sessions.
    • Typing indicators: Broadcast a typing event when a user is composing a message.
    • Scalable deployment: Pair Flask‑SocketIO with eventlet or gevent workers and a Redis message queue to synchronize multiple processes.

    Testing Your Real‑Time Chat Locally

    1. Run the Flask server: python app.py.
  • Python Flask Microservices Architecture

    Building scalable, maintainable, and fast‑moving applications has become a top priority for modern development teams. Python Flask microservices architecture offers a lightweight yet powerful way to break monolithic codebases into independent, reusable services that can be deployed, updated, and scaled on their own. In this guide we’ll explore why Flask is an excellent choice for microservices, walk through the core components of a Flask‑based microservice ecosystem, and provide practical tips for designing, containerizing, and orchestrating your services for production.

    Why Choose Flask for Microservices?

    Flask is a micro‑framework that gives you just enough tools to build web APIs without the overhead of a full‑stack solution. This minimalism translates into several advantages for a microservices architecture:

    • Lightweight footprint – Only the essentials are loaded, keeping memory and CPU usage low.
    • Flexibility – You can pick the exact extensions (SQLAlchemy, Marshmallow, Celery, etc.) you need per service.
    • Fast development cycle – Simple routing and request handling let developers prototype and iterate quickly.
    • Python ecosystem – Leverage a rich set of libraries for data processing, machine learning, and more.

    Core Principles of a Flask Microservices Architecture

    1. Single Responsibility per Service

    Each Flask service should own one business capability (e.g., user‑management, order‑processing, inventory‑lookup). This isolation reduces coupling and makes it easier to evolve services independently.

    2. API‑First Design

    Define clear RESTful or GraphQL contracts before writing code. Use tools like OpenAPI (Swagger) to generate documentation that stays in sync with the implementation.

    3. Statelessness

    Microservices should not rely on in‑memory session data. Store state in external systems (databases, caches, message brokers) so any instance can handle any request.

    4. Independent Deployment

    Package each Flask app as a Docker image. This enables continuous delivery pipelines to push updates without affecting other services.

    Building a Flask Microservice: Step‑by‑Step

    Project Layout

    my_service/
    ├── app/
    │   ├── __init__.py
    │   ├── routes.py
    │   ├── models.py
    │   └── schemas.py
    ├── tests/
    │   └── test_routes.py
    ├── Dockerfile
    ├── requirements.txt
    └── config.py
    

    This structure separates the application logic (app/) from tests and configuration, making the codebase easier to navigate.

    Creating the Flask Application

    # app/__init__.py
    from flask import Flask
    from .routes import api_blueprint
    
    def create_app(config_object='config.Config'):
        app = Flask(__name__)
        app.config.from_object(config_object)
    
        # Register blueprints (modular routing)
        app.register_blueprint(api_blueprint, url_prefix='/api/v1')
        return app
    

    Defining a Simple REST Endpoint

    # app/routes.py
    from flask import Blueprint, request, jsonify
    from .models import User
    from .schemas import UserSchema
    
    api_blueprint = Blueprint('api', __name__)
    user_schema = UserSchema()
    
    @api_blueprint.route('/users', methods=['POST'])
    def create_user():
        data = request.get_json()
        errors = user_schema.validate(data)
        if errors:
            return jsonify(errors), 400
    
        user = User(**data)
        user.save()
        return user_schema.jsonify(user), 201
    

    Notice the use of a Blueprint to keep routing modular – a best practice when scaling to dozens of services.

    Containerizing Flask Microservices

    Docker provides a consistent runtime environment across development, staging, and production. Below is a minimal Dockerfile for a Flask service:

    # Dockerfile
    FROM python:3.12-slim
    
    # Set working directory
    WORKDIR /app
    
    # Install dependencies
    COPY requirements.txt .
    RUN pip install --no-cache-dir -r requirements.txt
    
    # Copy source code
    COPY . .
    
    # Expose the default Flask port
    EXPOSE 5000
    
    # Use gunicorn for production‑grade serving
    CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "app:create_app()"]
    

    Key points:

    • Use gunicorn (or uvicorn for async) instead of the built‑in development server.
    • Multi‑worker configuration (-w 4) improves concurrency.
    • Keep the image size small by using the slim variant and cleaning caches.

    Service Discovery & Communication

    In a microservices world, services must locate each other dynamically. Common patterns include:

    1. DNS‑based discovery – Register services with a DNS server (e.g., Consul) and resolve hostnames at runtime.
    2. Service mesh – Use Envoy or Istio to handle routing, retries, and observability without code changes.
    3. API gateway – Central entry point (Kong, Traefik, AWS API Gateway) that routes external traffic to internal services.

    For most Flask microservices, a lightweight approach using Docker‑compose or Kubernetes Service objects suffices during early stages.

    Data Management Strategies

    Database per Service

    Each microservice should own its own database schema (or even a different database type). This eliminates tight coupling and allows independent scaling. Example:

    • user‑service → PostgreSQL
    • order‑service → MongoDB (document‑oriented)
    • analytics‑service → ClickHouse (columnar)

    Event‑Driven Communication

    When services need to stay in sync without synchronous HTTP calls, publish events to a message broker (RabbitMQ, Apache Kafka, or AWS SNS/SQS). A typical flow:

    # Example using Celery + RabbitMQ
    # tasks.py
    from celery import Celery
    
    celery = Celery('tasks', broker='amqp://guest@rabbitmq//')
    
    @celery.task
    def send_welcome_email(user_id):
        # fetch user, send email, etc.
        pass
    

    Events guarantee eventual consistency and improve resilience under high load.

    Observability: Logging, Metrics, and Tracing

    Production‑grade microservices require visibility into their behavior. Implement the following three pillars:

    • Structured Logging – Use jsonlog or structlog to emit logs in JSON format for easy ingestion by ELK or Loki stacks.
    • Metrics – Expose Prometheus metrics via /metrics endpoint using prometheus-flask-exporter.
    • Distributed Tracing – Integrate OpenTelemetry to trace requests across service boundaries, visualizing them in Jaeger or Zipkin.

    Sample Prometheus Exporter

    # app/__init__.py (add after app creation)
    from prometheus_flask_exporter import PrometheusMetrics
    
    def create_app(...):
        app = Flask(__name__)
        # Existing setup ...
    
        # Enable metrics
        PrometheusMetrics(app)
        return app
    

    Continuous Integration & Deployment (CI/CD)

    Automate the lifecycle of each Flask microservice with pipelines that:

    1. Run unit and integration tests on every push.
    2. Build Docker images and push them to a registry (Docker Hub, ECR, GCR).
    3. Deploy to a staging environment using Helm charts or Docker‑compose.
    4. Perform automated security scans (Trivy, Bandit) before production release.

    Sample GitHub Actions snippet for building and pushing an image:

    name: CI
    
    on:
      push:
        branches: [ main ]
    
    jobs:
      build:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
          - name: Set up Python
            uses: actions/setup-python@v4
            with:
              python-version: '3.12'
          - name: Install dependencies
            run: pip install -r requirements.txt
          - name: Run tests
            run: pytest
          - name: Build Docker image
            run: |
              docker build -t myorg/user-service:${{ github.sha }} .
              docker push myorg/user-service:${{ github.sha }}
    

    Scaling Flask Microservices with Kubernetes

    Kubernetes (K8s) is the de‑facto platform for orchestrating containerized microservices. A typical deployment includes:

    • Deployment – Manages replica sets and rolling updates.
    • Service – Provides a stable DNS name and load balancing.
    • Ingress – Routes external HTTP traffic, often backed by an API gateway.
    • Horizontal Pod Autoscaler (HPA) – Scales pods based on CPU or custom metrics.

    Example deployment.yaml

  • Python Flask Role-Based Access Control

    When you build a web application with Python Flask, securing your endpoints is as important as delivering great features. One of the most scalable ways to protect resources is role‑based access control (RBAC), a pattern that lets you assign permissions to roles and then attach those roles to users. In this guide you’ll learn what RBAC is, why it fits Flask perfectly, and how to implement a clean, reusable RBAC system using popular extensions like Flask‑Login, Flask‑Principal, and Flask‑Security. By the end, you’ll have a ready‑to‑use code template that you can drop into any Flask project and start managing user privileges with confidence.

    Understanding Role‑Based Access Control

    RBAC separates who a user is from what they can do. Instead of checking a user’s identity on every request, you check the role assigned to that user. This approach offers three major benefits:

    • Scalability: Adding a new permission only requires updating the role definition, not every route.
    • Maintainability: Business rules stay in a single place, making audits and compliance easier.
    • Clarity: Developers read a role name (“admin”, “editor”) instead of a list of cryptic permission IDs.

    Core Components of Flask RBAC

    1. Authentication vs. Authorization

    Authentication confirms the user’s identity (usually with Flask‑Login). Authorization decides whether the authenticated user may access a particular resource – that’s where RBAC lives.

    2. User Model with Roles

    At the database level you typically need two tables: users and roles, linked by a many‑to‑many association table (user_roles). A minimal SQLAlchemy model looks like this:

    from flask_sqlalchemy import SQLAlchemy
    
    db = SQLAlchemy()
    
    user_roles = db.Table('user_roles',
        db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
        db.Column('role_id', db.Integer, db.ForeignKey('role.id'))
    )
    
    class Role(db.Model):
        id   = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(64), unique=True, nullable=False)
    
    class User(db.Model):
        id       = db.Column(db.Integer, primary_key=True)
        email    = db.Column(db.String(120), unique=True, nullable=False)
        password = db.Column(db.String(255), nullable=False)
        roles    = db.relationship('Role', secondary=user_roles,
                                   backref=db.backref('users', lazy='dynamic'))

    3. Loading Roles on Login

    When a user logs in, Flask‑Login stores the user ID in the session. You can extend the UserMixin to expose a has_role() helper:

    from flask_login import UserMixin
    
    class User(UserMixin, db.Model):
        # ... fields from previous example ...
    
        def has_role(self, role_name):
            return any(role.name == role_name for role in self.roles)

    Implementing RBAC with Flask‑Principal

    Flask‑Principal provides a flexible way to define identities and permissions. Below is a step‑by‑step setup.

    Step 1 – Install the extensions

    • pip install Flask-Login Flask-Principal Flask-SQLAlchemy

    Step 2 – Initialize extensions

    from flask import Flask, abort
    from flask_login import LoginManager, current_user, login_user, logout_user
    from flask_principal import Principal, Permission, RoleNeed, Identity, identity_loaded, identity_changed
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'replace‑with‑strong‑secret'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
    
    db.init_app(app)
    login_manager = LoginManager(app)
    principal = Principal(app)

    Step 3 – Define role‑based permissions

    Each permission is tied to a RoleNeed. You can create reusable objects such as admin_permission or editor_permission:

    admin_permission  = Permission(RoleNeed('admin'))
    editor_permission = Permission(RoleNeed('editor'))

    Step 4 – Load roles into the identity

    @identity_loaded.connect_via(app)
    def on_identity_loaded(sender, identity):
        # Set the identity user object
        identity.user = current_user
    
        # Add the UserNeed (unique identifier)
        if hasattr(current_user, 'id'):
            identity.provides.add(RoleNeed(str(current_user.id)))
    
        # Add each role the user has
        if hasattr(current_user, 'roles'):
            for role in current_user.roles:
                identity.provides.add(RoleNeed(role.name))

    Step 5 – Protect routes with decorators

    Use the @admin_permission.require() decorator to guard a view. If the user lacks the role, Flask‑Principal raises a 403 Forbidden error.

    @app.route('/admin/dashboard')
    @admin_permission.require(http_exception=403)
    def admin_dashboard():
        return 'Welcome to the admin dashboard!'

    Step 6 – Custom error handling

    @app.errorhandler(403)
    def access_denied(e):
        return 'Access denied: you do not have the required permissions.', 403

    Alternative: Using Flask‑Security (All‑in‑One)

    If you prefer a single package that bundles authentication, password hashing, and RBAC, Flask‑Security (or its maintained fork Flask‑Security‑Too) is a solid choice. It adds a RoleMixin and automatically creates decorators like @roles_required and @roles_accepted.

    from flask_security import Security, SQLAlchemyUserDatastore, \
        UserMixin, RoleMixin, login_required, roles_required
    
    class Role(db.Model, RoleMixin):
        id   = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(80), unique=True)
    
    class User(db.Model, UserMixin):
        id       = db.Column(db.Integer, primary_key=True)
        email    = db.Column(db.String(255), unique=True)
        password = db.Column(db.String(255))
        active   = db.Column(db.Boolean())
        roles    = db.relationship('Role', secondary=user_roles,
                                   backref=db.backref('users', lazy='dynamic'))

    After initializing the datastore, protect an endpoint with a single line:

    @app.route('/reports')
    @roles_required('manager')
    def view_reports():
        return 'Confidential reports for managers only.'

    Best Practices for Flask RBAC

    1. Keep permissions granular but manageable

    • Define high‑level roles (admin, editor, viewer) and map fine‑grained actions to them.
    • Avoid creating a separate role for every tiny permission; use Permission objects for the rare cases.

    2. Store role names in constants

    ROLE_ADMIN  = 'admin'
    ROLE_EDITOR = 'editor'
    ROLE_USER   = 'user'

    Using constants prevents typos and makes refactoring easier.

    3. Cache role lookups

    For high‑traffic apps, loading roles from the database on every request can be costly. Store the list of role names in the Flask session or a short‑lived cache (e.g., Redis) after login, and refresh only when the user’s role changes.

    4. Test your access rules

    Write unit tests that simulate users with different roles and verify that protected routes return the expected HTTP status codes. Example with pytest:

    def test_admin_cannot_access_editor_route(client, admin_user):
        login_as(admin_user)
        response = client.get('/editor/page')
        assert response.status_code == 403

    5. Separate business logic from permission checks

    Never embed role checks deep inside service functions. Keep the check at the view layer (or a decorator) and let the underlying function assume the caller is authorized. This separation keeps your codebase clean and testable.

    Full Minimal Flask RBAC Example

    The following script ties everything together. It creates a SQLite database, adds two users (admin and editor), and demonstrates protected routes.

    from flask import Flask, redirect, url_for
    from flask_sqlalchemy import SQLAlchemy
    from flask_login import LoginManager, login_user, logout_user, login_required, current_user
    from flask_principal import Principal, Permission, RoleNeed, identity_loaded, identity_changed, Identity

    app = Flask(__name__)
    app.config.update(
    SECRET_KEY='super‑secret-key',
    SQLALCHEMY_DATABASE_URI='sqlite:///rbac_demo.db',
    SQLALCHEMY_TRACK_MODIFICATIONS=False
    )

    db = SQLAlchemy(app)
    login_manager = LoginManager(app)
    principal = Principal(app)

    # Association table
    user_roles = db.Table('user_roles',
    db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
    db.Column('role_id', db.Integer, db.ForeignKey('role.id'))
    )

    class Role(db.Model):
    id

  • Python Flask Portfolio Website Project

    Creating a personal portfolio website with Python Flask is an excellent way to showcase your projects, skills, and professional story while sharpening your web‑development chops. In this guide we’ll walk through every step of building a clean, responsive, and SEO‑friendly Flask portfolio from scratch, covering everything from environment setup to deployment on a cloud platform. Whether you’re a seasoned developer or just getting started with Flask, the project outlined here will give you a solid foundation you can customize and expand.

    Why Choose Flask for Your Portfolio?

    Flask is a lightweight, micro‑framework that gives you full control over the architecture of your site. Here are a few reasons it’s perfect for a personal portfolio:

    • Flexibility: You can start with a single file and grow to a full‑featured app without fighting the framework.
    • Python‑centric: Leverage your existing Python knowledge and libraries for data handling, image processing, or even AI‑powered features.
    • SEO friendliness: With server‑side rendering, search engines can crawl your content easily, boosting discoverability.
    • Community & extensions: A rich ecosystem (Flask‑Login, Flask‑Mail, Flask‑Migrate, etc.) lets you add functionality quickly.

    Setting Up the Development Environment

    Before writing code, make sure your workstation is ready. Follow these steps:

    1. Install Python 3.11+ if you haven’t already.
    2. Create a virtual environment to isolate dependencies:
    python -m venv venv
    source venv/bin/activate   # On Windows: venv\Scripts\activate
    1. Install Flask and essential extensions:
    pip install Flask Flask-WTF Flask-Mail Flask-Migrate Flask-SQLAlchemy
    1. Optional but recommended: install black and flake8 for code formatting and linting.

    Project Structure: Organizing Your Files

    A clean folder layout makes the project easier to maintain and scale. Below is a recommended structure:

    portfolio/
    │
    ├── app/
    │   ├── __init__.py        # Application factory
    │   ├── routes.py          # View functions
    │   ├── models.py          # Database models
    │   ├── forms.py           # WTForms definitions
    │   ├── static/
    │   │   ├── css/
    │   │   └── images/
    │   └── templates/
    │       ├── base.html
    │       ├── index.html
    │       ├── about.html
    │       └── projects.html
    │
    ├── migrations/            # Flask-Migrate files
    ├── config.py              # Configuration settings
    ├── run.py                 # Entry point
    └── requirements.txt       # Pinned dependencies
    

    This layout separates concerns (routes, models, forms) and keeps static assets organized, which is crucial for SEO‑friendly URLs and fast page loads.

    Building Core Features

    1. Home Page (Landing)

    The home page should introduce you with a concise headline, a professional photo, and a call‑to‑action (CTA) linking to the projects section.

    {% raw %}
    {% extends "base.html" %}
    {% block content %}
    

    Hi, I'm {{ name }} – Full‑Stack Developer

    {{ tagline }}

    View My Work
    {% endblock %} {% endraw %}

    2. About Page

    Include a brief bio, a list of technical skills, and a downloadable résumé. Use semantic HTML tags (<section>, <article>) to help search engines understand the content hierarchy.

    {% raw %}
    

    Technical Skills

    • Python & Flask
    • JavaScript, React
    • SQL & NoSQL databases
    • Docker & CI/CD
    {% endraw %}

    3. Projects Gallery

    Showcase each project with a thumbnail, short description, tech stack badges, and a link to the live demo or GitHub repo. Store project data in a simple SQLite table for easy updates.

    # models.py
    class Project(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        title = db.Column(db.String(120), nullable=False)
        description = db.Column(db.Text, nullable=False)
        image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
        demo_url = db.Column(db.String(200))
        repo_url = db.Column(db.String(200))
        tech_stack = db.Column(db.String(200))  # comma‑separated list
    

    4. Contact Form

    Use Flask-WTF to create a secure contact form that sends messages via Flask-Mail. Adding a reCAPTCHA widget helps prevent spam and improves SEO trust signals.

    # forms.py
    class ContactForm(FlaskForm):
        name = StringField('Name', validators=[DataRequired(), Length(max=50)])
        email = StringField('Email', validators=[DataRequired(), Email()])
        message = TextAreaField('Message', validators=[DataRequired(), Length(max=500)])
        submit = SubmitField('Send')
    

    Adding a Database for Dynamic Content

    While a static JSON file works for a tiny portfolio, a relational database lets you edit projects without touching code. Here’s a quick setup using Flask‑SQLAlchemy and Flask‑Migrate:

    # __init__.py
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    from flask_migrate import Migrate
    
    db = SQLAlchemy()
    migrate = Migrate()
    
    def create_app():
        app = Flask(__name__)
        app.config.from_object('config.Config')
        db.init_app(app)
        migrate.init_app(app, db)
    
        with app.app_context():
            from . import routes, models
            return app
    

    Run migrations with:

    flask db init
    flask db migrate -m "Create project table"
    flask db upgrade

    SEO Optimization Tips for a Flask Portfolio

    Flask gives you full control over the HTML rendered for each page, which is a huge advantage for search‑engine optimization. Implement the following best practices:

    • Meta tags: Include <title>, meta description, canonical, and Open Graph tags in the base.html template.
    • Semantic HTML: Use headings (h2, h3), section, article, and nav elements to convey structure.
    • Responsive design: Leverage CSS Grid or Flexbox; Google favors mobile‑friendly sites.
    • Image optimization: Serve WebP images, add alt attributes, and use srcset for different resolutions.
    • Fast loading: Minify CSS/JS, enable gzip compression in Flask with Flask-Compress, and set proper cache headers.
    • Structured data: Add JSON‑LD for Person and WebSite schema to improve rich‑snippet visibility.

    Example of a meta block in base.html:

    {% raw %}
    
        {% block title %}My Portfolio{% endblock %}
        
        
        
        
        
        
        
        
        
        
        
    
    {% endraw %}

    Deploying Your Flask Portfolio

    Once the site is polished locally, you’ll want to share it with the world. Here’s a concise deployment checklist:

    1. Choose a host: Platforms like Heroku, <
  • Python Flask File Upload Security Guide

    File uploads are a common feature in modern web applications, but they also introduce a high‑risk attack surface if not handled correctly. In the Python Flask ecosystem, developers often focus on getting the upload functionality working before thinking about security—only to discover later that a single malicious file can compromise the entire server. This guide walks you through best‑practice techniques, code snippets, and real‑world tips to secure file uploads in Flask, helping you protect your app, your users, and your reputation.

    Why File Upload Security Matters in Flask

    Flask gives you the flexibility to accept files with just a few lines of code, but that flexibility can be a double‑edged sword. Attackers can exploit insecure uploads to:

    • Execute arbitrary code on the server (e.g., uploading a .py script).
    • Overwrite existing files and trigger path traversal attacks.
    • Inject malicious content that is later served to other users (XSS, malware).
    • Consume server resources with large or numerous files (Denial‑of‑Service).

    Addressing these threats from the start ensures compliance with security standards such as OWASP Top 10 and reduces costly remediation later.

    Core Principles for Secure File Uploads

    1. Validate the File Type, Not Just the Extension

    Relying solely on file extensions (e.g., .jpg, .png) is unsafe because an attacker can rename a malicious script with a harmless extension. Instead, inspect the file’s MIME type and, when possible, its actual content.

    import imghdr
    
    def is_allowed_image(file_stream):
        header = file_stream.read(512)
        file_stream.seek(0)  # Reset pointer after reading
        fmt = imghdr.what(None, header)
        return fmt in {'jpeg', 'png', 'gif'}
    

    2. Enforce a Strict Whitelist

    Maintain a whitelist of allowed MIME types and extensions. Anything not explicitly permitted should be rejected.

    ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
    ALLOWED_MIME_TYPES = {'image/png', 'image/jpeg', 'image/gif'}
    
    def allowed_file(filename, mimetype):
        ext = filename.rsplit('.', 1)[1].lower() if '.' in filename else ''
        return ext in ALLOWED_EXTENSIONS and mimetype in ALLOWED_MIME_TYPES
    

    3. Set a Reasonable File Size Limit

    Large uploads can exhaust memory or disk space. Flask’s MAX_CONTENT_LENGTH configuration stops oversized requests early.

    # Limit uploads to 2 MB
    app.config['MAX_CONTENT_LENGTH'] = 2 * 1024 * 1024
    

    4. Use Secure Filenames

    Never trust the original filename. Use werkzeug.utils.secure_filename to strip unsafe characters and then prepend a unique identifier (UUID, timestamp, or hash) to avoid collisions.

    import uuid
    from werkzeug.utils import secure_filename
    
    def generate_secure_filename(filename):
        ext = filename.rsplit('.', 1)[1].lower()
        unique_name = f"{uuid.uuid4().hex}.{ext}"
        return secure_filename(unique_name)
    

    5. Store Files Outside the Web Root

    Placing uploaded files in a directory that is not directly served by Flask prevents accidental execution. Serve them via a dedicated route that checks permissions before sending the file.

    UPLOAD_FOLDER = '/var/www/app/uploads'  # Not under static/
    app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
    

    Step‑by‑Step Implementation in Flask

    Step 1: Configure the Application

    from flask import Flask
    
    app = Flask(__name__)
    app.config.update(
        MAX_CONTENT_LENGTH=5 * 1024 * 1024,   # 5 MB limit
        UPLOAD_FOLDER='/opt/myapp/uploads',
        SECRET_KEY='your-secret-key'          # Needed for session protection
    )
    

    Step 2: Create the Upload Form (HTML)

    Use the enctype="multipart/form-data" attribute and limit the accepted MIME types on the client side as a usability aid (never rely on it for security).

    <form method="POST" action="/upload" enctype="multipart/form-data">
        <input type="file" name="file" accept="image/png, image/jpeg, image/gif" required>
        <button type="submit">Upload</button>
    </form>
    

    Step 3: Handle the Upload in a Flask View

    from flask import request, abort, send_from_directory, jsonify
    import os
    
    @app.route('/upload', methods=['POST'])
    def upload_file():
        # 1️⃣ Ensure a file part is present
        if 'file' not in request.files:
            abort(400, description='No file part in the request')
        
        file = request.files['file']
        
        # 2️⃣ Reject empty submissions
        if file.filename == '':
            abort(400, description='No selected file')
        
        # 3️⃣ Validate file type and size
        if not allowed_file(file.filename, file.mimetype):
            abort(400, description='File type not allowed')
        
        # Optional: deeper content inspection (e.g., image verification)
        if not is_allowed_image(file.stream):
            abort(400, description='File content does not match its type')
        
        # 4️⃣ Secure the filename and save
        filename = generate_secure_filename(file.filename)
        save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        file.save(save_path)
        
        # 5️⃣ Respond with a safe reference
        return jsonify({'message': 'Upload successful', 'file_id': filename}), 201
    

    Step 4: Serve Uploaded Files Safely

    Instead of exposing the upload directory directly, create a protected endpoint that checks authentication and authorization before sending the file.

    @app.route('/files/<filename>')
    def serve_file(filename):
        # Example: ensure the user is logged in
        if not session.get('user_id'):
            abort(401)
        
        # Verify the filename is within the allowed directory
        safe_path = os.path.abspath(app.config['UPLOAD_FOLDER'])
        requested_path = os.path.abspath(os.path.join(safe_path, filename))
        
        if not requested_path.startswith(safe_path):
            abort(403)
        
        return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
    

    Advanced Security Enhancements

    1. Virus Scanning Integration

    Integrate ClamAV or another antivirus engine to scan each upload before saving it.

    import subprocess
    
    def scan_file(path):
        result = subprocess.run(['clamscan', '--no-summary', path],
                                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        return result.returncode == 0  # 0 = clean
    

    2. Content‑Disposition Header

    Force browsers to download files instead of rendering them, reducing the risk of XSS when serving user‑generated content.

    return send_from_directory(
        app.config['UPLOAD_FOLDER'],
        filename,
        as_attachment=True,
        attachment_filename=filename
    )
    

    3. Rate Limiting and Throttling

    Use Flask‑Limiter to prevent abuse by limiting the number of uploads per IP address.

    from flask_limiter import Limiter
    from flask_limiter.util import get_remote_address
    
    limiter = Limiter(app, key_func=get_remote_address)
    
    @app.route('/upload', methods=['POST'])
    @limiter.limit('5/minute')
    def upload_file():
        # existing upload logic...
        pass
    

    4. Use a Dedicated Storage Service

    Offload uploads to Amazon S3, Google Cloud Storage, or Azure Blob Storage. These services provide built‑in virus scanning, encryption at rest, and fine‑grained access control. When using S3, generate pre‑signed URLs so the Flask app never touches the raw file data.

    Common Pitfalls and How to Avoid Them

    • Skipping MIME validation: Attackers can spoof the Content-Type header; always double‑check the file content.
    • Saving files with original names: This opens path traversal and name‑collision risks. Always rename.
    • Storing uploads in static/: Directly serving from the static folder can execute scripts if the server misconfigures MIME handling.
    • Ignoring error handling: Use Flask’s abort() with clear messages and appropriate HTTP status codes to avoid leaking internal details.
    • Neglecting authentication on download routes: Public download endpoints can expose sensitive files to unauthenticated users.

    Testing Your Upload Security

    1. Static analysis: Run bandit or pylint to catch insecure patterns.
    2. Dynamic testing: Use OWASP ZAP or Burp Suite to attempt file upload bypasses, oversized files, and path traversal.
    3. Unit tests: Write pytest cases that feed malicious payloads (e.g., PHP shells renamed as .jpg) and assert a 400 response.
    4. Fuzzing: Employ tools like afl to generate random file streams and ensure your validation never crashes.

    SEO Tips for This Guide

    To make this article rank well for queries such as “Python Flask file upload security guide”, include the target keyword naturally throughout the headings, meta‑description (if you add one later), and body text. Use variations like “secure file uploads in Flask

  • Python Flask Blog Application Tutorial

    Welcome to the ultimate Python Flask blog application tutorial! In this step‑by‑step guide, you’ll learn how to turn a simple idea into a fully functional, SEO‑friendly blog using Flask, SQLAlchemy, and Jinja2. Whether you’re a beginner looking for a hands‑on project or a seasoned developer who wants a quick starter template, this tutorial covers everything from environment setup to deployment, ensuring your blog not only works flawlessly but also ranks well in search engines.

    Prerequisites: What You Need Before You Start

    Technical requirements

    • Python 3.9+ installed on your machine.
    • Basic knowledge of HTML, CSS, and Python.
    • A code editor (VS Code, PyCharm, or Sublime Text).
    • Git for version control (optional but recommended).

    Software dependencies

    We’ll use the following Python packages, all of which can be installed via pip:

    • Flask – the micro‑framework that powers the web app.
    • Flask‑SQLAlchemy – ORM for handling the database.
    • Flask‑Migrate – database migration tool.
    • Flask‑Login – simple user authentication.
    • python‑dotenv – to manage environment variables securely.

    Project Setup: Laying the Foundation

    1. Create a project directory

    mkdir flask_blog
    cd flask_blog

    2. Set up a virtual environment

    python -m venv venv
    source venv/bin/activate  # On Windows use: venv\Scripts\activate

    3. Install required packages

    pip install Flask Flask-SQLAlchemy Flask-Migrate Flask-Login python-dotenv

    4. Initialize Git (optional)

    git init
    git add .
    git commit -m "Initial commit – project scaffold"

    Building the Core Features

    Database model with SQLAlchemy

    First, create a models.py file to define the Post and User tables. Use descriptive column names and add indexes for SEO‑relevant fields like title and slug.

    from datetime import datetime
    from flask_sqlalchemy import SQLAlchemy
    from werkzeug.security import generate_password_hash, check_password_hash
    
    db = SQLAlchemy()
    
    class User(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(80), unique=True, nullable=False, index=True)
        email = db.Column(db.String(120), unique=True, nullable=False, index=True)
        password_hash = db.Column(db.String(128), nullable=False)
    
        def set_password(self, password):
            self.password_hash = generate_password_hash(password)
    
        def check_password(self, password):
            return check_password_hash(self.password_hash, password)
    
    class Post(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        title = db.Column(db.String(150), nullable=False, index=True)
        slug = db.Column(db.String(150), unique=True, nullable=False, index=True)
        body = db.Column(db.Text, nullable=False)
        created_at = db.Column(db.DateTime, default=datetime.utcnow)
        author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    
        author = db.relationship('User', backref=db.backref('posts', lazy=True))

    Routes and views

    Next, create routes.py. Keep URLs clean and keyword‑rich – a key SEO practice.

    from flask import Blueprint, render_template, request, redirect, url_for, flash
    from flask_login import login_user, logout_user, login_required, current_user
    from .models import db, User, Post
    
    blog = Blueprint('blog', __name__)
    
    @blog.route('/')
    def index():
        posts = Post.query.order_by(Post.created_at.desc()).all()
        return render_template('index.html', posts=posts)
    
    @blog.route('/post/')
    def post_detail(slug):
        post = Post.query.filter_by(slug=slug).first_or_404()
        return render_template('post_detail.html', post=post)
    
    @blog.route('/create', methods=['GET', 'POST'])
    @login_required
    def create_post():
        if request.method == 'POST':
            title = request.form['title']
            slug = request.form['slug']
            body = request.form['body']
            new_post = Post(title=title, slug=slug, body=body, author=current_user)
            db.session.add(new_post)
            db.session.commit()
            flash('Post created successfully!', 'success')
            return redirect(url_for('blog.post_detail', slug=slug))
        return render_template('create_post.html')

    Templates with Jinja2

    Store HTML files in a templates folder. Use semantic tags (<article>, <header>, <section>) and include meta tags for SEO.

    <!-- templates/index.html -->
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>My Flask Blog – Home</title>
        <meta name="description" content="A Python Flask blog featuring tutorials, tips, and personal stories.">
    </head>
    <body>
        <h1>Welcome to My Flask Blog</h1>
        {% for post in posts %}
        <article>
            <h2><a href="{{ url_for('blog.post_detail', slug=post.slug) }}">{{ post.title }}</a></h2>
            <p>{{ post.body[:200] }}...</p>
            <footer>
                <small>Posted on {{ post.created_at.strftime('%B %d, %Y') }} by {{ post.author.username }}</small>
            </footer>
        </article>
        {% else %}
        <p>No posts yet. Stay tuned!</p>
        {% endfor %}
    </body>
    </html>

    Adding User Authentication

    Configure Flask‑Login

    In auth.py, set up login, logout, and registration routes. Use flash messages for better UX and include next parameter handling for redirects after login.

    from flask import Blueprint, render_template, redirect, url_for, flash, request
    from flask_login import login_user, logout_user, login_required, current_user
    from .models import db, User
    
    auth = Blueprint('auth', __name__)
    
    @auth.route('/register', methods=['GET', 'POST'])
    def register():
        if request.method == 'POST':
            username = request.form['username']
            email = request.form['email']
            password = request.form['password']
            if User.query.filter_by(email=email).first():
                flash('Email already registered.', 'danger')
                return redirect(url_for('auth.register'))
            user = User(username=username, email=email)
            user.set_password(password)
            db.session.add(user)
            db.session.commit()
            flash('Registration successful! Please log in.', 'success')
            return redirect(url_for('auth.login'))
        return render_template('register.html')
    
    @auth.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == 'POST':
            email = request.form['email']
            password = request.form['password']
            user = User.query.filter_by(email=email).first()
            if user and user.check_password(password):
                login_user(user)
                next_page = request.args.get('next')
                return redirect(next_page or url_for('blog.index'))
            flash('Invalid credentials.', 'danger')
        return render_template('login.html')
    
    @auth.route('/logout')
    @login_required
    def logout():
        logout_user()
        flash('You have been logged out.', 'info')
        return redirect(url_for('blog.index'))

    Protect routes

    Apply @login_required to any view that creates, edits, or deletes posts. This not only secures the app but also improves crawlability by keeping public pages clean.

    Search Engine Optimization (SEO) Best Practices

    Key on‑page elements

    • Title tags: Include primary keywords like “Python Flask blog tutorial”.
    • Meta description: Write a concise, compelling description (150‑160 characters).
    • Header hierarchy: Use <h2> for sections and <h3> for subsections – search engines read this structure.
  • Python Flask User Authentication System

    Building a secure user authentication system is the cornerstone of any modern web application, and Flask makes it surprisingly straightforward. In this guide you’ll learn how to create a full‑featured authentication flow—from registration and login to protected routes and password hashing—using pure Python, Flask extensions, and best‑in‑class security practices. Whether you’re a beginner looking for a step‑by‑step tutorial or an experienced developer polishing a production‑ready solution, this article covers everything you need to know to implement a robust Flask user authentication system.

    Why Flask Is Ideal for Custom Authentication

    Flask is a lightweight micro‑framework that gives you full control over the components you add. This flexibility means you can start with a simple username/password login and later extend it with OAuth, JWT, or multi‑factor authentication without rewriting the core logic. Moreover, Flask’s extensive ecosystem—including Flask‑Login, Flask‑WTF, and Flask‑Bcrypt—provides battle‑tested building blocks that keep your code clean and secure.

    Project Setup: Getting the Basics Right

    1. Create a virtual environment

    python -m venv venv
    source venv/bin/activate   # On Windows use `venv\Scripts\activate`
    

    2. Install required packages

    pip install Flask Flask-Login Flask-WTF Flask-Bcrypt Flask-SQLAlchemy
    

    3. Directory layout

    • app.py – main application entry point
    • models.py – database models
    • forms.py – WTForms definitions
    • templates/ – HTML templates (login.html, register.html, dashboard.html)
    • static/ – CSS and JavaScript assets

    Defining the User Model with SQLAlchemy

    The user model stores essential information such as the username, email, and a securely hashed password. Using Flask‑Bcrypt ensures passwords are never saved in plain text.

    from flask_sqlalchemy import SQLAlchemy
    from flask_bcrypt import Bcrypt
    
    db = SQLAlchemy()
    bcrypt = Bcrypt()
    
    class User(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(150), unique=True, nullable=False)
        email = db.Column(db.String(150), unique=True, nullable=False)
        password_hash = db.Column(db.String(60), nullable=False)
    
        def set_password(self, password):
            self.password_hash = bcrypt.generate_password_hash(password).decode('utf-8')
    
        def check_password(self, password):
            return bcrypt.check_password_hash(self.password_hash, password)
    
        # Required by Flask-Login
        def get_id(self):
            return str(self.id)
    

    Integrating Flask‑Login for Session Management

    Flask‑Login handles user session tracking, “remember me” functionality, and protects routes with a simple decorator. First, initialize the extension in app.py:

    from flask import Flask
    from flask_login import LoginManager
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'your‑strong‑secret‑key'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
    
    db.init_app(app)
    bcrypt.init_app(app)
    
    login_manager = LoginManager()
    login_manager.login_view = 'login'          # Redirect unauthenticated users
    login_manager.login_message_category = 'info'
    login_manager.init_app(app)
    
    @login_manager.user_loader
    def load_user(user_id):
        return User.query.get(int(user_id))
    

    Creating Registration and Login Forms with Flask‑WTF

    from flask_wtf import FlaskForm
    from wtforms import StringField, PasswordField, SubmitField, BooleanField
    from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
    from models import User
    
    class RegistrationForm(FlaskForm):
        username = StringField('Username', validators=[DataRequired(), Length(min=3, max=20)])
        email = StringField('Email', validators=[DataRequired(), Email()])
        password = PasswordField('Password', validators=[DataRequired(), Length(min=6)])
        confirm_password = PasswordField('Confirm Password',
                                         validators=[DataRequired(), EqualTo('password')])
        submit = SubmitField('Sign Up')
    
        def validate_username(self, username):
            if User.query.filter_by(username=username.data).first():
                raise ValidationError('That username is already taken.')
    
        def validate_email(self, email):
            if User.query.filter_by(email=email.data).first():
                raise ValidationError('An account with this email already exists.')
    
    class LoginForm(FlaskForm):
        email = StringField('Email', validators=[DataRequired(), Email()])
        password = PasswordField('Password', validators=[DataRequired()])
        remember = BooleanField('Remember Me')
        submit = SubmitField('Login')
    

    Registration Route: Storing a Secure Password

    from flask import render_template, redirect, url_for, flash, request
    from flask_login import login_user, current_user
    from models import User, db
    from forms import RegistrationForm
    
    @app.route('/register', methods=['GET', 'POST'])
    def register():
        if current_user.is_authenticated:
            return redirect(url_for('dashboard'))
    
        form = RegistrationForm()
        if form.validate_on_submit():
            user = User(username=form.username.data,
                        email=form.email.data)
            user.set_password(form.password.data)
            db.session.add(user)
            db.session.commit()
            flash('Your account has been created! You can now log in.', 'success')
            return redirect(url_for('login'))
        return render_template('register.html', form=form)
    

    Login Route: Verifying Credentials

    from flask_login import login_user, logout_user, login_required
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if current_user.is_authenticated:
            return redirect(url_for('dashboard'))
    
        form = LoginForm()
        if form.validate_on_submit():
            user = User.query.filter_by(email=form.email.data).first()
            if user and user.check_password(form.password.data):
                login_user(user, remember=form.remember.data)
                next_page = request.args.get('next')
                flash('Logged in successfully.', 'success')
                return redirect(next_page) if next_page else redirect(url_for('dashboard'))
            else:
                flash('Login failed. Check email and password.', 'danger')
        return render_template('login.html', form=form)
    

    Protecting Views with the @login_required Decorator

    Any route that should be accessible only to authenticated users can be wrapped with @login_required. For example, a simple dashboard:

    @app.route('/dashboard')
    @login_required
    def dashboard():
        return render_template('dashboard.html')
    

    Logout Endpoint

    @app.route('/logout')
    @login_required
    def logout():
        logout_user()
        flash('You have been logged out.', 'info')
        return redirect(url_for('login'))
    

    Optional: JSON Web Tokens (JWT) for API Authentication

    If you need token‑based authentication for a RESTful API, PyJWT or Flask-JWT-Extended can be added without disturbing the session‑based flow.

    1. Install the extension: pip install Flask-JWT-Extended
    2. Configure a secret key and token expiration.
    3. Create login endpoint that returns access_token and refresh_token.
    4. Protect API routes with @jwt_required().

    Using JWT keeps your API stateless and works well with mobile clients or single‑page applications.

    Security Best Practices You Should Never Skip

    • Use HTTPS in production to encrypt credentials in transit.
    • Store only password hashes—never raw passwords. Bcrypt with a work factor of at least 12 is recommended.
    • Implement rate limiting (e.g., Flask‑Limiter) to mitigate brute‑force attacks.
    • Validate and sanitize user input using WTForms validators to prevent injection attacks.
    • Enable CSRF protection—Flask‑WTF does this automatically for form submissions.
    • Set secure cookie flags (Secure, HttpOnly, SameSite) via Flask’s session configuration.
    • Use a strong secret key and rotate it periodically.

    Testing Your Authentication Flow

    Before deploying, run a quick sanity check:

    1. Register a new user and verify the entry appears in the database with a hashed password.
    2. Attempt to log in with correct and incorrect credentials to ensure flash messages behave as expected.
    3. Navigate directly to /dashboard while logged out—Flask‑Login should redirect you to the login page.
    4. Use tools like Postman or curl to test JWT endpoints if you implemented them.

    Deploying to Production

    When you’re ready to go live, follow these deployment tips:

    • Run the app behind a WSGI server such as Gunicorn or uWSGI.
    • Set SESSION_COOKIE_SECURE = True
  • Python Flask Rest Api With Sqlalchemy

    Building a modern web service often starts with a clear, maintainable API that can talk to a database efficiently. Python Flask paired with SQLAlchemy offers exactly that: a lightweight framework for routing HTTP requests and a powerful ORM for handling relational data. In this guide we’ll walk through every step needed to create a production‑ready REST API using Flask and SQLAlchemy, from project setup to testing and deployment. Whether you’re a beginner eager to see a working example or a seasoned developer looking for best‑practice tips, this tutorial has you covered.

    Why Choose Flask and SQLAlchemy for a REST API?

    Before diving into code, it’s worth understanding the advantages that make Flask + SQLAlchemy a popular stack for RESTful services:

    • Minimalistic core: Flask provides just the essentials—routing, request handling, and extensions—so you stay in control of your architecture.
    • Extensible ecosystem: Extensions like Flask‑RESTful, Flask‑Migrate, and Flask‑JWT‑Extended add features without bloat.
    • SQLAlchemy’s ORM: Write Python classes instead of raw SQL, enjoy automatic schema migrations, and benefit from a database‑agnostic layer.
    • Great community and documentation: Both projects have extensive tutorials, Stack Overflow answers, and production‑grade examples.

    Project Structure

    A clean folder layout helps you scale the API as it grows. Below is a recommended structure for a Flask‑SQLAlchemy project:

    my_flask_api/
    │
    ├── app/
    │   ├── __init__.py        # Flask app factory
    │   ├── models.py          # SQLAlchemy models
    │   ├── resources.py       # API endpoint definitions
    │   ├── schemas.py         # Marshmallow schemas (optional)
    │   └── config.py          # Configuration settings
    │
    ├── migrations/            # Alembic migration scripts
    │
    ├── tests/
    │   └── test_api.py
    │
    ├── venv/                  # Virtual environment (optional)
    ├── requirements.txt
    └── run.py                 # Entry point
    

    Step‑by‑Step Implementation

    1. Set Up the Development Environment

    First, create a virtual environment and install the required packages.

    python -m venv venv
    source venv/bin/activate   # On Windows: venv\Scripts\activate
    pip install Flask Flask‑SQLAlchemy Flask‑RESTful Flask‑Migrate Flask‑JWT‑Extended marshmallow
    pip freeze > requirements.txt
    

    2. Create the Flask Application Factory

    Using an application factory makes testing and configuration easier.

    # app/__init__.py
    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    from flask_migrate import Migrate
    from flask_restful import Api
    from flask_jwt_extended import JWTManager
    
    db = SQLAlchemy()
    migrate = Migrate()
    jwt = JWTManager()
    
    def create_app(config_object='app.config.Config'):
        app = Flask(__name__)
        app.config.from_object(config_object)
    
        # Initialize extensions
        db.init_app(app)
        migrate.init_app(app, db)
        jwt.init_app(app)
    
        # Register API resources
        api = Api(app)
        from .resources import UserListResource, UserResource
        api.add_resource(UserListResource, '/api/users')
        api.add_resource(UserResource, '/api/users/<int:user_id>')
    
        return app
    

    3. Define Configuration Settings

    Keep secret keys and database URLs out of source control.

    # app/config.py
    import os
    
    class Config:
        SECRET_KEY = os.getenv('SECRET_KEY', 'super-secret-key')
        SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL', 'sqlite:///app.db')
        SQLALCHEMY_TRACK_MODIFICATIONS = False
        JWT_SECRET_KEY = os.getenv('JWT_SECRET_KEY', 'jwt-secret-key')
    

    4. Model Your Data with SQLAlchemy

    Below is a simple User model that includes password hashing using werkzeug.security.

    # app/models.py
    from . import db
    from werkzeug.security import generate_password_hash, check_password_hash
    
    class User(db.Model):
        __tablename__ = 'users'
    
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(80), unique=True, nullable=False)
        email = db.Column(db.String(120), unique=True, nullable=False)
        password_hash = db.Column(db.String(128), nullable=False)
    
        def set_password(self, password):
            self.password_hash = generate_password_hash(password)
    
        def check_password(self, password):
            return check_password_hash(self.password_hash, password)
    
        def to_dict(self):
            return {
                'id': self.id,
                'username': self.username,
                'email': self.email
            }
    

    5. Create Marshmallow Schemas (Optional but Recommended)

    Marshmallow handles serialization and validation cleanly.

    # app/schemas.py
    from marshmallow import Schema, fields, validate
    
    class UserSchema(Schema):
        id = fields.Int(dump_only=True)
        username = fields.Str(required=True, validate=validate.Length(min=3))
        email = fields.Email(required=True)
        password = fields.Str(load_only=True, required=True, validate=validate.Length(min=6))
    

    6. Implement RESTful Resources

    Using Flask‑RESTful, define endpoints for CRUD operations.

    # app/resources.py
    from flask import request, jsonify
    from flask_restful import Resource
    from flask_jwt_extended import jwt_required, create_access_token
    from . import db
    from .models import User
    from .schemas import UserSchema
    
    user_schema = UserSchema()
    users_schema = UserSchema(many=True)
    
    class UserListResource(Resource):
        @jwt_required()
        def get(self):
            users = User.query.all()
            return users_schema.dump(users), 200
    
        def post(self):
            data = request.get_json()
            errors = user_schema.validate(data)
            if errors:
                return errors, 400
    
            user = User(
                username=data['username'],
                email=data['email']
            )
            user.set_password(data['password'])
            db.session.add(user)
            db.session.commit()
            return user_schema.dump(user), 201
    
    class UserResource(Resource):
        @jwt_required()
        def get(self, user_id):
            user = User.query.get_or_404(user_id)
            return user_schema.dump(user), 200
    
        @jwt_required()
        def put(self, user_id):
            user = User.query.get_or_404(user_id)
            data = request.get_json()
            errors = user_schema.validate(data, partial=True)
            if errors:
                return errors, 400
    
            if 'username' in data:
                user.username = data['username']
            if 'email' in data:
                user.email = data['email']
            if 'password' in data:
                user.set_password(data['password'])
    
            db.session.commit()
            return user_schema.dump(user), 200
    
        @jwt_required()
        def delete(self, user_id):
            user = User.query.get_or_404(user_id)
            db.session.delete(user)
            db.session.commit()
            return {'message': 'User deleted'}, 204
    
    class AuthResource(Resource):
        def post(self):
            data = request.get_json()
            user = User.query.filter_by(username=data.get('username')).first()
            if user and user.check_password(data.get('password')):
                access_token = create_access_token(identity=user.id)
                return {'access_token': access_token}, 200
            return {'message': 'Invalid credentials'}, 401
    

    7. Register the Authentication Endpoint

    Add the auth route in create_app:

    # Inside app/__init__.py, after other resources
    from .resources import AuthResource
    api.add_resource(AuthResource, '/api/auth')
    

    8. Run Database Migrations

    Initialize Alembic and generate the first migration.

    flask db init
    flask db migrate -m "Create users table"
    flask db upgrade
    

    9. Create the Entry Point

    The run.py file boots the application.

    # run.py
    from app import create_app
    
    app = create_app()
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    Testing the API

    Automated tests ensure your API behaves as expected. Below is a minimal pytest example using Flask’s test client.

    # tests/test_api.py
    import json
    import pytest
    from app import create_app, db
    from app.models import User
    
    @pytest.fixture
    def client():
        app = create_app('app.config.Config')
        app.config['TESTING'] = True
        app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
    
        with app.test_client() as client:
            with app.app_context():
                db.create_all()
                # Create a test user
                user = User(username='tester', email='test@example.com')
                user.set_password('password123')
                db.session.add(user)
                db.session.commit()
            yield client
            with app.app_context():
                db.drop_all()
    
    def get_token(client):
        response = client.post('/api/auth', json={'username': 'tester', 'password': 'password123'})
        return json.loads(response.data)['access_token']
    
    def test_get_users(client):
        token = get_token(client)
        resp = client.get('/api/users', headers={'Authorization': f'Bearer {token}'})
        assert resp.status_code == 200
        data = json.loads(resp.data)
        assert isinstance(data, list)
    

    Best Practices for Production‑Ready APIs

    • <