{"id":13524345,"url":"https://github.com/gimlet2/kottpd","last_synced_at":"2026-01-14T03:14:13.731Z","repository":{"id":10645882,"uuid":"65999896","full_name":"gimlet2/kottpd","owner":"gimlet2","description":"REST framework written in pure Kotlin","archived":false,"fork":false,"pushed_at":"2025-10-29T21:36:54.000Z","size":323,"stargazers_count":74,"open_issues_count":12,"forks_count":16,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-10-29T21:38:51.290Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gimlet2.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2016-08-18T13:34:58.000Z","updated_at":"2025-10-29T21:05:24.000Z","dependencies_parsed_at":"2025-10-29T21:25:48.185Z","dependency_job_id":"8212ac14-4f9d-464a-a111-681b7a8bdfce","html_url":"https://github.com/gimlet2/kottpd","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/gimlet2/kottpd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gimlet2%2Fkottpd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gimlet2%2Fkottpd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gimlet2%2Fkottpd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gimlet2%2Fkottpd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gimlet2","download_url":"https://codeload.github.com/gimlet2/kottpd/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gimlet2%2Fkottpd/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408818,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":"2024-08-01T06:01:09.150Z","updated_at":"2026-01-14T03:14:13.726Z","avatar_url":"https://github.com/gimlet2.png","language":"Kotlin","funding_links":[],"categories":["开源库和框架","开发框架"],"sub_categories":["Web 开发","Web框架"],"readme":"# Kottpd\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.github.gimlet2/kottpd.svg)](https://search.maven.org/artifact/com.github.gimlet2/kottpd)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Kotlin](https://img.shields.io/badge/Kotlin-2.0.21-blue.svg)](https://kotlinlang.org)\n[![Build](https://github.com/gimlet2/kottpd/actions/workflows/build.yml/badge.svg)](https://github.com/gimlet2/kottpd/actions/workflows/build.yml)\n![Coverage](.github/badges/jacoco.svg)\n![Branches](.github/badges/branches.svg)\n\nA lightweight REST framework written in pure Kotlin with zero external dependencies. Perfect for building microservices, REST APIs, and simple web servers.\n\n## Features\n\n✨ **Pure Kotlin** - No external framework dependencies  \n🚀 **Lightweight** - Minimal footprint (~316 LOC)  \n🔒 **HTTPS Support** - Built-in SSL/TLS support  \n🛣️ **Flexible Routing** - Path-based and regex routing  \n🎯 **Filters** - Before/after request filters  \n⚡ **Simple API** - Easy to learn and use  \n📁 **Static Files** - Built-in static file serving  \n🎭 **Exception Handling** - Custom exception handlers  \n\n## Quick Start\n\n### Installation\n\nAdd Kottpd to your project using Maven:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.gimlet2\u003c/groupId\u003e\n    \u003cartifactId\u003ekottpd\u003c/artifactId\u003e\n    \u003cversion\u003e0.2.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nOr Gradle:\n\n```kotlin\nimplementation(\"com.github.gimlet2:kottpd:0.2.2\")\n```\n\n### Hello World\n\n```kotlin\nimport com.github.gimlet2.kottpd.Server\n\nfun main() {\n    val server = Server() // Default port is 9000\n    \n    server.get(\"/hello\") { _, _ -\u003e \n        \"Hello, World!\" \n    }\n    \n    server.start()\n    println(\"Server running at http://localhost:9000\")\n}\n```\n\nVisit http://localhost:9000/hello to see your server in action!\n\n## Usage Examples\n\n### Basic Routing\n\n```kotlin\nval server = Server(port = 8080)\n\n// GET request\nserver.get(\"/users\") { req, res -\u003e\n    res.send(\"[{\\\"id\\\": 1, \\\"name\\\": \\\"John\\\"}]\")\n}\n\n// POST request\nserver.post(\"/users\") { req, res -\u003e\n    val userData = req.content\n    res.send(\"User created: $userData\", Status.Created)\n}\n\n// PUT request\nserver.put(\"/users/:id\") { req, res -\u003e\n    res.send(\"User ${req.url} updated\")\n}\n\n// DELETE request\nserver.delete(\"/users/:id\") { req, res -\u003e\n    res.send(\"User deleted\", Status.NoContent)\n}\n\nserver.start()\n```\n\n### Regex-based Routing\n\n```kotlin\nserver.get(\"/api/v.*/users\") { req, res -\u003e\n    res.send(\"Matches /api/v1/users, /api/v2/users, etc.\")\n}\n\nserver.get(\"/files/.*\\\\.pdf\") { req, res -\u003e\n    res.send(\"PDF file requested\")\n}\n```\n\n### Request Filters (Middleware)\n\n```kotlin\n// Global before filter (runs before all requests)\nserver.before { req, res -\u003e\n    println(\"Incoming request: ${req.method} ${req.url}\")\n    res.send(\"Log: Request received\\n\")\n}\n\n// Path-specific before filter\nserver.before(\"/api/.*\") { req, res -\u003e\n    // Authentication check\n    val token = req.headers[\"Authorization\"]\n    if (token == null) {\n        res.send(\"Unauthorized\", Status.Unauthorized)\n    }\n}\n\n// After filter\nserver.after(\"/.*\") { req, res -\u003e\n    res.send(\"\\n--- Request completed ---\")\n}\n```\n\n### Exception Handling\n\n```kotlin\nserver.get(\"/error\") { req, res -\u003e\n    throw IllegalStateException(\"Something went wrong!\")\n}\n\nserver.exception(IllegalStateException::class) { req, res -\u003e\n    res.send(\"Error handled gracefully\", Status.InternalServerError)\n}\n```\n\n### Static File Serving\n\n```kotlin\n// Serve static files from resources/public\nserver.staticFiles(\"/public\")\n\n// Now files are accessible:\n// resources/public/index.html -\u003e http://localhost:9000/index.html\n// resources/public/css/style.css -\u003e http://localhost:9000/css/style.css\n```\n\n### HTTPS/TLS Support\n\n```kotlin\nserver.start(\n    port = 9443,\n    secure = true,\n    keyStoreFile = \"./keystore.jks\",\n    password = \"keystorePassword\"\n)\n```\n\n### Working with Headers\n\n```kotlin\nserver.get(\"/headers\") { req, res -\u003e\n    val userAgent = req.headers[\"User-Agent\"]\n    val contentType = req.headers[\"Content-Type\"]\n    \n    res.send(\"User-Agent: $userAgent\")\n}\n```\n\n### Reading Request Body\n\n```kotlin\nserver.post(\"/data\") { req, res -\u003e\n    val body = req.content\n    val contentLength = req.headers[\"Content-Length\"]\n    \n    res.send(\"Received ${contentLength} bytes: $body\", Status.Created)\n}\n```\n\n### Complete Example\n\n```kotlin\nfun main() {\n    Server(9000).apply {\n        // Static files\n        staticFiles(\"/public\")\n        \n        // Routes\n        get(\"/\") { _, _ -\u003e \"Welcome to Kottpd!\" }\n        get(\"/hello\") { _, res -\u003e res.send(\"Hello\") }\n        get(\"/user/.*\") { req, res -\u003e res.send(\"User path: ${req.url}\") }\n        \n        // POST with body\n        post(\"/data\") { req, res -\u003e \n            res.send(req.content, Status.Created) \n        }\n        \n        // Filters\n        before(\"/hello\") { _, res -\u003e res.send(\"before\\n\") }\n        after(\"/hello\") { _, res -\u003e res.send(\"\\nafter\") }\n        \n        // Global filter\n        before { _, res -\u003e res.send(\"[LOG] \") }\n        \n        // Exception handling\n        get(\"/error\") { _, _ -\u003e throw IllegalStateException(\"Test error\") }\n        exception(IllegalStateException::class) { _, _ -\u003e \"Error handled\" }\n        \n        start()\n    }.also {\n        println(\"Server started on http://localhost:9000\")\n        println(\"Try: http://localhost:9000/hello\")\n    }\n}\n```\n\n## Architecture\n\nKottpd uses a simple architecture:\n\n1. **Server** - Main class that handles routing and server lifecycle\n2. **ClientThread** - Processes individual HTTP requests in separate threads\n3. **HttpRequest** - Represents incoming HTTP requests\n4. **HttpResponse** - Represents outgoing HTTP responses\n5. **Status** - HTTP status codes\n6. **HttpMethod** - Supported HTTP methods\n\n## Configuration\n\n### Custom Port\n\n```kotlin\nval server = Server(port = 8080)\n// or via system property\n// -Dserver.port=8080\n```\n\n### Thread Pool\n\nThe server uses a cached thread pool by default, which creates new threads as needed and reuses previously constructed threads when available.\n\n## Documentation\n\n- 📖 [Development Roadmap](ROADMAP.md) - Future plans and features\n- 🤝 [Contributing Guide](CONTRIBUTING.md) - How to contribute\n- 🔒 [Security Best Practices](SECURITY.md) - Security guidelines\n\n## Comparison with Other Frameworks\n\n| Feature | Kottpd | Ktor | Javalin | Spring Boot |\n|---------|--------|------|---------|-------------|\n| Size | Tiny | Medium | Small | Large |\n| Dependencies | None | Many | Few | Many |\n| Learning Curve | Easy | Medium | Easy | Steep |\n| Performance | Good | Excellent | Good | Good |\n| Best For | Simple APIs | Production apps | REST APIs | Enterprise |\n\n## Limitations\n\n⚠️ **Current limitations to be aware of:**\n\n- No built-in JSON serialization (bring your own library)\n- Basic error handling\n- Limited documentation\n- No built-in CORS support\n- Early development stage (v0.2.x)\n\nSee [ROADMAP.md](ROADMAP.md) for planned improvements.\n\n## Contributing\n\nWe welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Author\n\n**Andrei Chernyshev** - [@gimlet2](https://github.com/gimlet2)\n\n## Support\n\n- 🐛 [Report a bug](https://github.com/gimlet2/kottpd/issues/new)\n- 💡 [Request a feature](https://github.com/gimlet2/kottpd/issues/new)\n- ⭐ Star this repository if you find it useful!\n\n---\n\nMade with ❤️ using Kotlin\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgimlet2%2Fkottpd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgimlet2%2Fkottpd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgimlet2%2Fkottpd/lists"}