This is a reference project for a Kotlin-based AWS Lambda service using http4k and Exposed.
- HTTP Layer: Built with http4k. Uses Lenses for type-safe request parsing and
kotlinx.serializationfor JSON. - Service Layer: Explicit dependency injection. No reflection or "magic" frameworks.
- Persistence: Exposed DSL for type-safe SQL construction over PostgreSQL.
- Database: PostgreSQL
- Compatibility: Fully compatible with GraalVM Native Image.
The application uses environment variables for configuration. For local development, we use .env files managed by Gradle.
| Variable | Description | Default (Local) |
|---|---|---|
DB_URL |
JDBC Connection String | jdbc:postgresql://localhost:5432/postgres |
DB_USER |
Database Username | postgres |
DB_PASSWORD |
Database Password | password |
For convenience, local development uses the co.uzzu.dotenv.gradle plugin.
- Copy
.env.exampleto.env. - Fill in your local database credentials.
- Run
./gradlew run.
- Ensure a PostgreSQL instance is running.
- Set the environment variables listed above.
- Run
./gradlew runor execute themainfunction inMain.kt. - The API will be available at
http://localhost:8080/brands.
Execute the test suite (uses an H2 in-memory database):
./gradlew test
This project is configured to build automatically via GitHub Actions. Every push to main generates two deployment artifacts:
- Standard Lambda: A Fat JAR optimized for Java 21 runtime.
- Native Lambda: A Linux binary built with GraalVM for ultra-fast cold starts.
If building manually, use the following Gradle tasks:
| Task | Output File | AWS Runtime |
|---|---|---|
./gradlew buildLambdaZip |
build/dist/deployment.zip |
Java 21 |
./gradlew buildNativeLambdaZip |
build/dist/native-deployment.zip |
Amazon Linux |
Depending on your AWS trigger, use one of these handlers:
- API Gateway (HTTP API v2):
gg.aquatic.foodservice.LambdaHandler - Application Load Balancer (ALB):
gg.aquatic.foodservice.AlbLambdaHandler
Endpoint: GET /brands
Query Parameters:
name(Optional): Partial match, case-insensitive.externalId(Optional): Exact match.sortBy(Optional):name|last_updated.sortDirection(Optional):asc|desc.
Example Request:
GET /brands?name=apple&sortBy=last_updated&sortDirection=desc