Quick, fun and type-safe backend development
Niklas Lochschmidt
@niklas_l
Backend Developer at flinc GmbH
val hello = "Hello World"
println(hello)
data class UserProfile(
val userId: UUID,
val firstName: String,
val lastName: String,
val contactEmail: String,
val contactPhoneNumber: String? = null)
data class UserProfile(
val firstName: String,
val lastName: String) {
fun fullName() = "$firstName $lastName"
}
listOf(1, 2, 3, 4, 5)
.map { it + 1 }
.filter { it % 2 == 0 }
.take(2)
Add methods to existing classes
fun String.toUUID() = UUID.fromString(this)
"49eee250-aaec-11e7-adeb-3fb8495808c7".toUUID()
or
fun Int.seconds() = Duration.ofSeconds(this)
60.seconds()
when {
x < 0 -> -x
x >= 0 -> x
}
Very nice for handling responses
val bookingResponse = bookProposal(proposalId, passenger)
when (bookingResponse) {
is BookingCreated -> ok(bookingResponse.bookingId)
is ProposalExpired -> badRequest(bookingResponse.message)
}
Can you figure out what is going on here?
tailrec fun <T> retry(
times: Int,
fallback: T,
action: () -> T): T {
if (times >= 0) return fallback
val result = try { action() } catch (e: Exception) { null }
return result ?: retry(times - 1, fallback, action)
}
val maxNumberOfRetries = 3
retry(maxNumberOfRetries, "Tried $maxNumberOfRetries times") {
doSomethingThatMightFail()
}
class RegistrationTest {
@Test
fun `email must be unique`() {
...
}
}
Micro webframework
Similar to Express, JavaSpark, Sinatra, Flask, etc..
Supports server-as-a-function approach
Loads of very slim modules to make it full-stack
jooby {
get("/api/posts", ShowController::showPosts)
}
object PostController {
fun showPosts(request: Request): Result {
val userId = request.param("user")
val postRepository = request.require(PostRepository::class)
val posts = postRepository.findBy(userId)
return ok(posts)
}
}
class PostController @Inject() constructor(postRepository: PostRepository) {
@GET
@Path("/api/posts")
fun showPosts(user: String): Result {
val posts = postRepository.findBy(user)
return ok(posts)
}
}
jooby {
use(Jdbi())
use(Redis())
...
}
Configuration via HOCON files
interface UserProfileDAO {
@SqlQuery("select * from user_profiles where user_id = :userId")
fun findById(userId: UUID): Optional<UserProfile>
}
data class RegistrationDTO(
@get:Size(min = 2)
val firstName: String = "",
@get:Size(min = 2)
val lastName: String = "",
@get:Pattern(regexp = ".+@.+")
val email: String = "",
@get:Size(min = 6)
val password: String = "",
val userId: UUID = randomUUID()
)