Skip to content

v1.0.1#9

Merged
SzaBee13 merged 14 commits intomainfrom
v/1.0.1
Apr 21, 2026
Merged

v1.0.1#9
SzaBee13 merged 14 commits intomainfrom
v/1.0.1

Conversation

@SzaBee13
Copy link
Copy Markdown
Contributor

@SzaBee13 SzaBee13 commented Apr 21, 2026

PrereleaseNotes

All notable changes to this project are documented in this file.

[v1.0.1] - 2026-04-21

Added

  • New Random endpoints:
    • GET /random/color
    • GET /random/gradient
    • GET /random/quote
    • GET /random/joke
    • GET /random/dad_joke
  • New Network endpoints:
    • GET /network/dns
    • GET /network/dns/reverse
    • GET /network/subnet_mask_to_cidr
    • GET /network/cidr_to_subnet_mask
    • GET /network/ip_range
    • GET /network/ip_range/recommended
  • API key management endpoints under auth:
    • POST /auth/api-keys
    • GET /auth/api-keys
    • DELETE /auth/api-keys/{key_uuid}
  • Structured app layers for config, routes, models, and services (src/config, src/routes, src/models, src/services) to support cleaner module boundaries and easier maintenance.
  • New test coverage for archive layout rules and module-level behavior (dev, network, random).

Changed

  • Reworked archive version layout: archive versions now contain only assets/, modules/, and routes/.
  • Updated archive mounting logic to load archived APIs from route modules instead of requiring archive-local app bootstrap files.
  • Added support for both archive/ and archives/ as archive roots at runtime.
  • Wired the main API app through dedicated route modules and expanded router registration for new feature groups.
  • Updated deployment/version routing defaults to v1.0.1 in Vercel redirects, including aliases from /v1 and /v1.0.
  • Expanded runtime dependencies for new capabilities (argon2-cffi, psycopg[binary], redis, numpy, dnspython).

Fixed

  • Improved HTTP status behavior for module responses that include explicit {"error": ..., "code": ...} payloads, so returned status codes now align with module error codes.
  • Improved repository test organization by splitting module tests by domain and removing the old aggregated module test file.

Security

  • Added API key hashing via Argon2 with optional pepper support (API_KEY_PEPPER).
  • Added Postgres-backed API key persistence with per-user active-key limits and key lifecycle metadata.
  • Kept stable unversioned OAuth callback/login/logout endpoints on the gateway to avoid redirect issues with external OAuth providers.

Notes

  • The latest API version is now v1.0.1.
  • Canonical endpoints remain versioned under /v1.0.1/*, while unversioned endpoints continue to redirect to the latest version.

- Added API key creation, listing, and deletion endpoints.
- Integrated Redis for rate limiting and PostgreSQL for persistent API key storage.
- Updated Docker configuration to include PostgreSQL and Redis services.
- Enhanced README with setup instructions and environment variables.
- Removed unused fake user data and added names.json for random identity generation.
- Updated requirements.txt to include new dependencies for Redis and PostgreSQL.
- Refactored middleware to support Redis-based rate limiting.
- Added tests for API key lifecycle and bearer authentication.
Copilot AI review requested due to automatic review settings April 21, 2026 13:11
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
free-api Ready Ready Preview, Comment Apr 21, 2026 4:15pm

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR bumps the project to v1.0.1 and restructures the app into clearer layers (config/routes/models/services), while adding new Random + Network endpoints, API key management, Redis-backed rate limiting, and a new archive layout/mounting strategy.

Changes:

  • Update version routing/redirects to v1.0.1 and rework gateway/archive mounting to load routers from archives/*/routes.
  • Add API key issuance/listing/deletion (Argon2 hashing + optional Postgres persistence) and bearer-token auth support.
  • Add Random/Network feature areas (routes + modules + assets) and reorganize tests + Docker configs.

Reviewed changes

Copilot reviewed 58 out of 62 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
vercel.json Redirect defaults updated to v1.0.1 + add /v1 and /v1.0 aliases.
tests/test_modules.py Removes old aggregated module tests.
tests/test_endpoints.py Updates/extends endpoint tests incl. API key lifecycle + bearer auth.
tests/test_archives_layout.py Adds test enforcing archive version directory layout.
tests/modules/random.py Adds a “module runner” script under tests (not a pytest test).
tests/modules/network.py Adds a “module runner” script under tests (not a pytest test).
tests/modules/dev.py Adds a “module runner” script under tests (not a pytest test).
src/services/random.py Adds parsing/validation helper for explicit content filters.
src/services/auth.py Adds require_authenticated_user() service helper.
src/services/init.py Exposes service helpers via package exports.
src/security.py Removes old monolithic security module (moved into src/config/security.py).
src/routes/uuid_hashing.py Adds UUID/hash routing module.
src/routes/text.py Adds text routing module.
src/routes/root.py Adds root/status/assets routing module.
src/routes/random.py Adds random routing module (color/gradient/quote/jokes).
src/routes/network.py Adds network routing module (DNS + subnet/IP range helpers).
src/routes/math.py Adds math routing module (incl. numeric system conversion endpoint).
src/routes/geo.py Adds geo routing module.
src/routes/datetime.py Adds datetime routing module.
src/routes/auth.py Adds auth routing module (OAuth + API key management).
src/routes/init.py Central router export/registration list.
src/modules/random.py Adds Random module implementation + loads random assets.
src/modules/network.py Adds Network module implementation (DNS, CIDR/subnet, IP ranges).
src/modules/math.py Adds numeric base conversion helper to math module.
src/modules/dev.py Adds “dev tools” module (regex/json helpers, diff, debug).
src/models/auth.py Adds request model for API key creation.
src/models/init.py Exposes auth models.
src/middleware/rate_limit.py Adds Redis-backed rate limiting fallbacking to in-memory.
src/middleware/docs_rate_limit.py Adds Redis-backed docs rate limiting fallbacking to in-memory.
src/main.py Refactors app wiring through routers; adds middleware for module error-code->HTTP status; rewrites archive loader + gateway redirect logic; adds unversioned auth endpoints on gateway.
src/logging.py Removes old logging module (moved into src/config/logging.py).
src/config/security.py Enhances auth (stable OAuth redirect URI + bearer token support + logging).
src/config/logging.py Adds config-scoped JSON logging setup.
src/config/config.py Adds Postgres URL builder + version/domain defaults + API key pepper config.
src/config/api_keys.py Adds API key hashing/storage/authentication (memory + Postgres).
src/config/init.py Exposes settings from config package.
src/assets/random/names.json Adds name/email provider dataset for Random identity.
src/assets/random/jokes.json Adds jokes dataset for Random joke endpoint.
src/assets/random/dad_jokes.json Adds dad jokes dataset.
src/assets/dev/regex.json Adds regex mapping asset for dev tools.
src/assets/dev/debug.json Adds debug responses/docs asset for dev tools.
requirements.txt Adds runtime deps for new features (argon2/psycopg/redis/numpy/dnspython).
docker/docker-compose.yml Adds Postgres + Redis services and wires env vars for the API.
docker/dev-docker-compose.yml Adds dev compose setup building locally with Postgres + Redis.
archives/v1.0.0/routes/uuid_hashing.py Adds archived router module for uuid/hashing.
archives/v1.0.0/routes/text.py Adds archived router module for text endpoints.
archives/v1.0.0/routes/root.py Adds archived router module for root/status/assets endpoints.
archives/v1.0.0/routes/math.py Adds archived router module for math endpoints.
archives/v1.0.0/routes/geo.py Adds archived router module for geo endpoints.
archives/v1.0.0/routes/datetime.py Adds archived router module for datetime endpoints.
archives/v1.0.0/routes/auth.py Adds archived router module for auth endpoints.
archives/v1.0.0/routes/init.py Exposes archived routers.
archives/v1.0.0/middleware/rate_limit.py Removes archived middleware (archive no longer ships app bootstrap).
archives/v1.0.0/middleware/docs_rate_limit.py Removes archived middleware (archive no longer ships app bootstrap).
archives/v1.0.0/main.py Removes archived bootstrap app (archive now router-only).
archives/v1.0.0/config.py Removes archived settings module (shared config now used).
archives/v1.0.0/init.py Removes archived package marker.
README.md Updates versioning + archive layout docs + Docker instructions + security notes.
.gitignore Adds .vercel to ignores.
.env.example Adds Redis/Postgres/API key env examples and guidance.
Comments suppressed due to low confidence (1)

tests/test_endpoints.py:35

  • These tests are hard-coded to v1.0.0 for redirects and versioned endpoints, but the PR sets the current version to 1.0.1 (and updates Vercel redirects accordingly). This will fail once FREEAPI_CURRENT_VERSION defaults to 1.0.1. Derive the version prefix from settings (or a shared constant) and update expected redirect locations/payload versions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/main.py
Comment on lines +191 to +197
# Ensure a package module exists so relative imports inside the archive work.
# Keep BASE_DIR as a fallback so shared modules like config/services/models can
# be reused without duplicating them inside each archive version.
if package_name not in sys.modules:
pkg = types.ModuleType(package_name)
pkg.__path__ = [str(version_dir), str(BASE_DIR)]
sys.modules[package_name] = pkg
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding BASE_DIR to the archive package __path__ means shared modules (e.g. config.api_keys, config.security) will be imported under the archive-specific module name (e.g. freeapi_archives.v1_0_0.config.api_keys) rather than the canonical src.config.api_keys. This creates duplicate module singletons (separate settings objects, separate _STORE API key stores, etc.) and can lead to inconsistent behavior between current and archived apps. Consider a different sharing strategy (e.g., require archives to import src.* explicitly, or provide a single shared package name for common code) to avoid double-loading shared modules.

Copilot uses AI. Check for mistakes.
Comment thread src/modules/random.py
Comment on lines +59 to +63
def random_color() -> dict:
COLOR = (rand.randint(0,255), rand.randint(0,255), rand.randint(0,255))
HEX = f"#{cns('decimal', 'hexadecimal', COLOR[0])['result']}{cns('decimal', 'hexadecimal', COLOR[1])['result']}{cns('decimal', 'hexadecimal', COLOR[2])['result']}"
GOOGLE_COLOR_PICKER_URL = f"https://google.com/search?q={HEX.replace('#', '%23')}&utm_source={settings.freeapi_domain}"
return { "hex": HEX, "rgb": COLOR, "google": GOOGLE_COLOR_PICKER_URL}
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HEX concatenates base-conversion results that are not zero-padded, so values < 16 produce 1-digit components (e.g., #A3F...) which is not a valid 6-digit hex color. Format each channel as exactly two hex digits (e.g., via format(x, "02X") or .zfill(2)) before concatenation.

Copilot uses AI. Check for mistakes.
Comment thread src/modules/network.py
Comment on lines +21 to +40
def dns_request(domain: str, type: str = 'A', nameserver: str = "1.1.1.1") -> dict:
"""
Perform a DNS request for the given domain and record type.

Args:
domain (str): The domain to query.
type (str): The type of DNS record to query (e.g., 'A', 'MX', 'CNAME').
nameserver (str): The DNS server to use for the query (default is "1.1.1.1").
Returns:
dict: A dictionary containing the DNS response.
"""
try:
client = _dns_client(nameserver)
if client is None:
return {"error": "dnspython is not installed."}

answers = client.resolve(domain, type)
return {"answers": [str(answer) for answer in answers]}
except Exception as e:
return {"error": str(e)}
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dns_request() returns error payloads without a code, and exception handling returns raw exception strings. With the new {"error": ..., "code": ...} -> HTTP status middleware, these errors will still be returned as HTTP 200 and may leak internal details. Return consistent code values (e.g., 400/500) and map/normalize exception messages to user-safe errors.

Copilot uses AI. Check for mistakes.
Comment thread tests/modules/network.py
Comment on lines +1 to +15
from pathlib import Path
import sys

# Allow direct execution of this file from any working directory.
PROJECT_ROOT = Path(__file__).resolve().parents[2]
SCRIPT_DIR = Path(__file__).resolve().parent
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))

# Avoid shadowing the stdlib `network` module with this file name.
sys.path = [path for path in sys.path if Path(path).resolve() != SCRIPT_DIR]

import src.modules.network as mnetwork

print(mnetwork.ip_range('24')) No newline at end of file
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests/modules/*.py look like ad-hoc debug scripts (they mutate sys.path and print() output) rather than pytest tests, so they won't be executed by default test discovery and can confuse the test suite structure. Consider moving these to a scripts/ or tools/ folder, or converting them into real test_*.py tests with assertions.

Copilot uses AI. Check for mistakes.
Comment thread tests/modules/dev.py
Comment on lines +1 to +20
from pathlib import Path
import sys

# Allow direct execution of this file from any working directory.
PROJECT_ROOT = Path(__file__).resolve().parents[2]
SCRIPT_DIR = Path(__file__).resolve().parent
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))

# Avoid shadowing the stdlib `dev` module with this file name.
sys.path = [path for path in sys.path if Path(path).resolve() != SCRIPT_DIR]

import src.modules.dev as mdev

print(mdev.test_regex(r'\b\w+\b', 'This is a test string.'))
print(mdev.generate_regex('This is a test string.'))

import re
pattern = re.compile(r"2020-03-12T13:34:56\.123Z INFO \[org\.example\.Class\]: This is a #simple #logline containing a 'value'\.", re.IGNORECASE)
print(pattern.match("This is a test string.")) No newline at end of file
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests/modules/*.py look like ad-hoc debug scripts (they mutate sys.path and print() output) rather than pytest tests, so they won't be executed by default test discovery and can confuse the test suite structure. Consider moving these to a scripts/ or tools/ folder, or converting them into real test_*.py tests with assertions.

Copilot uses AI. Check for mistakes.
Comment thread .env.example
# OAUTH_SCOPES=

# Optional cookie secret. If omitted, the app falls back to OAUTH_CLIENT_SECRET.
# Optional cookie secret. Ifdev omitted, the app falls back to OAUTH_CLIENT_SECRET.
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in comment: "Ifdev" should be "If".

Suggested change
# Optional cookie secret. Ifdev omitted, the app falls back to OAUTH_CLIENT_SECRET.
# Optional cookie secret. If omitted, the app falls back to OAUTH_CLIENT_SECRET.

Copilot uses AI. Check for mistakes.
Comment thread src/config/api_keys.py
Comment on lines +396 to +399
def _pepper() -> str:
return settings.api_key_pepper or settings.session_secret or os.getenv("SESSION_SECRET", "") or "freeapi-api-key-pepper"


Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_pepper() falls back to a hard-coded constant ("freeapi-api-key-pepper") when neither API_KEY_PEPPER nor SESSION_SECRET is set. That removes the security benefit of a pepper (hashes become portable/offline-crackable if the DB leaks). Consider requiring an explicit pepper/secret in production (and failing fast if missing), or at least making the fallback conditional on non-production environments.

Suggested change
def _pepper() -> str:
return settings.api_key_pepper or settings.session_secret or os.getenv("SESSION_SECRET", "") or "freeapi-api-key-pepper"
def _is_production_environment() -> bool:
configured_environment = getattr(settings, "environment", None)
if isinstance(configured_environment, str) and configured_environment.strip():
return configured_environment.strip().lower() == "production"
for env_var in ("ENVIRONMENT", "APP_ENV", "PYTHON_ENV", "FASTAPI_ENV"):
value = os.getenv(env_var, "")
if value.strip():
return value.strip().lower() == "production"
return False
def _pepper() -> str:
pepper = settings.api_key_pepper or settings.session_secret or os.getenv("SESSION_SECRET", "")
if pepper:
return pepper
if _is_production_environment():
raise RuntimeError("API key pepper is required in production; set API_KEY_PEPPER or SESSION_SECRET")
return "freeapi-api-key-pepper"

Copilot uses AI. Check for mistakes.
Comment thread README.md
```

This will build the Docker image and start the API in a container. The API will be accessible at `http://localhost:8000`.
This will build the API image locally and start the API together with Postgres and Redis. The API will be accessible at `http://localhost:8000`.
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Docker instructions say docker compose up -d "will build the API image locally", but docker/docker-compose.yml uses a prebuilt image: ghcr.io/freepyapi/freeapi:latest (no build:). Either update the compose file to build locally (or reference dev-docker-compose.yml), or adjust the README wording so it matches what actually happens.

Suggested change
This will build the API image locally and start the API together with Postgres and Redis. The API will be accessible at `http://localhost:8000`.
This will start the API together with Postgres and Redis using the prebuilt API image defined in the compose file. The API will be accessible at `http://localhost:8000`.

Copilot uses AI. Check for mistakes.
Comment thread tests/modules/random.py
Comment on lines +1 to +15
from pathlib import Path
import sys

# Allow direct execution of this file from any working directory.
PROJECT_ROOT = Path(__file__).resolve().parents[2]
SCRIPT_DIR = Path(__file__).resolve().parent
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))

# Avoid shadowing the stdlib `random` module with this file name.
sys.path = [path for path in sys.path if Path(path).resolve() != SCRIPT_DIR]

import src.modules.random as mrandom

print(mrandom.random_gradient()) No newline at end of file
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests/modules/*.py look like ad-hoc debug scripts (they mutate sys.path and print() output) rather than pytest tests, so they won't be executed by default test discovery and can confuse the test suite structure. Consider moving these to a scripts/ or tools/ folder, or converting them into real test_*.py tests with assertions.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +21
@router.get("/", tags=["Root"])
def root() -> dict[str, Any]:
version = settings.freeapi_current_version
return {
"message": "Welcome to the FreeAPI!",
"version": f"v{version}",
"documentation": f"/v{version}/docs",
}
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This archived root handler uses settings.freeapi_current_version to build the reported version and docs link. That will reflect the current deployment version (e.g. 1.0.1), not the archived version (v1.0.0), so /v1.0.0/ can report the wrong version and point to the wrong docs. Prefer deriving the version from the mounted app (e.g., request.app.version) or hard-coding v1.0.0 within this archive package.

Copilot uses AI. Check for mistakes.
@SzaBee13 SzaBee13 merged commit c9b6151 into main Apr 21, 2026
3 checks passed
@SzaBee13 SzaBee13 deleted the v/1.0.1 branch April 21, 2026 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants