{"id":43152262,"url":"https://github.com/fiddlerwoaroof/sqlite-serve","last_synced_at":"2026-02-01T00:26:29.221Z","repository":{"id":325037686,"uuid":"1098840779","full_name":"fiddlerwoaroof/sqlite-serve","owner":"fiddlerwoaroof","description":null,"archived":false,"fork":false,"pushed_at":"2025-11-19T11:33:00.000Z","size":231,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-30T19:49:56.967Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fiddlerwoaroof.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-18T08:03:10.000Z","updated_at":"2025-11-19T11:32:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/fiddlerwoaroof/sqlite-serve","commit_stats":null,"previous_names":["fiddlerwoaroof/sqlite-serve"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fiddlerwoaroof/sqlite-serve","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fiddlerwoaroof%2Fsqlite-serve","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fiddlerwoaroof%2Fsqlite-serve/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fiddlerwoaroof%2Fsqlite-serve/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fiddlerwoaroof%2Fsqlite-serve/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fiddlerwoaroof","download_url":"https://codeload.github.com/fiddlerwoaroof/sqlite-serve/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fiddlerwoaroof%2Fsqlite-serve/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28961796,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T23:03:11.038Z","status":"ssl_error","status_checked_at":"2026-01-31T22:56:44.691Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-01T00:26:28.749Z","updated_at":"2026-02-01T00:26:29.201Z","avatar_url":"https://github.com/fiddlerwoaroof.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sqlite-serve - SQLite Module for NGINX\n\nA dynamic NGINX module written in Rust that integrates SQLite databases with Handlebars templating, enabling data-driven web applications directly from NGINX configuration.\n\n## Features\n\n✅ **SQLite Integration** - Query SQLite databases from NGINX  \n✅ **Handlebars Templates** - Render dynamic HTML with template inheritance  \n✅ **Parameterized Queries** - Safe SQL parameters from nginx variables  \n✅ **Global \u0026 Local Templates** - Template reuse with override support  \n✅ **Zero Application Server** - Serve data-driven pages directly from NGINX  \n\n## Quick Start\n\n### 1. Build the Module\n\n```bash\ndirenv exec \"$PWD\" cargo build\n```\n\n### 2. Run the Book Catalog Example\n\n```bash\n./start_book_catalog.sh\n```\n\nVisit http://localhost:8080/books/all\n\n### 3. Run the Parameters Example\n\n```bash\n./start_book_detail.sh\n```\n\nVisit http://localhost:8081/book?id=1\n\n## Examples\n\n### Example 1: Book Catalog (Port 8080)\n\nA full-featured catalog with category browsing, global templates, and responsive UI.\n\n**Features:**\n- Browse all books or filter by category\n- Shared header/footer/card templates\n- Modern gradient UI design\n- Multiple category pages\n\n**See:** `conf/book_catalog.conf` and `README_BOOK_CATALOG.md`\n\n### Example 2: Positional Parameters (Port 8081)\n\nDemonstrates dynamic SQL queries with positional parameters.\n\n**Features:**\n- Query parameters with `?` placeholders\n- Multiple positional parameters\n- Safe prepared statement binding\n\n**See:** `conf/book_detail.conf`\n\n### Example 3: Named Parameters (Port 8082) - Recommended\n\nDemonstrates named SQL parameters for better readability.\n\n**Features:**\n- Named parameters with `:name` syntax\n- Order-independent parameter binding\n- Title search with LIKE operator\n- Rating filtering\n- More maintainable configuration\n\n**See:** `conf/book_named_params.conf` and `README_PARAMETERS.md`\n\n## Configuration Directives\n\n### `sqlite_db`\nSet the SQLite database file path.\n\n**Syntax:** `sqlite_db path;`  \n**Context:** `location`\n\n### `sqlite_query`\nDefine the SQL SELECT query to execute.\n\n**Syntax:** `sqlite_query \"SELECT ...\";`  \n**Context:** `location`  \n**Notes:** Use `?` placeholders for parameters\n\n### `sqlite_template`\nSpecify the Handlebars template file (relative to location path).\n\n**Syntax:** `sqlite_template filename.hbs;`  \n**Context:** `location`  \n**Notes:** Sets the content handler for the location\n\n### `sqlite_param`\nAdd a parameter to the SQL query (can be used multiple times).\n\n**Syntax:**  \n- Positional: `sqlite_param $variable_or_value;`  \n- Named: `sqlite_param :param_name $variable_or_value;`\n\n**Context:** `location`  \n**Notes:**  \n- Positional parameters match `?` placeholders in order\n- Named parameters match `:name` placeholders by name (recommended)\n\n### `sqlite_global_templates`\nSet a directory for global template files (partials, layouts).\n\n**Syntax:** `sqlite_global_templates directory;`  \n**Context:** `http`\n\n## Basic Example\n\n```nginx\nhttp {\n    sqlite_global_templates \"templates/global\";\n    \n    server {\n        listen 8080;\n        root \"public\";\n        \n        # Simple query without parameters\n        location = /books {\n            sqlite_db \"catalog.db\";\n            sqlite_query \"SELECT * FROM books ORDER BY title\";\n            sqlite_template \"list.hbs\";\n        }\n        \n        # Parameterized query with named parameter (recommended)\n        location = /book {\n            sqlite_db \"catalog.db\";\n            sqlite_query \"SELECT * FROM books WHERE id = :book_id\";\n            sqlite_param :book_id $arg_id;\n            sqlite_template \"detail.hbs\";\n        }\n        \n        # Positional parameters also supported\n        location = /search {\n            sqlite_db \"catalog.db\";\n            sqlite_query \"SELECT * FROM books WHERE year \u003e= ? AND year \u003c= ?\";\n            sqlite_param $arg_min;  # First ?\n            sqlite_param $arg_max;  # Second ?\n            sqlite_template \"list.hbs\";\n        }\n    }\n}\n```\n\n## Template System\n\n### Template Resolution\n\nTemplates are resolved as: `{document_root}{uri}/{template_name}`\n\nExample:\n- `root \"public\"`\n- `location /books`\n- `sqlite_template \"list.hbs\"`\n- Resolved to: `public/books/list.hbs`\n\n### Global Templates\n\nPlace shared templates (headers, footers, partials) in a global directory:\n\n```nginx\nhttp {\n    sqlite_global_templates \"templates/shared\";\n}\n```\n\nAll `.hbs` files in this directory are automatically loaded as partials (referenced without `.hbs` extension):\n\n```handlebars\n{{\u003e header}}\n\u003cdiv class=\"content\"\u003e\n    {{#each results}}\n        {{\u003e card}}\n    {{/each}}\n\u003c/div\u003e\n{{\u003e footer}}\n```\n\n### Local Templates\n\nEach location can have its own template directory. Local templates override global ones with the same name.\n\n**Directory structure:**\n```\npublic/\n├── global/           # Global templates\n│   ├── header.hbs\n│   └── footer.hbs\n└── books/\n    ├── list.hbs      # Main template\n    └── card.hbs      # Local partial (overrides global if exists)\n```\n\n### Template Data\n\nQuery results are passed to templates as a `results` array:\n\n```handlebars\n\u003ch1\u003eBooks ({{results.length}} total)\u003c/h1\u003e\n\u003cul\u003e\n{{#each results}}\n    \u003cli\u003e{{title}} by {{author}} ({{year}})\u003c/li\u003e\n{{/each}}\n\u003c/ul\u003e\n```\n\n## SQL Query Results\n\nResults are converted to JSON format:\n\n| SQLite Type | JSON Type |\n|-------------|-----------|\n| NULL        | `null` |\n| INTEGER     | Number |\n| REAL        | Number |\n| TEXT        | String |\n| BLOB        | String (hex-encoded) |\n\n## Development\n\n### Build\n\n```bash\ndirenv exec \"$PWD\" cargo build\n```\n\n### Test\n\n```bash\n# Run nginx with configuration\n./ngx_src/nginx-1.28.0/objs/nginx -c conf/book_catalog.conf -p .\n\n# Test endpoint\ncurl http://localhost:8080/books/all\n\n# Stop nginx\n./ngx_src/nginx-1.28.0/objs/nginx -s stop -c conf/book_catalog.conf -p .\n```\n\n### Debug\n\nEnable debug logging in nginx configuration:\n\n```nginx\nerror_log logs/error.log debug;\n```\n\nThen check the logs:\n\n```bash\ntail -f logs/error.log | grep sqlite\n```\n\n## Architecture\n\n```\nRequest → NGINX → Module Handler → SQLite Query\n                         ↓\n                  Resolve Variables\n                         ↓\n                  Execute Prepared Statement\n                         ↓\n                  Load Templates (Global + Local)\n                         ↓\n                  Render with Handlebars\n                         ↓\n                  Return HTML Response\n```\n\n## Project Structure\n\n```\nsqlite-serve/\n├── src/\n│   └── lib.rs                     # Module implementation\n├── conf/\n│   ├── book_catalog.conf          # Static catalog example\n│   └── book_detail.conf           # Parameterized queries example\n├── server_root/\n│   ├── global_templates/          # Shared templates\n│   │   ├── header.hbs\n│   │   ├── footer.hbs\n│   │   └── book_card.hbs\n│   ├── books/                     # Category pages\n│   ├── book/                      # Detail pages\n│   └── genre/                     # Genre pages\n├── book_catalog.db                # Sample database\n├── setup_book_catalog.sh          # Database setup script\n├── start_book_catalog.sh          # Start catalog server\n├── start_book_detail.sh           # Start parameters example\n├── README_BOOK_CATALOG.md         # Catalog example docs\n└── README_PARAMETERS.md           # Parameters feature docs\n```\n\n## Dependencies\n\n- **Rust** - 2024 edition\n- **ngx** (0.5.0) - Rust bindings for NGINX\n- **rusqlite** (0.37.0) - SQLite integration\n- **handlebars** (6.3.2) - Template engine\n- **serde** \u0026 **serde_json** - JSON serialization\n\n## License\n\nSee LICENSE file for details.\n\n## Resources\n\n- [NGINX Module Development Guide](https://nginx.org/en/docs/dev/development_guide.html)\n- [ngx Rust Crate](https://crates.io/crates/ngx)\n- [Handlebars Rust](https://crates.io/crates/handlebars)\n- [Rusqlite](https://crates.io/crates/rusqlite)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffiddlerwoaroof%2Fsqlite-serve","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffiddlerwoaroof%2Fsqlite-serve","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffiddlerwoaroof%2Fsqlite-serve/lists"}