Skip to content
This repository was archived by the owner on Mar 31, 2025. It is now read-only.

Add Http Methode typed NotarizedResource #704

@ezienecker

Description

@ezienecker

Is your feature request related to a problem? Please describe.

Ktor offers several ways to organize the typed safe routes. We favor the approach where you have a separate method for each route. For us it offers the most flexibility to group these by paths:

routing {
  route("/api") {
    listUserRoute()

    getUserRoute()
    getUserRolesRoute()
    assignUserRolesRoute()
  }

  route("/system") {
    createUserRoute()
    createUserRoleRoute()
  }
}

This has the consequence that we also implement the documentation per route method. If we now implement the documentation for the List User endpoint and the Create User endpoint:

fun Route.createUserRoute() {
  createUserDocumentation()
  ...
}

private fun Route.createUserDocumentation() {
  install(NotarizedResource<User>()) {
  }
}

fun Route.listUserRoute() {
  listUserDocumentation()
  ...
}

private fun Route.listUserDocumentation() {
  install(NotarizedResource<User>()) {
  }
}

we will get the following error:

io.ktor.server.application.DuplicatePluginException: Please make sure that you use unique name for the plugin and don't install it twice. Plugin `io.bkbn.kompendium.resources.NotarizedResource@aafcffa<io.bkbn.kompendium.playground.User>` is already installed to the pipeline /

This makes sense because both use the User resource. One route with the Get method and the other with the Post method.

Describe the solution you'd like

An analysis has shown that the problem comes from the way the plugin is installed (NotarizedResource.kt):

  inline operator fun <reified T> invoke() = createRouteScopedPlugin(
    name = "NotarizedResource<${T::class.qualifiedName}>",
    createConfiguration = NotarizedRoute::Config
  ) {
  ...
}

One way to solve this problem would be if the Http methods could be found in io.bkbn.kompendium.resources.NotarizedResource. This means that in future there will be the following NotarizedResource:

  • NotarizedResource (for backward compatibility reasons)
  • NotarizedGetResource
  • NotarizedPostResource
  • NotarizedPutResource
  • NotarizedDeleteResource
  • NotarizedHeadResource
  • NotarizedPatchResource
  • NotarizedOptionsResource

The current class NotarizedResource is renamed to NotarizedMethodResource and becomes an abstract class. All the NotarizedResource mentioned above inherit from this class and are the new objects. The invoke method is also adapted accordingly:

  inline operator fun <reified T> invoke() = createRouteScopedPlugin(
    name = "$this<${T::class.qualifiedName}>",
    createConfiguration = NotarizedRoute::Config
  ) {
  ...
}

This means that the documentation will be even more strongly typified in future because the Http method is used as a plug-in name in addition to the resource.

The new implementation will look like this:

fun Route.createUserRoute() {
  createUserDocumentation()
  ...
}

private fun Route.createUserDocumentation() {
  install(NotarizedPostResource<User>()) {
  }
}

fun Route.listUserRoute() {
  listUserDocumentation()
  ...
}

private fun Route.listUserDocumentation() {
  install(NotarizedGetResource<User>()) {
  }
}

Describe alternatives you've considered
I have not found an alternative to the above approach.

Additional context
If desired, I can open a pull request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions