utybo / Tegral

🟣 A Kotlin framework for web applications, cool libraries that go along with it!
https://tegral.zoroark.guru
Apache License 2.0
38 stars 4 forks source link

ktor-resources: cannot describe multiple methods on single resource when using getD/postD/etc. #59

Closed Ribesg closed 1 year ago

Ribesg commented 1 year ago

I have an endpoint which can receive either a GET to retrieve the resource or a DELETE to delete it.

Those methods should have different documentation (different response types, summary, response codes, etc.) but I don't see a way to do that using the resource companion object way.

Right now I defined two objects Get and Delete in my resource instead of a companion object, and I use the normal get delete endpoint definition functions with describe MyResource.Get.openApi and describe MyResource.Delete.openApi, but it's not ideal as it's a different way to document endpoints than when the resource only has one method used, which makes it a little harder to understand for reviewers etc.

Ribesg commented 1 year ago

Maybe describeResource could have a version with a vararg parameter with each element having to specify a value for a new method field or it throws, and you could have multiple documentations this way.

Or maybe we should just always have to specify the method so that everything is a little more strongly typed. Maybe something like:

describeResource({

    get {
        summary = "…"
    }

    delete {
        summary = "…"
    }

})
Ribesg commented 1 year ago

After reading some more docs, I feel like describeResource should just use PathDsl instead of OperationDsl? That's it I think

utybo commented 1 year ago

After reading some more docs, I feel like describeResource should just use PathDsl instead of OperationDsl? That's it I think

I think that would be a pretty good solution, but being able to define "common properties" that are used across all operations in a resource (e.g. query parameters) would be handy, e.g.

@Serializable @Resource("/cat/{id}")
class Cat(val id: Long) {
    companion object : OpenApiDescription by describeResource({
        "id" pathParameter {
            description = "The ID of the cat"
        }

        get { 
            description = "Get the cat with the given ID"
        }

        put {
            description = "Update the cat with the given ID"
        }
    })
}

This should be feasible and not too hard to do. Also, this makes me think that supporting this use case with nested resources would be very handy too, and I don't think this is currently supported:

@Serializable @Resource("/cat/{id}")
class Cat(val id: Long) {
    companion object : OpenApiDescription by describeResource({
        "id" pathParameter {
            description = "The ID of the cat"
        }

        get { 
            description = "Get the cat with the given ID"
        }

        put {
            description = "Update the cat with the given ID"
        }
    })

    @Serializable @Resource("/adopt")
    class Adopt() {
        companion object : OpenApiDescription by describeResource({
            post {
                description = "Adopt the cat with the given ID"
            }
        })
    }
}