papsign / Ktor-OpenAPI-Generator

Ktor OpenAPI/Swagger 3 Generator
Apache License 2.0
241 stars 42 forks source link

API route with Any must be a data class. #121

Closed Groodian closed 2 years ago

Groodian commented 2 years ago

The route works fine if i run the application, but if i am trying to run this inside the test the route does not work.

fun NormalOpenAPIRoute.loginRoute(jwtConfig: JwtConfig) {

    route("login") {

        throws(
            HttpStatusCode.NotFound,
            LoginResponse(false, null, credentialsInvalid),
            { _: InvalidCredentials -> LoginResponse(false, null, credentialsInvalid) }) {

            post<Any, LoginResponse, LoginRequest>(
                info(
                    summary = "Login",
                    description = "Login to the API.",
                ),
                exampleRequest = LoginRequest.EXAMPLE,
                exampleResponse = LoginResponse.EXAMPLE,
            ) { _, loginRequest ->

                run {

                    val user = userRepository.getUser(loginRequest.username, loginRequest.password)
                    if (user == null) {
                        throw InvalidCredentials()
                    } else {
                        val token = jwtConfig.generateToken(JwtUser(user.id, user.name))
                        respond(LoginResponse(true, token, loginSuccessful))
                    }

                }

            }

        }

    }

}
@Test
    fun testLogin() {
        var token: String? = null

        withTestApplication({ module(true) }) {
            handleRequest(HttpMethod.Post, "/api/login") {
                addHeader(HttpHeaders.ContentType, ContentType.Application.Json.toString())
                setBody(Gson().toJson(LoginRequest("Admin", "Admin")))
            }.apply {
                assertEquals(HttpStatusCode.OK, response.status())

                val loginResponse: LoginResponse =
                    Gson().fromJson(response.content, LoginResponse::class.java)
                assertEquals(loginResponse.ok, true)
                assertNotNull(loginResponse.token)
                assertNotNull(loginResponse.message)

                token = loginResponse.token
            }
        }

        withTestApplication({ module(true) }) {
            handleRequest(HttpMethod.Get, "/api/me") {
                addHeader("Authorization", "Bearer $token")
            }.apply {
                assertEquals(HttpStatusCode.OK, response.status())

                val user: JwtUser = Gson().fromJson(response.content, JwtUser::class.java)

                assertEquals(user.id, 1)
                assertEquals(user.name, "Admin")
            }
        }

    }

Error when running the test:

API route with Any must be a data class.
java.lang.AssertionError: API route with Any must be a data class.
    at com.papsign.ktor.openapigen.parameters.util.UtilKt.buildParameterHandler(Util.kt:21)
    at com.papsign.ktor.openapigen.route.OpenAPIRoute.handle(OpenAPIRoute.kt:43)
    at com.papsign.ktor.openapigen.route.path.normal.NormalOpenAPIRoute.handle(NormalOpenAPIRoute.kt:25)
    at de.h_da.fbi.findus.routes.AuthenticationKt$loginRoute$lambda-1$lambda-0$$inlined$post$1.invoke(Functions.kt:169)
    at de.h_da.fbi.findus.routes.AuthenticationKt$loginRoute$lambda-1$lambda-0$$inlined$post$1.invoke(Functions.kt:168)
    at com.papsign.ktor.openapigen.route.FunctionsKt.preHandle(Functions.kt:162)
    at de.h_da.fbi.findus.routes.AuthenticationKt.loginRoute(Authentication.kt:115)
    at de.h_da.fbi.findus.ApplicationKt$module$7.invoke(Application.kt:136)
    at de.h_da.fbi.findus.ApplicationKt$module$7.invoke(Application.kt:126)
    at com.papsign.ktor.openapigen.route.RouteConfigKt$apiRouting$1.invoke(RouteConfig.kt:21)
    at com.papsign.ktor.openapigen.route.RouteConfigKt$apiRouting$1.invoke(RouteConfig.kt:17)
    at io.ktor.routing.RoutingKt.routing(Routing.kt:129)
    at com.papsign.ktor.openapigen.route.RouteConfigKt.apiRouting(RouteConfig.kt:17)
    at de.h_da.fbi.findus.ApplicationKt.module(Application.kt:126)
    at de.h_da.fbi.findus.ApplicationTest$testLogin$1.invoke(ApplicationTest.kt:30)
    at de.h_da.fbi.findus.ApplicationTest$testLogin$1.invoke(ApplicationTest.kt:30)
    at io.ktor.server.testing.TestEngineKt$withTestApplication$1.invoke(TestEngine.kt:67)
    at io.ktor.server.testing.TestEngineKt$withTestApplication$1.invoke(TestEngine.kt:66)
    at io.ktor.server.testing.TestEngineKt.withApplication(TestEngine.kt:49)
    at io.ktor.server.testing.TestEngineKt.withApplication$default(TestEngine.kt:41)
    at io.ktor.server.testing.TestEngineKt.withTestApplication(TestEngine.kt:66)
    at de.h_da.fbi.findus.ApplicationTest.testLogin(ApplicationTest.kt:30)
Wicpar commented 2 years ago

You must provide a class that can be analyzed by the library to generate the appropriate documentation. Any doesn't mean anything so it makes no sense to allow that. If you mean it returns nothing you can use Unit. If it returns an empty object create an empty data class.

Groodian commented 2 years ago

Thanks for your answer. I don't want to return anything, i don't want a parameter. I replaced Any with UInt, but I still get an error.

API route with UInt must be a data class.

And I can't find a way to create an empty data class because it needs a parameter for a data class.

darkxanter commented 2 years ago

Unit not UInt

Groodian commented 2 years ago

Oh sorry, now it works.