SMILEY4 / ktor-swagger-ui

Kotlin Ktor plugin to generate OpenAPI and provide Swagger UI
Apache License 2.0
156 stars 25 forks source link

Support for Resources (Type-safe routing) #56

Closed lukelast closed 12 months ago

lukelast commented 1 year ago

Are there any plans to support routes defined using ktor Resources?

https://ktor.io/docs/type-safe-routing.html https://github.com/ktorio/ktor-documentation/blob/2.3.2/codeSnippets/snippets/resource-routing/src/main/kotlin/resourcerouting/Application.kt

SMILEY4 commented 1 year ago

Hi,

kinda, i've been thinking about supporting Resources every now and then but i didnt have the time or the best solution yet.

I'll try to look into it again and see what i can do.

Blumbum commented 1 year ago

just try it like this:

inline fun <reified T : Any> Route.GET(
    noinline builder: OpenApiRoute.() -> Unit = { },
    noinline body: suspend PipelineContext<Unit, ApplicationCall>.(T) -> Unit
): Route {
    return documentation(builder) {
        resource<T> {
            method(HttpMethod.Get) {
                handle(body)
            }
        }
    }
}

i made a lib for myself to use your system with resources

Giuliopime commented 1 year ago

Any chance of getting some basic support for resources? Even without automatic route parameters from the resource class it would be fine for a basic usage.

SMILEY4 commented 1 year ago

so i've just very briefly looked into this and i think Type-safe routing / Resources should already be somewhat supported - though i am not that familiar with resources yet, so i might be missing something. Using the sample-code from the ktor-documentation, it should be possible to add the openapi-documentation like in the following example:

import io.github.smiley4.ktorswaggerui.SwaggerUI
import io.github.smiley4.ktorswaggerui.dsl.documentation
import io.ktor.resources.Resource
import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.application.install
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import io.ktor.server.resources.Resources
import io.ktor.server.resources.get
import io.ktor.server.response.respondText
import io.ktor.server.routing.routing

fun main() {
    embeddedServer(Netty, port = 8080, host = "localhost", module = Application::myModule).start(wait = true)
}

@Resource("/articles")
class Articles(val sort: String? = "new") {}

private fun Application.myModule() {
    install(SwaggerUI)
    install(Resources)

    routing {
        documentation({ // add documentation to a route by wrapping the 'io.ktor.server.resources.get'-method
            description = "Returns a sorted list of articles"
            request {
                queryParameter<String>("sort")
            }
        }) {
            get<Articles> { article ->
                call.respondText("List of articles sorted starting from ${article.sort}")
            }
        }
    }
}
Giuliopime commented 1 year ago

would it be hard to make a few extensions on the Route class for all the http methods with support for documentation inside them directly instead of wrapping each route with a routing? Kinda like @Blumbum did I guess

SMILEY4 commented 1 year ago

In theory yes, i could create a wrapper for a get, post, put, ... with openapi-documentation like @Blumbum did (exactly like i am currently doing it with the base ktor-routes). However, that would required a dependency on the resources-plugin in this library, which i would like to avoid. Another idea that would support all routes of all plugins without having any additional dependencies would be a slightly different way of adding documentation to a route:

get<Articles> { article ->
    call.respondText("List of articles sorted starting from ${article.sort}")
}.documented {
    description = "Returns a sorted list of articles"
    request {
        queryParameter<String>("sort")
    }
}

Maybe this as an generic alternative could be a first step :thinking:

Giuliopime commented 1 year ago

Why not adding the dependency? Is there any downside to that? I do like the generic way too, maybe more than the default one rn mhh

Giuliopime commented 1 year ago

Is this planned in the near future? Otherwise I could open a pr if you want

SMILEY4 commented 1 year ago

Is this planned in the near future? Otherwise I could open a pr if you want

Feel free to open one :D

Giuliopime commented 1 year ago

Which approach should I use? The generalised one or the "dependency dependant" one? Or both ^^

SMILEY4 commented 1 year ago

Which approach should I use? The generalised one or the "dependency dependant" one? Or both ^^

The one you think works best :)

I think the long term solution would be to split off support for specific plugins (e.g. resources) into their own projects (maybe with gradle multimodules) - so i'm also fine with depending on the resouces-plugin directly for now.

Giuliopime commented 1 year ago

I'll go with the resource dependency. Mostly because I think having the documentation below the route isn't that nice, it's much better to write the route code having the docs to refer to on top, plus maybe having docs at the bottom would make it easier to forget to actually write them. I have no experience in library development so I wont do any multimodule stuff, but it's definitely a great idea

SMILEY4 commented 12 months ago

Initial support for typesafe routing was added with version 2.5.0. Thanks to everyone involved.

Giuliopime commented 12 months ago

Thank you for creating this library, this really works amazingly now, love it ^^

Giuliopime commented 10 months ago

It seems like it's not behaving correctly, if I add a queryParameter to a resource route, it will add both the queryParameter (correctly) and an identical path parameter that shouldn't be there

There seem to be an automatic resources class conversion which shouldn't be there

Any idea of the code responsible of this?