Notarized Resources

The Ktor Resources API allows users to define their routes in a type-safe manner.

You can read more about it here.

Kompendium supports Ktor-Resources through an ancillary module kompendium-resources

Adding the Artifact

Prior to documenting your resources, you will need to add the artifact to your gradle build file.

dependencies {
  implementation("io.bkbn:kompendium-resources:$version")
}

NotarizedResources

The NotarizedResources plugin is an application level plugin, and must be installed after both the NotarizedApplication plugin and the Ktor Resources plugin. It is intended to be used to document your entire application in a single block.

private fun Application.mainModule() {
  install(Resources)
  install(NotarizedApplication()) {
    spec = baseSpec
  }
  install(NotarizedResources()) {
    resources = mapOf(
      Listing::class to NotarizedResources.ResourceMetadata(
        parameters = listOf(
          Parameter(
            name = "name",
            `in` = Parameter.Location.path,
            schema = TypeDefinition.STRING
          ),
          Parameter(
            name = "page",
            `in` = Parameter.Location.path,
            schema = TypeDefinition.INT
          )
        ),
        get = GetInfo.builder {
          summary("Get user by id")
          description("A very neat endpoint!")
          response {
            responseCode(HttpStatusCode.OK)
            responseType<ExampleResponse>()
            description("Will return whether or not the user is real 😱")
          }
        }
      ),
    )
  }
}

Here, the resources property is a map of KClass<*> to ResourceMetadata instance describing that resource. This metadata is functionally identical to how a standard NotarizedRoute is defined.

NotarizedResource

If you prefer a route-based approach similar to NotarizedRoute, you can use the NotarizedResource<MyResourceType>() plugin instead of NotarizedResources. It will combine paths from any parent route with the route defined in the resource, exactly as Ktor itself does:

@Serializable
@Resource("/list/{name}/page/{page}")
data class Listing(val name: String, val page: Int)

private fun Application.mainModule() {
  install(Resources)
  route("/api") {
    listingDocumentation()
    get<Listing> { listing ->
      call.respondText("Listing ${listing.name}, page ${listing.page}")
    }
  }
}

private fun Route.listingDocumentation() {
  install(NotarizedResource<Listing>()) {
    parameters = listOf(
      Parameter(
        name = "name",
        `in` = Parameter.Location.path,
        schema = TypeDefinition.STRING
      ),
      Parameter(
        name = "page",
        `in` = Parameter.Location.path,
        schema = TypeDefinition.INT
      )
    )
    get = GetInfo.builder {
      summary("Get user by id")
      description("A very neat endpoint!")
      response {
        responseCode(HttpStatusCode.OK)
        responseType<ExampleResponse>()
        description("Will return whether or not the user is real 😱")
      }
    }
  }
}

In this case, the generated path will be /api/list/{name}/page/{page}, combining the route prefix with the path in the resource.

Last updated