Code

Fastapi - Ratelimiting

Fastapi & Rate Limiting

Let’s test a simple Rate Limiting Function found on the Net …

main.py

Main App with Rate Limiting Function

# main.py
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
from Token_bucket import TokenBucket

app = FastAPI()

class RateLimiterMiddleware(BaseHTTPMiddleware):
    def __init__(self, app, bucket: TokenBucket):
        super().__init__(app)
        self.bucket = bucket

    async def dispatch(self, request: Request, call_next):
        if self.bucket.take_token():
            return await call_next(request)

        # Return a JSON response for rate limit exceeded
        return JSONResponse(status_code=429, content={"detail": "Rate limit exceeded"})

# Token bucket with a capacity of 3 and refill rate of 1 token per second
bucket = TokenBucket(capacity=3, refill_rate=3)

# Apply the rate limiter middleware
app.add_middleware(RateLimiterMiddleware, bucket=bucket)

@app.get("/")
async def read_root():
    return {"message": "Hello World"}

Token_bucket.py

# Token_bucket.py
import time

class TokenBucket:
    def __init__(self, capacity, refill_rate):
        self.capacity = capacity
        self.refill_rate = refill_rate
        self.tokens = capacity
        self.last_refill = time.time()

    def add_tokens(self):
        now = time.time()
        if self.tokens < self.capacity:
            tokens_to_add = (now - self.last_refill) * self.refill_rate
            self.tokens = min (self.capacity, self.tokens + tokens_to_add)
        self.last_refill=now

    def take_token(self):
        self.add_tokens()
        if self.tokens >= 1:
            self.tokens -=1
            return True
        return False

Test Script

Let’s produce some requests …

HTML - Center Div

3 Ways to Center a < div >

Credits to https://twitter.com/BilliCodes

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Centering a Div - Three Methods</title>
    <style>
        .container {
            height: 100vh; /* Full height */
            position: relative; /* Required for absolute positioning */
            background-color: #f0f0f0;
        }

        /* (1) Flexbox Method */
        .flexbox {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh; /* Full viewport height */
        }

        /* (2) Grid Method */
        .grid {
            display: grid;
            place-items: center; /* Center using grid */
            height: 100vh; /* Full viewport height */
        }

        /* (3) Absolute Positioning Method */
        .absolute {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%); /* Offset to center */
        }      
    </style>
</head>

<body>
    <div class="container">
        <!-- Flexbox Method -->
        <div class="centered flexbox">Centered with Flexbox</div>

        <!-- Grid Method -->
        <div class="centered grid">Centered with CSS Grid</div>
        
        <!-- Absolute Positioning Method -->
        <div class="centered absolute">Centered with Absolute Positioning</div>
    </div>
</body>

</html>

Any Comments ?

sha256: 85678db9aeded3bf6ba6bce5bf56014023c834cdd99b62f0d8427f3c12a65360

Python - Decorator

how to use Python Decorator

Sample Code

main.py

cat << 'EOF' > main.py
#!/usr/bin/env python3

# Sample from https://blog.stoege.net/posts/python_decorator/

# Vars
a = 3
b = 8

# Decorator which logs start and end of a function
def log_function_call(func):
    def wrapper(*args, **kwargs):
        print(f"\nCalling function '{func.__name__}' with {args=} & {kwargs=}")
        result = func(*args, **kwargs)
        print(f"Function '{func.__name__}' finnished\n")
        return result
    return wrapper

@log_function_call
def add(a=int, b=int) -> int:
    result = a + b
    return result

@log_function_call
def sub(a=int, b=int) -> int:
    result = a - b
    return result

@log_function_call
def prod(a=int, b=int) -> int:
    result = a * b
    return result

@log_function_call
def div(a=int, b=int) -> int:
    result = a / b
    return result

if __name__ == "__main__":
    print("Result:", add(a, b))
    print("Result:", sub(a, b))
    print("Result:", prod(a, b))
    print("Result:", div(a, b))

EOF
chmod u+x main.py

##### RUN #####

# ./main.py

###############

Running Code

user@host% ./main.py 

Calling function 'add' with args=(3, 8) & kwargs={}
Function 'add' finnished

Result: 11

Calling function 'sub' with args=(3, 8) & kwargs={}
Function 'sub' finnished

Result: -5

Calling function 'prod' with args=(3, 8) & kwargs={}
Function 'prod' finnished

Result: 24

Calling function 'div' with args=(3, 8) & kwargs={}
Function 'div' finnished

Result: 0.375

Any Comments ?

sha256: ab6641b101cea8ac7eb6517fcefb029380644a56203723973fa1bc957fafbafb

Fastapi Project Template

Project Template for FastAPI

gave a try with a FastAPI Template, https://github.com/rochacbruno/fastapi-project-template.git

Projectname: gugus1234

clone the repo

git clone https://github.com/rochacbruno/fastapi-project-template.git gugus1234
cd gugus1234

Switch Poetry

i’d like to have poetry as virtual env manager

make switch-to-poetry

Rename some Stuff

had to rename some string in pyproject and different files …

mv project_name gugug1234
gsed -i 's/a-flask-test/gugus1234/' pyproject.toml
gsed -i 's/project_name/gugus1234/' pyproject.toml
gsed -i 's/project_name/gugus1234/g' gugus1234/cli.py gugus1234/app.py gugus1234/config.py gugus1234/security.py

Run Poetry once

poetry shell
poetry lock
poetry install

Admin User

let’s create admin user

Fastapi Simple Security

How to Protect your App with Simple Security

Let’s build a small API Endpoint with FastAPI and protect it with SimpleSecurity.

API key based security package for FastAPI, focused on simplicity of use:

  • Full functionality out of the box, no configuration required
  • API key security with local sqlite backend, working with both header and query parameters
  • Default 15 days deprecation for generated API keys
  • Key creation, revocation, renewing, and usage logs handled through administrator endpoints
  • No dependencies, only requiring FastAPI and the python standard library

Build new App

and show the Directory Structure

Dotnet - Hello World

Running a WebApp in 5min ?

ASP.NET Tutorial - Hello World in 5 minutes

in a Language you never touched before … ? a Microsoft App running on Linux running in Docker running on macOS … ?

Let’ give a try …

Fireup Ubuntu via Docker, do Port Forward

docker run -it -p 5123:5123 --name dotnet-hello ubuntu:latest

add basics

apt-get update && apt-get -y upgrade && apt-get -y install wget

add dotnet

wget https://packages.microsoft.com/config/ubuntu/22.10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
dpkg -i packages-microsoft-prod.deb && rm packages-microsoft-prod.deb
apt-get update && apt-get install -y dotnet-sdk-7.0
dotnet --version

build webapp

dotnet new webapp -o MyWebApp --no-https -f net7.0

run webapp, change IP & Port

cd MyWebApp
sed -i 's#"applicationUrl".*#"applicationUrl": "http://0.0.0.0:5123",#' Properties/launchSettings.json
dotnet watch

Hello World

Flask JWT - Sample

Flask & JWT

getting your hands dirty with Flask and JWT

Source

with some modifications by myself …

Environment

Test under macOS & OpenBSD, Poetry installed and working

Script

build virtual env

export app="app100"
export FLASK_APP="${app}/app"
poetry new ${app}
cd ${app}

set python 3.10

poetry env use $(which python3.10)
gsed -i "s/python = \"^3.*$/python = \"^3.10\"/" pyproject.toml
poetry lock

add packages

wget -4 -O requirements.txt https://raw.githubusercontent.com/GrahamMorbyDev/jwt-flask/master/requirements.txt
echo "marshmallow-sqlalchemy" >> requirements.txt
poetry add $(awk -F '==' '!/sha256/{print $1}' requirements.txt |tr '\n' ' ')
wget -4 -O ${app}/app.py https://raw.githubusercontent.com/GrahamMorbyDev/jwt-flask/master/app.py
poetry shell

create db

Fastapi

FastAPI - Dependencies and Custom Headers

Source

Code

from fastapi import Depends, FastAPI, Header, HTTPException

app = FastAPI()


async def verify_token(x_token: str = Header()):
    if x_token != "fake-super-secret-token":
        raise HTTPException(status_code=400, detail="X-Token header invalid")


async def verify_key(x_key: str = Header()):
    if x_key != "fake-super-secret-key":
        raise HTTPException(status_code=400, detail="X-Key header invalid")
    return x_key


@app.get("/items/", dependencies=[Depends(verify_token), Depends(verify_key)])
async def read_items():
    return [{"item": "Foo"}, {"item": "Bar"}]

Test’s

Failed

no Custom Header

curl -s http://localhost/api/items/ |jq
{
  "detail": [
    {
      "loc": [
        "header",
        "x-token"
      ],
      "msg": "field required",
      "type": "value_error.missing"
    },
    {
      "loc": [
        "header",
        "x-key"
      ],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}

adding “x-token”

VSCode

Let’s tweak a bit the settings …

settings.json

Useful Settings for VSCode … settings.json

test -d .vscode || mkdir .vscode
test -f .vscode/settings.json && mv .vscode/settings.json .vscode/settings.json-$(date +%s)
cat << 'EOF' > .vscode/settings.json
{
    "[python]": {
        "editor.defaultFormatter": "charliermarsh.ruff",
        "editor.formatOnSave": true,
        "editor.codeActionsOnSave": {
            "source.organizeImports": "explicit",
            "source.fixAll": true
        },
    },
}
EOF

pyproject.toml

[tool.ruff]
# Disable rule F401 for unused imports
ignore = ["F401"]

launch.json

test -d .vscode || mkdir .vscode
test -f .vscode/launch.json && mv .vscode/launch.json .vscode/launch.json-$(date +%s)
cat << 'EOF' > .vscode/launch.json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        // default config to debug your current active file with python
        {
            "name": "Python: Current File",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "justMyCode": true
        },
        {
            "name": "Python: Test001",
            "type": "python",
            "request": "launch",
            "program": "${workspaceFolder}/project/code.py",
            "args": [
                "arg1",
                "arg2",
                "arg3"
            ],
            "console": "integratedTerminal"
        },
        {
            "name": "Python: FastAPI",
            "type": "python",
            "request": "launch",
            "module": "uvicorn",
            "args": [
                "app.main:app",
                "--reload"
            ]
        },
        {
            "name": "Python: Flask",
            "type": "python",
            "request": "launch",
            "module": "flask",
            "args": [
                "run",
                "--reload"
            ]
        }
    ]
}
EOF

.gitignore

test -f .gitignore && mv .gitignore .gitignore-$(date +%s)
cat << EOF > .gitignore
# added $(date), https://blog.stoege.net/posts/vscode/

# Files
.DS_Store
backup.*
secret
secrets

# Folders
**/.DS_Store/*
**/.history/*
**/.terraform/*
**/.venv/*
**/__pycache__/*
**/cache/*
EOF

Add Basic Packages

poetry add --group dev black pylint py-pytest

keyboards shortcuts macOS

Comment block

command + k, command + u

Uncomment block

command + k, command + u

Collapse All

command + k, command + 0

Expand All

command + k, command + j

Export Extensions

code --list-extensions |xargs -L 1 echo code --install-extension |sed "s/$/ --force/"

import Extensions on another Machine