add neko controller

This commit is contained in:
Denis Savosin
2024-10-24 13:12:15 +07:00
parent 24129c8102
commit 853cb67455
6 changed files with 119 additions and 1 deletions

View File

@@ -0,0 +1,26 @@
package com.github.dannecron.demo.http.controllers
import com.github.dannecron.demo.http.responses.neko.ImagesResponse
import com.github.dannecron.demo.services.neko.Client
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping(value = ["/api/neko"], produces = [MediaType.APPLICATION_JSON_VALUE])
class NekoController(
private val nekoClient: Client,
) {
@GetMapping("/categories")
fun categories(): ResponseEntity<Any> = ResponseEntity(nekoClient.getCategories(), HttpStatus.OK)
@GetMapping("/images/{category}")
fun images(
@PathVariable category: String,
@RequestParam imagesCount: Int = 1,
): ResponseEntity<Any> = ResponseEntity(
ImagesResponse(baseImages = nekoClient.getImages(category = category, amount = imagesCount)),
HttpStatus.OK,
)
}

View File

@@ -1,6 +1,7 @@
package com.github.dannecron.demo.http.exceptions
import com.github.dannecron.demo.http.responses.BadRequestResponse
import com.github.dannecron.demo.http.responses.BaseResponse
import com.github.dannecron.demo.http.responses.NotFoundResponse
import com.github.dannecron.demo.http.responses.UnprocessableResponse
import org.springframework.http.HttpStatus
@@ -42,4 +43,12 @@ class ExceptionHandler {
UnprocessableResponse(exception.javaClass.name, exception.allErrors),
HttpStatus.UNPROCESSABLE_ENTITY,
)
// 500
@ExceptionHandler(RuntimeException::class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
fun handleUnexpectedRuntimeException(exception: RuntimeException): ResponseEntity<Any> = ResponseEntity(
BaseResponse(com.github.dannecron.demo.http.responses.ResponseStatus.INTERNAL_ERROR),
HttpStatus.INTERNAL_SERVER_ERROR,
)
}

View File

@@ -6,5 +6,6 @@ enum class ResponseStatus(@JsonValue val status: String) {
OK("ok"),
NOT_FOUND("not found"),
BAD_REQUEST("bad request"),
UNPROCESSABLE("unprocessable");
UNPROCESSABLE("unprocessable"),
INTERNAL_ERROR("internal");
}

View File

@@ -0,0 +1,14 @@
package com.github.dannecron.demo.http.responses.neko
import kotlinx.serialization.Serializable
@Serializable
data class Image(
val url: String,
val animeName: String?,
val artistHref: String?,
val artistName: String?,
val sourceUrl: String?,
) {
fun isGif() = animeName != null
}

View File

@@ -0,0 +1,15 @@
package com.github.dannecron.demo.http.responses.neko
import kotlinx.serialization.Serializable
import com.github.dannecron.demo.services.neko.dto.ImagesResponse as BaseResponse
@Serializable
data class ImagesResponse(
val images: List<Image>,
) {
constructor(baseImages: BaseResponse): this(
images = baseImages.results.map {
Image(it.url, it.animeName, it.artistHref, it.artistName, it.sourceUrl)
}
)
}

View File

@@ -0,0 +1,53 @@
package com.github.dannecron.demo.http.controllers
import com.github.dannecron.demo.BaseUnitTest
import com.github.dannecron.demo.services.neko.Client
import com.github.dannecron.demo.services.neko.dto.Image
import com.github.dannecron.demo.services.neko.dto.ImagesResponse
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.whenever
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
import kotlin.test.Test
@WebMvcTest(NekoController::class)
class NekoControllerTest(
@Autowired val mockMvc: MockMvc,
): BaseUnitTest() {
@MockBean
private lateinit var nekoClient: Client
@Test
fun categories_success() {
whenever(nekoClient.getCategories()) doReturn setOf("cat1", "cat2")
mockMvc.get("/api/neko/categories")
.andExpect { status { isOk() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { content { string("""["cat1","cat2"]""") } }
}
@Test
fun images_success() {
val category = "some"
val animeName = "boku no pico"
whenever(nekoClient.getImages(category = category, amount = 1)) doReturn ImagesResponse(
results = listOf(
Image(
"http://localhost",
animeName = animeName,
)
)
)
mockMvc.get("/api/neko/images/$category")
.andExpect { status { isOk() } }
.andExpect { content { contentType(MediaType.APPLICATION_JSON) } }
.andExpect { jsonPath("\$.images[0].animeName") { value(animeName) } }
.andExpect { jsonPath("\$.images[0].artistName") { value(null) } }
}
}