Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Javalin to 4.1.0 #97

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rhiannon/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ repositories {
dependencies {
implementation(kotlin("stdlib"))

val javalinVersion = "3.12.0"
val javalinVersion = "4.1.0"
implementation("io.javalin:javalin:$javalinVersion")
implementation("io.javalin:javalin-openapi:$javalinVersion")
implementation("com.typesafe:config:1.4.0")
Expand Down
17 changes: 9 additions & 8 deletions rhiannon/src/main/kotlin/club/jambuds/Application.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import club.jambuds.web.SongRoutes
import club.jambuds.web.SpotifyAuthRoutes
import club.jambuds.web.TwitterAuthRoutes
import club.jambuds.web.UserRoutes
import club.jambuds.web.extensions.logger
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
Expand All @@ -71,6 +72,7 @@ import io.javalin.core.validation.JavalinValidation
import io.javalin.http.HttpResponseExceptionMapper
import io.javalin.http.InternalServerErrorResponse
import io.javalin.plugin.json.JavalinJackson
import io.javalin.plugin.json.JsonMapper
import io.javalin.plugin.metrics.MicrometerPlugin
import io.javalin.plugin.openapi.OpenApiOptions
import io.javalin.plugin.openapi.OpenApiPlugin
Expand Down Expand Up @@ -150,14 +152,16 @@ class Application {
val spanId = span.spanContext.spanId
// TODO: make json? figure out other ways to do structured logging?
if (ctx.attribute<Boolean>("hideLog") != true) {
Javalin.log.info(
ctx.logger.info(
"method=${ctx.method()} endpoint=${ctx.matchedPath()} status=${ctx.status()} url=${ctx.url()} elapsed=$ms userAgent=${ctx.userAgent()} traceId=$traceId spanId=$spanId"
)
}
}

val objectMapper = createObjectMapper()
config.jsonMapper(JavalinJackson(objectMapper))
}

JavalinJackson.configure(createObjectMapper())
configureValidation()

app.get("/_prometheus") { ctx ->
Expand All @@ -166,7 +170,7 @@ class Application {
}

app.exception(Exception::class.java) { e, ctx ->
Javalin.log.error("Uncaught exception", e)
ctx.logger.error("Uncaught exception", e)
HttpResponseExceptionMapper.handle(InternalServerErrorResponse(), ctx)
}

Expand All @@ -186,11 +190,8 @@ class Application {
}

fun createObjectMapper(): ObjectMapper {
return createObjectMapper(ObjectMapper())
}
private fun createObjectMapper(objectMapper: ObjectMapper): ObjectMapper {
val df = SimpleDateFormat("yyyy-MM-dd'T'HH:mmX")
return objectMapper
return ObjectMapper()
.registerModule(KotlinModule())
.registerModule(JavaTimeModule())
.setDateFormat(df)
Expand Down Expand Up @@ -223,7 +224,7 @@ class Application {
}.apply {
path("/swagger-docs")
swagger(SwaggerOptions("/swagger-ui"))
val om = createObjectMapper(JacksonToJsonMapper.createObjectMapperWithDefaults())
val om = createObjectMapper()
toJsonMapper(JacksonToJsonMapper(om))
modelConverterFactory(JacksonModelConverterFactory(om))
}
Expand Down
4 changes: 2 additions & 2 deletions rhiannon/src/main/kotlin/club/jambuds/util/NewRelicPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import javax.servlet.http.HttpServletResponse

class NewRelicPlugin : Plugin {
override fun apply(app: Javalin) {
val server = app.server()?.server() ?: return
val server = app.jettyServer()?.server() ?: return

val handler = object : ServletHandler() {
override fun doHandle(
Expand All @@ -23,7 +23,7 @@ class NewRelicPlugin : Plugin {
) {
// logic via:
// https://github.com/tipsy/javalin/blob/master/javalin/src/main/java/io/javalin/plugin/metrics/MicrometerPlugin.kt
val uri = app.servlet()
val uri = app.javalinServlet()
.matcher
.findEntries(HandlerType.valueOf(request.method), request.pathInfo)
.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import org.eclipse.jetty.servlet.ServletHandler

class OpenTelemetryPlugin: Plugin {
override fun apply(app: Javalin) {
val server = app.server()?.server() ?: return
val server = app.jettyServer()?.server() ?: return

val handler = object : ServletHandler() {
override fun doHandle(
Expand All @@ -23,7 +23,7 @@ class OpenTelemetryPlugin: Plugin {
) {
// logic via:
// https://github.com/tipsy/javalin/blob/master/javalin/src/main/java/io/javalin/plugin/metrics/MicrometerPlugin.kt
val uri = app.servlet()
val uri = app.javalinServlet()
.matcher
.findEntries(HandlerType.valueOf(request.method), request.pathInfo)
.stream()
Expand Down
12 changes: 7 additions & 5 deletions rhiannon/src/main/kotlin/club/jambuds/web/AuthRoutes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import club.jambuds.service.AuthService
import club.jambuds.web.extensions.validateJsonBody
import io.javalin.apibuilder.ApiBuilder
import io.javalin.http.Context
import io.javalin.http.Cookie
import io.javalin.plugin.openapi.annotations.OpenApi
import io.javalin.plugin.openapi.annotations.OpenApiContent
import io.javalin.plugin.openapi.annotations.OpenApiRequestBody
import io.javalin.plugin.openapi.annotations.OpenApiResponse
import javax.servlet.http.Cookie
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size

Expand Down Expand Up @@ -159,11 +159,13 @@ class AuthRoutes(private val authService: AuthService, private val appUrl: Strin

private fun setTokenCookie(ctx: Context, authToken: String) {
ctx.cookie(
Cookie(AUTH_TOKEN_COOKIE, authToken).apply {
maxAge = 60 * 60 * 24 * 365
isHttpOnly = true
Cookie(
name = AUTH_TOKEN_COOKIE,
value = authToken,
maxAge = 60 * 60 * 24 * 365,
isHttpOnly = true,
secure = appUrl.startsWith("https")
}
)
)
}
}
8 changes: 4 additions & 4 deletions rhiannon/src/main/kotlin/club/jambuds/web/FollowingRoutes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import io.javalin.plugin.openapi.annotations.OpenApiResponse

class FollowingRoutes(private val followingService: FollowingService) {
fun register() {
ApiBuilder.put("/api/following/:followName", this::followUser)
ApiBuilder.delete("/api/following/:followName", this::unfollowUser)
ApiBuilder.put("/api/following/{followName}", this::followUser)
ApiBuilder.delete("/api/following/{followName}", this::unfollowUser)
}

@OpenApi(
Expand All @@ -24,7 +24,7 @@ class FollowingRoutes(private val followingService: FollowingService) {
)
private fun followUser(ctx: Context) {
val currentUser = ctx.requireUser()
val followName = ctx.pathParam<String>("followName").get()
val followName = ctx.pathParamAsClass<String>("followName").get()
val followingUser = followingService.followUser(currentUser, followName)
ctx.json(FollowUserResponse(followingUser))
}
Expand All @@ -37,7 +37,7 @@ class FollowingRoutes(private val followingService: FollowingService) {
)
private fun unfollowUser(ctx: Context) {
val currentUser = ctx.requireUser()
val followName = ctx.pathParam<String>("followName").get()
val followName = ctx.pathParamAsClass<String>("followName").get()
followingService.unfollowUser(currentUser, followName)
ctx.status(204)
}
Expand Down
16 changes: 8 additions & 8 deletions rhiannon/src/main/kotlin/club/jambuds/web/LikeRoutes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import io.javalin.plugin.openapi.annotations.OpenApiResponse

class LikeRoutes(private val likeService: LikeService) {
fun register() {
put("/api/likes/:type/:itemId", this::createLike)
delete("/api/likes/:type/:itemId", this::deleteLike)
put("/api/likes/{type}/{itemId}", this::createLike)
delete("/api/likes/{type}/{itemId}", this::deleteLike)
}

@OpenApi(
Expand Down Expand Up @@ -54,10 +54,10 @@ class LikeRoutes(private val likeService: LikeService) {
private fun createLike(ctx: Context) {
val currentUser = ctx.requireUser()
val itemType = getItemType(ctx)
val itemId = ctx.pathParam<Int>("itemId").get()
val likeSource = ctx.queryParam<LikeSource>("likeSource").getOrNull()
val sourceMixtapeId = ctx.queryParam<Int>("sourceMixtapeId").getOrNull()
val sourceUserNames = ctx.queryParam<String>("sourceUserNames").getOrNull()
val itemId = ctx.pathParamAsClass<Int>("itemId").get()
val likeSource = ctx.queryParamAsClass<LikeSource>("likeSource").allowNullable().get()
val sourceMixtapeId = ctx.queryParamAsClass<Int>("sourceMixtapeId").allowNullable().get()
val sourceUserNames = ctx.queryParamAsClass<String>("sourceUserNames").allowNullable().get()
likeService.createLike(currentUser, itemType, itemId, likeSource, sourceMixtapeId, sourceUserNames)
ctx.status(204)
}
Expand All @@ -79,13 +79,13 @@ class LikeRoutes(private val likeService: LikeService) {
private fun deleteLike(ctx: Context) {
val currentUser = ctx.requireUser()
val itemType = getItemType(ctx)
val itemId = ctx.pathParam<Int>("itemId").get()
val itemId = ctx.pathParamAsClass<Int>("itemId").get()
likeService.deleteLike(currentUser, itemType, itemId)
ctx.status(204)
}

private fun getItemType(ctx: Context): ItemType {
val type = ctx.pathParam<String>("type").get()
val type = ctx.pathParamAsClass<String>("type").get()
return when (type) {
"songs" -> ItemType.SONG
"mixtapes" -> ItemType.MIXTAPE
Expand Down
30 changes: 15 additions & 15 deletions rhiannon/src/main/kotlin/club/jambuds/web/MixtapeRoutes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ import io.javalin.plugin.openapi.annotations.OpenApiResponse
class MixtapeRoutes(private val mixtapeService: MixtapeService) {
fun register() {
ApiBuilder.post("/api/mixtapes", this::createMixtape)
ApiBuilder.get("/api/mixtapes/:id", this::getMixtape)
ApiBuilder.delete("/api/mixtapes/:id", this::deleteMixtape)
ApiBuilder.get("/api/mixtapes/{id}", this::getMixtape)
ApiBuilder.delete("/api/mixtapes/{id}", this::deleteMixtape)

ApiBuilder.post("/api/mixtapes/:mixtapeId/songs", this::addSongToMixtape)
ApiBuilder.delete("/api/mixtapes/:mixtapeId/songs/:songId", this::removeSongFromMixtape)
ApiBuilder.post("/api/mixtapes/:mixtapeId/order", this::reorderSongsInMixtape)
ApiBuilder.post("/api/mixtapes/:mixtapeId/title", this::renameMixtape)
ApiBuilder.post("/api/mixtapes/:mixtapeId/publish", this::publishMixtape)
ApiBuilder.post("/api/mixtapes/{mixtapeId}/songs", this::addSongToMixtape)
ApiBuilder.delete("/api/mixtapes/{mixtapeId}/songs/{songId}", this::removeSongFromMixtape)
ApiBuilder.post("/api/mixtapes/{mixtapeId}/order", this::reorderSongsInMixtape)
ApiBuilder.post("/api/mixtapes/{mixtapeId}/title", this::renameMixtape)
ApiBuilder.post("/api/mixtapes/{mixtapeId}/publish", this::publishMixtape)

ApiBuilder.get("/api/draft-mixtapes", this::getDraftMixtapes)
}
Expand Down Expand Up @@ -58,7 +58,7 @@ class MixtapeRoutes(private val mixtapeService: MixtapeService) {
)
private fun getMixtape(ctx: Context) {
val currentUserId = ctx.currentUser?.id
val id = ctx.pathParam<Int>("id").get()
val id = ctx.pathParamAsClass<Int>("id").get()

val mixtape = mixtapeService.getMixtapeById(id, currentUserId = currentUserId)
?: throw NotFoundResponse("Could not find mixtape with id $id")
Expand All @@ -74,7 +74,7 @@ class MixtapeRoutes(private val mixtapeService: MixtapeService) {
)
private fun deleteMixtape(ctx: Context) {
val currentUser = ctx.requireUser()
val id = ctx.pathParam<Int>("id").get()
val id = ctx.pathParamAsClass<Int>("id").get()

mixtapeService.deleteMixtapeById(id, currentUserId = currentUser.id)

Expand All @@ -95,7 +95,7 @@ class MixtapeRoutes(private val mixtapeService: MixtapeService) {
)
private fun addSongToMixtape(ctx: Context) {
val currentUser = ctx.requireUser()
val mixtapeId = ctx.pathParam<Int>("mixtapeId").get()
val mixtapeId = ctx.pathParamAsClass<Int>("mixtapeId").get()
val body = ctx.validateJsonBody(AddSongBody::class.java)

val song = mixtapeService.addSongToMixtape(
Expand All @@ -119,8 +119,8 @@ class MixtapeRoutes(private val mixtapeService: MixtapeService) {
)
private fun removeSongFromMixtape(ctx: Context) {
val currentUser = ctx.requireUser()
val mixtapeId = ctx.pathParam<Int>("mixtapeId").get()
val songId = ctx.pathParam<Int>("songId").get()
val mixtapeId = ctx.pathParamAsClass<Int>("mixtapeId").get()
val songId = ctx.pathParamAsClass<Int>("songId").get()

mixtapeService.removeSongFromMixtape(
mixtapeId = mixtapeId,
Expand All @@ -144,7 +144,7 @@ class MixtapeRoutes(private val mixtapeService: MixtapeService) {
)
private fun reorderSongsInMixtape(ctx: Context) {
val currentUser = ctx.requireUser()
val mixtapeId = ctx.pathParam<Int>("mixtapeId").get()
val mixtapeId = ctx.pathParamAsClass<Int>("mixtapeId").get()
val body = ctx.validateJsonBody(ReorderSongsBody::class.java)

mixtapeService.reorderSongsInMixtape(
Expand All @@ -169,7 +169,7 @@ class MixtapeRoutes(private val mixtapeService: MixtapeService) {
)
private fun renameMixtape(ctx: Context) {
val currentUser = ctx.requireUser()
val mixtapeId = ctx.pathParam<Int>("mixtapeId").get()
val mixtapeId = ctx.pathParamAsClass<Int>("mixtapeId").get()
val body = ctx.validateJsonBody(RenameMixtapeBody::class.java)

val newSlug = mixtapeService.renameMixtape(
Expand All @@ -189,7 +189,7 @@ class MixtapeRoutes(private val mixtapeService: MixtapeService) {
)
private fun publishMixtape(ctx: Context) {
val currentUser = ctx.requireUser()
val mixtapeId = ctx.pathParam<Int>("mixtapeId").get()
val mixtapeId = ctx.pathParamAsClass<Int>("mixtapeId").get()

mixtapeService.publishMixtape(mixtapeId = mixtapeId, currentUser = currentUser)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class NotificationRoutes(private val notificationService: NotificationService) {
fun register() {
ApiBuilder.get("/api/notifications", this::getNotifications)
ApiBuilder.post("/api/notifications/mark-all-read", this::markAllRead)
ApiBuilder.post("/api/notifications/:id/read", this::markOneRead)
ApiBuilder.post("/api/notifications/{id}/read", this::markOneRead)
}

@OpenApi(
Expand Down Expand Up @@ -48,7 +48,7 @@ class NotificationRoutes(private val notificationService: NotificationService) {
)
private fun markOneRead(ctx: Context) {
val currentUser = ctx.requireUser()
val notificationId = ctx.pathParam<Int>("id").get()
val notificationId = ctx.pathParamAsClass<Int>("id").get()
notificationService.markOneRead(notificationId = notificationId, user = currentUser)
ctx.status(204)
}
Expand Down
19 changes: 10 additions & 9 deletions rhiannon/src/main/kotlin/club/jambuds/web/PlaylistRoutes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class PlaylistRoutes(
fun register() {
get("/api/public-feed", this::getPublicFeed)
get("/api/feed", this::getUserFeed)
get("/api/playlists/:userName", this::getUserPlaylist)
get("/api/playlists/:userName/liked", this::getUserLikesPlaylist)
get("/api/playlists/{userName}", this::getUserPlaylist)
get("/api/playlists/{userName}/liked", this::getUserLikesPlaylist)
}

@OpenApi(
Expand Down Expand Up @@ -97,9 +97,9 @@ class PlaylistRoutes(
private fun getUserPlaylist(ctx: Context) {
val currentUserId = ctx.currentUser?.id
val timestamps = getTimestamps(ctx)
val onlyMixtapes = ctx.queryParam<Boolean>("onlyMixtapes").getOrNull() ?: false
val onlyMixtapes = ctx.queryParamAsClass<Boolean>("onlyMixtapes").allowNullable().get() ?: false

val userName = ctx.pathParam<String>("userName").get()
val userName = ctx.pathParamAsClass<String>("userName").get()
val userProfile = userService.getUserProfileByName(userName)
?: throw NotFoundResponse("User not found with name $userName")

Expand Down Expand Up @@ -133,7 +133,7 @@ class PlaylistRoutes(
val currentUserId = ctx.currentUser?.id
val timestamps = getTimestamps(ctx)

val userName = ctx.pathParam<String>("userName").get()
val userName = ctx.pathParamAsClass<String>("userName").get()
val userProfile = userService.getUserProfileByName(userName)
?: throw NotFoundResponse("User not found with name $userName")

Expand All @@ -155,13 +155,14 @@ class PlaylistRoutes(
private data class Timestamps(val beforeTimestamp: Instant?, val afterTimestamp: Instant?)

private fun getTimestamps(ctx: Context): Timestamps {
val beforeTimestamp = ctx.queryParam<Instant>("before").getOrNull()
val afterTimestamp = ctx.queryParam<Instant>("after")
val beforeTimestamp = ctx.queryParamAsClass<Instant>("before").allowNullable().get()
val afterTimestamp = ctx.queryParamAsClass<Instant>("after")
.allowNullable()
.check(
{ beforeTimestamp == null },
{ it == null || beforeTimestamp == null },
"cannot have both 'beforeTimestamp' and 'afterTimestamp'"
)
.getOrNull()
.get()
return Timestamps(beforeTimestamp, afterTimestamp)
}
}
8 changes: 4 additions & 4 deletions rhiannon/src/main/kotlin/club/jambuds/web/PostRoutes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import io.javalin.plugin.openapi.annotations.OpenApiResponse
class PostRoutes(private val postService: PostService, private val reportService: ReportService) {
fun register() {
ApiBuilder.post("/api/posts", this::createPost)
ApiBuilder.delete("/api/posts/:postId", this::deletePost)
ApiBuilder.put("/api/posts/:postId/report", this::reportPost)
ApiBuilder.delete("/api/posts/{postId}", this::deletePost)
ApiBuilder.put("/api/posts/{postId}/report", this::reportPost)
}

enum class PostItemType(@get:JsonValue val type: String) {
Expand Down Expand Up @@ -80,7 +80,7 @@ class PostRoutes(private val postService: PostService, private val reportService
)
private fun deletePost(ctx: Context) {
val user = ctx.requireUser()
val postId = ctx.pathParam<Int>("postId").get()
val postId = ctx.pathParamAsClass<Int>("postId").get()
postService.deletePost(
user,
postId = postId
Expand All @@ -96,7 +96,7 @@ class PostRoutes(private val postService: PostService, private val reportService
)
private fun reportPost(ctx: Context) {
val user = ctx.requireUser()
val postId = ctx.pathParam<Int>("postId").get()
val postId = ctx.pathParamAsClass<Int>("postId").get()
reportService.createPostReport(user, postId)
ctx.status(204)
}
Expand Down
Loading