Skip to main content

YAML-based API mocking server

Project description

seyon

A YAML-driven API mocking tool that parses schema definitions from YAML files, validates them, generates databases (SQLite or PostgreSQL) with mock data, and serves a dynamic REST API — all from a single YAML spec.

Features

  • Define your database schema (tables, columns, types, constraints) in YAML
  • Validate the YAML schema for correctness
  • Generate SQLite (local .db file) or PostgreSQL (remote server) databases
  • Populate tables with realistic mock data (random phone numbers, emails, UUIDs, etc.)
  • Serve a FastAPI REST server with auto-generated CRUD endpoints per model
  • Pagination, filtering, sorting on all list endpoints
  • Relation resolution — foreign keys auto-resolve to full referenced objects
  • Handle PRIMARY KEY, UNIQUE, NOT NULL, AUTOINCREMENT/SERIAL, and max-length constraints automatically
  • Support for Neon.tech serverless PostgreSQL (auto-resolves hostnames via Google DNS)

Project Structure

seyon/
├── src/
│   ├── seyon/
│   │   └── main.py              # CLI entry point (start, generate, validate, serve)
│   ├── database/
│   │   ├── base.py              # DatabaseAbstract — abstract base class
│   │   ├── factory.py           # DataFactory — selects DB generator by type
│   │   ├── sqlite_generator.py  # SQLiteGenerator — table creation & data insertion
│   │   └── postgress_generator.py  # PostgressGenerator — PostgreSQL implementation
│   ├── parser/
│   │   └── yaml_load.py         # load_yaml — reads and parses YAML files
│   ├── schema/
│   │   ├── constants.py         # Elements — supported types & allowed properties
│   │   ├── field.py             # Field — column definition & mock value generation
│   │   ├── model.py             # Model — table definition & validation
│   │   └── project.py           # Project — top-level spec & validation
│   ├── server/
│   │   ├── app.py               # create_app(project) — FastAPI factory
│   │   ├── router_builder.py    # Dynamic CRUD route registration per model
│   │   └── response_builder.py  # Delegates to DB generator, resolves relations
│   └── util/
│       ├── config.py            # Settings — paths, DB name, defaults
│       ├── exeception.py        # ProjectException — structured error reporting
│       └── logging.py           # Logging — file-based timestamped logs
├── employee.yaml                # Example single-model YAML spec
├── test_multi.yaml              # Example multi-model YAML spec
├── pyproject.toml               # Package metadata & build config
├── requirements.txt             # Python dependencies
├── skills/
│   └── skill.md                 # IDE skill for spec authoring
└── README.md

Installation

Prerequisites

  • Python 3.10 or higher
  • pip
  • (Optional) PostgreSQL server or Neon.tech account for PSQL backend

Steps

  1. Clone the repository

    git clone <repo-url>
    cd seyon
    
  2. Create a virtual environment (recommended)

    python -m venv .venv
    .venv\Scripts\activate    # Windows
    # source .venv/bin/activate  # Linux/macOS
    
  3. Install the package

    pip install -e .
    

    This installs the seyon CLI command and dependencies (pyyaml, psycopg2-binary).

Usage

CLI Commands

seyon <command> --file <yaml-file>
Command Description
validate Load and validate the YAML schema
generate Validate, create tables, and populate with mock data
start Validate and create tables only
serve Validate, create tables, and start the REST API server

Examples

# Validate a YAML file
seyon validate --file employee.yaml

# Generate SQLite database with mock data
seyon generate --file employee.yaml

# Generate PostgreSQL database with mock data
seyon generate --file test_multi.yaml

# Start the REST API server (FastAPI)
seyon serve --file test_multi.yaml --port 8000

SQLite: generates mock.db in the current directory. PostgreSQL: connects to the remote server specified in the database: section.

Server API

When you run seyon serve, a FastAPI server starts with auto-generated CRUD endpoints for each model in the spec.

Method Endpoint Description
GET / Project info + model list
GET /{model_name} List rows (paginated)
GET /{model_name}/{id} Get row by primary key
POST /{model_name} Create a new row
PUT /{model_name}/{id} Update row by primary key
DELETE /{model_name}/{id} Delete row by primary key

Interactive API docs at http://localhost:8000/docs (Swagger UI).

Pagination

GET /{model_name} returns a paginated envelope:

{ "total": 50, "skip": 0, "limit": 100, "data": [...] }
Param Default Description
skip 0 Number of rows to skip
limit 100 Max rows to return (max 1000)

Example: GET /employee?skip=10&limit=20

Filtering

Any query param matching a field name becomes an equality filter. Supports operators via __ suffix:

Operator Example
eq (default) ?name=John or ?name__eq=John
ne ?name__ne=John
lt ?age__lt=30
gt ?age__gt=18
lte ?age__lte=65
gte ?age__gte=21
contains ?name__contains=oh
startswith ?name__startswith=J
endswith ?name__endswith=n

Example: GET /employee?department_id=1&age__gt=25

Sorting

Param Default Description
sort_by Field name to sort by
sort_order asc asc or desc

Example: GET /employee?sort_by=name&sort_order=desc

Relations

Fields with type: relation and references: are auto-resolved to full objects in responses:

models:
  department:
    fields:
      id: { type: integer, primarykey: true }
      name: { type: string }
  employee:
    fields:
      id: { type: integer, primarykey: true }
      department_id: { type: relation, references: department }

Response to GET /employee/1:

{
  "id": 1,
  "department_id": { "id": 1, "name": "Engineering" }
}

Use ?resolve_relations=false to get raw foreign key integers.

YAML Schema Reference

Database Backend Configuration

database:
  type: sqlite | psql | postgresql   # required — backend selection

  # PostgreSQL-only fields (ignored for SQLite):
  db_host: localhost                  # default: localhost
  db_port: 5432                       # default: 5432
  db_name: mydb                       # default: mock
  db_username: user                   # default: root
  db_password: pass                   # default: root
  db_sslmode: require                 # optional — e.g. require, disable, verify-full
  db_options: endpoint=my-endpoint    # optional — extra connection parameters

Neon.tech: Hostnames ending with .neon.tech are auto-resolved via Google DNS (8.8.8.8). The endpoint ID is extracted from the hostname and passed as a connection option automatically.

Supported Data Types

Type Description Generated Value
integer Whole number 1 (sequential for primary keys)
string Text "example"
boolean True/false True
float Decimal number 1.0
double Double-precision float 1.0
bigint Large integer 1234567890123456789
phone Phone number Random 10-digit Indian mobile
email Email address Random username@example.com
date Calendar date Current date
datetime Date and time Current timestamp
time Time of day Current time
text Long text Lorem ipsum placeholder
uuid UUID v4 Random UUID string
url Web URL https://example.com
json JSON object {"key": "value"}
relation Foreign key to another model Random valid PK from referenced model

PostgreSQL Type Mapping

When using type: psql, YAML types are mapped to PostgreSQL column types:

YAML type PostgreSQL type
integer INTEGER
bigint BIGINT
float REAL
double DOUBLE PRECISION
string VARCHAR(255)
text TEXT
boolean BOOLEAN
date DATE
datetime TIMESTAMP
time TIME
email VARCHAR(255)
phone VARCHAR(20)
password VARCHAR(255)
url VARCHAR(500)
uuid UUID
json JSONB
relation INTEGER

Constraints

  • primarykey: For integer primary keys, values autoincrement from 1.
  • unique: Phone fields use sequential offset, email fields use indexed username, other string types get a _N suffix.
  • required: Adds NOT NULL constraint to the column.
  • max-length: Optional positive integer. For string, email, password, url, phone, and text types, sets VARCHAR(n) column length in DDL and limits generated mock values. Example: max-length: 100.
  • autoincrement: Optional boolean. Only for integer type. Uses AUTOINCREMENT in SQLite and SERIAL in PostgreSQL. The field is omitted from INSERT statements so the DB assigns the value.

Example: SQLite (Single Model)

project: employee-management
database:
  type: sqlite

models:
  employee:
    count: 100
    fields:
      id:
        type: integer
        primarykey: true
      username:
        type: string
        unique: true
      email:
        type: email
      mobile:
        type: phone

Example: PostgreSQL (Multiple Models)

project: company-management
database:
  type: psql
  db_host: your-instance.region.neon.tech
  db_port: 5432
  db_name: neondb
  db_username: neondb_owner
  db_password: your-password
  db_sslmode: require

models:
  employee:
    count: 50
    fields:
      id:
        type: integer
        primarykey: true
      name:
        type: string
      email:
        type: email
      mobile:
        type: phone
      department_id:
        type: relation
        references: department

  department:
    count: 10
    fields:
      id:
        type: integer
        primarykey: true
      name:
        type: string
        unique: true
      head_count:
        type: integer

  project:
    count: 30
    fields:
      id:
        type: integer
        primarykey: true
      title:
        type: string
        unique: true
      budget:
        type: float
      start_date:
        type: date

Data Flow

YAML File
    │
    ▼
parser/yaml_load.py  ──►  dict
    │
    ▼
schema/       ──►  Project (validated) ──►  Model ──►  Field
    │
    ├── validate / generate ──────────────────►  database/factory.py
    │                                               │
    │                        ├── sqlite ────────────┤───►  SQLiteGenerator
    │                        │                      │         │
    │                        └── psql ──────────────┘───►  PostgressGenerator
    │                                                          │
    │                                          mock.db ◄───────┘
    │                                       PostgreSQL ◄───────┘
    │
    └── serve ──►  server/app.py (create_app)
                        │
                        ▼
              server/router_builder.py
                        │
                        ▼
              FastAPI routes per model
                        │
                        ▼
              server/response_builder.py
                        │
                        ▼
              database/generator CRUD methods

Logging

Logs are written to logs/<DD_MM_YYYY_HH>/<DD_MM_YYYY_HH>.log with timestamps and log levels.

Development

Running from source

python -m seyon.main generate --file employee.yaml

Adding a new database backend

  1. Create a new generator class in src/database/ implementing DatabaseAbstract
  2. Implement connect(), close(), generate_table(), generate_data(), get_all_data(), get_by_id(), insert(), update(), delete()
  3. Register it in src/database/factory.py
  4. Add the dependency to pyproject.toml and requirements.txt

Adding a new data type

  1. Add the type name to Elements.SUPPORTED_DATA_TYPES in src/schema/constants.py
  2. Add a generate_value branch in src/schema/field.py
  3. If the type can be unique, update uniqueness handling in all generators
  4. For PostgreSQL, add the type to TYPE_MAP in postgress_generator.py

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

seyon-0.1.4.tar.gz (27.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

seyon-0.1.4-py3-none-any.whl (28.6 kB view details)

Uploaded Python 3

File details

Details for the file seyon-0.1.4.tar.gz.

File metadata

  • Download URL: seyon-0.1.4.tar.gz
  • Upload date:
  • Size: 27.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.0

File hashes

Hashes for seyon-0.1.4.tar.gz
Algorithm Hash digest
SHA256 9a95aa2e52ac83ec1cc022ebd013f56260caee5243036b194e9f90807a45162d
MD5 bce91e52752cfa964cf08f96143df216
BLAKE2b-256 54ee4333d2e806443c22798c98659ed20319ed26ab47b19690eb7ce5a48ca0d2

See more details on using hashes here.

File details

Details for the file seyon-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: seyon-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 28.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.0

File hashes

Hashes for seyon-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 296c80f2dc6e7bd3224c80cb9be81204da340b33e677caa0e4b5ec90ea676add
MD5 2891738231b789784345fe277a5adafd
BLAKE2b-256 288af41a080330ca27cb14f28930841337782c7b0c00ca3d255b3fe7250345f2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page