Production ready , and easy to use starterpack for Ktor API development. It has Sensible feature set which every large-scale (or quality) application should have.
The source code can also serve as learning material. It's build with personal know-how and experience collected during development in PHP + Laravel
, Typescript + express
, C# + Unity3D
, Swift iOs Apps
. and more..
It is designed with large-scale applications in mind.
I hope it helps you! Feel free leave feedback or your ideas (Code review appreciated).
- Modern (y2023) - Kotlin & Ktor based, using kotlin advanced features
- Best practices - Domain Driven Design, Clean Architecture, SOLID, KISS, YAGNI, DRY
- Simplicity - Clarity, Obviousness, No-Magic, No-annotations, NO-unnecessary features,
- Easy-to-use - (preconfigured, extendable, DI, config (support .env), logging, example REST included)
- Modular Approach -
- every module is self-contained (single folder) and can be used independently
- Loose coupling
- wn Routing, Dependency Injection, Services etc..
- Production Ready
- it is suited for small and large projects
- Performance (Ktor, Kotlin, Coroutines, EventLoop)
- Docker, Kubernetes, Helm, CI/CD, Monitoring, Logging, Metrics, etc..
- Kotlin
- Ktor (framework)
- Koin (DI library)
- Logback (Logging configured for ELK (Kibana, Logstash))
- dotenv
.env
- Swagger UI (exposed API Documentation )
- JUnit5
- Docker
- Gradle
- Prometheus
- REST API
sh gradlew run
!!! IMPORTANT !!! auto-reload feature - which broke singletons! @see stackOverflow
set .env
file or ENV variable
ENVIRONMENT=development
Since Auto-reload detects changes in output files, we need to enable automatic project rebuilding. To do this, execute the following command in a repository's root directory:
sh gradlew -t build
Follow the steps below to see Auto-reload in action:
- Open another terminal tab and run a sample:
sh gradlew run
- Open http://localhost:8080/ to see a sample text in a browser.
- Change a text passed to the
respondText
method in Application.kt and save a file. - Refresh the http://localhost:8080/ page to see the updated text.
see .env.sample
file
- Ktor framework
- Configuration using .env file
- Dependency Injection Koin
- should we use Eager initialization?
- App structure (Modules)
- Logging configure runtime
- LoggerService
- separated LoggerContext
- Check if all logs are compatible with ELK
- Scoped logger per request (meta data userId, shopId, etc) @see ReqContext.kt
- MethodCalled meta
- Request logging with correct scope and loggerName
- Error Handling
- Global handling of NotFoundException, RequestValidationException, BadRequestException, IllegalArgumentException, etc
- Monitoring
-
/metrics
endpoint (prometheus)- [] Metrics correct names and units (don't know how...it looks like its impossible) https://www.robustperception.io/who-wants-seconds/
-
/health
Health Check
-
- serialization
- Validation
- Request & Internal & Response Validation
- Custom solution - KTOR RequestValidationPlugin is just not good enough
- Validation with nice error messages @see [ValidationException]
- Extendable validation
- Testing
- Testing EP with snapshots
- Example module test (ArticleModule)
- Deployment
- Docker
- gitlab-ci
- k8s
- Example module (Articles)
- Routing (Resource Controller)
- Repository
- Service
- Model
- ModelExporter (versioned JSON export)
- Tests
- Request & Response validation
- RequestContext (contextual logger and metadata) @see
plugins/RequestContext.kt
- Root ApiInfo endpoint
/
(version, build, swagger, urls, etc) - Graceful shutdown
- Swagger
- serve swagger.yml
/swagger/swagger.yml
- swagger-ui
/swagger
- serve swagger.yml
- Auto-reload feature - which broke singletons! KTOR-4842
- if singleton is created inside Application module, it will be created only once (on first request) and KtorAutoLoader should don't release instance
- in development mode, it is not problem i guess... (only Singleton which is created outside of module is Config...)
- CallLogging sets custom logger (app.router) - but it is used by KTOR system logging...
- Serializer for LogLevel doesn't work @see
/lib/serializers/LogLevelSerializer.kt
" - Metrics are in default second units (prometheus default) - im was unable to change it to milliseconds
- maybe its intentional and it can't be changed
- we can maybe try Dropwizard instead of Micrometer
- Resource param validation weirdness (KTOR)
- if http://0.0.0.0:3000/v1/articles?status=NEEXISTUJE
- first time i have correct 400 BadRequest:
cz.danielkouba.ktorStarterpackDk.modules.article.model.ArticleStatus does not contain element with name 'PUBLISHEDs'
- second time i have wierd 400 BadRequest:
io.ktor.server.plugins.BadRequestException: Can't transform call to resource
- solvable with custom validation (don't use any Enums as types)
____ __ __ __ __ ______ ______ ______
/\ __-. /\ \/ / /\ \/ / /\__ _\ /\ __ \ /\ == \
\ \ \/\ \ \ \ _"-. \ \ _"-. \/_/\ \/ \ \ \/\ \ \ \ __<
\ \____- \ \_\ \_\ \ \_\ \_\ \ \_\ \ \_____\ \ \_\ \_\
\/____/ \/_/\/_/ \/_/\/_/ \/_/ \/_____/ \/_/ /_/
GINGER BEAVERS STARTERPACK FOR KOTLIN KTOR SERVERS