From 2bba75a91d12693f7966724f7f036c862de6174c Mon Sep 17 00:00:00 2001 From: James Fenn Date: Thu, 6 Aug 2020 20:33:54 -0400 Subject: [PATCH] update README, add documentation --- README.md | 69 +++++++++++++++++-- docs/src/me/jfenn/ktordocs/RestDocsFeature.kt | 11 +++ .../me/jfenn/ktordocs/interface/HasParams.kt | 4 ++ .../jfenn/ktordocs/interface/HasReferences.kt | 3 + .../me/jfenn/ktordocs/model/EndpointInfo.kt | 3 + .../me/jfenn/ktordocs/model/ResponseInfo.kt | 8 +++ 6 files changed, 94 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b63812a..eab8444 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Ktor-Docs [![JitPack](https://jitpack.io/v/dev.horrific.code.james/git-rest-wrapper.svg)](https://jitpack.io/#dev.horrific.code.james/ktordocs) [![Discord](https://img.shields.io/discord/514625116706177035.svg?logo=discord&colorB=7289da)](https://discord.jfenn.me/) +Ktor-Docs [![JitPack](https://jitpack.io/v/dev.horrific.code.james/ktordocs.svg)](https://jitpack.io/#dev.horrific.code.james/ktordocs) [![Discord](https://img.shields.io/discord/514625116706177035.svg?logo=discord&colorB=7289da)](https://discord.jfenn.me/) ===== This library automatically generates REST API documentation for Ktor/JVM projects and hosts it under a specified URL. @@ -24,13 +24,13 @@ implementation "dev.horrific.code.james:ktordocs:$ktordocs_version" ## Usage -First, you must install the ktor feature - replacing the configuration with your project's values. +First, you must install the ktor feature - replacing the default configuration with your project's values. ```kotlin install(RestDocsFeature) { baseUrl = "https://example.com" title = "Example API" - description = "Basic documentation generated for testing & demo purposes." + desc = "Basic documentation generated for testing & demo purposes." } ``` @@ -40,7 +40,7 @@ Documentation can then be specified in any endpoint/request handler by invoking get("/api/v1/example") { docs { title = "Hello World" - description = "Says hello to the world." + desc = "Says hello to the world." } call.respondText("Hello world!") @@ -55,6 +55,67 @@ route("/api") { } ``` +### Endpoint Parameters + +The library will automatically generate a list of URL parameters by parsing the endpoint URL - however, more information can be specified using the `param(...)` function... + +```kotlin +get("/api/user/{username}") { + docs { + param("username") { // a URL property + type = "SHA1 hash" + desc = "A unique identifier of a user." + } + param("fetchAll") { // a query parameter (/?fetchAll=true) + type = "boolean" + desc = "Whether to fetch all user information from external sources." + location = ParameterInfo.In.Query + } + } + + // ... +} +``` + +### Endpoint Responses + +Some endpoints may return different information depending on the response status - such as an error handler or authentication state. This can be specified using the `responds()` function. + +```kotlin +get("/api/user/{username}") { + docs { + responds { // default response behavior (200 OK) + desc = "If the user has been found." + + // this is a handy function to set the `example` property + // if your response uses a JSON serializer + exampleJson(UserInfo::class) + } + responds(HttpStatusCode.NotFound) { + desc = "If the user doesn't exist." + example = """{ "message": "Unable to locate the requested user." }""" + } + } + + // ... +} +``` + +### Links + +Endpoints can reference URL links as supporting material, which are provided in a list on the documentation page. + +```kotlin +get("/api/user/{username}") { + docs { + reference("https://example.com") + reference("https://example.com", "Example Link") + } + + // ... +} +``` + ## Development The project uses Gradle builds for... err... most things. `./gradlew :{module}:test` and `./gradle :{module}:run` are fairly universal. diff --git a/docs/src/me/jfenn/ktordocs/RestDocsFeature.kt b/docs/src/me/jfenn/ktordocs/RestDocsFeature.kt index 5ba91b8..5cdd370 100644 --- a/docs/src/me/jfenn/ktordocs/RestDocsFeature.kt +++ b/docs/src/me/jfenn/ktordocs/RestDocsFeature.kt @@ -116,6 +116,10 @@ class RestDocsFeature( } +/** + * Hosts the API documentation generated by the library + * at the specified path. + */ fun Route.restDocumentation(path: String = "/") { GlobalScope.launch { delay(500) @@ -129,6 +133,13 @@ fun Route.restDocumentation(path: String = "/") { } } +/** + * Provides documentation for a particular endpoint. + * Should be invoked at the start of the request handler. + * + * Under normal conditions, this function call does + * nothing. + */ fun PipelineContext.docs(configure: EndpointInfo.() -> Unit) { if (this is DummyPipelineContext) throw DocsProxyException(configure) diff --git a/docs/src/me/jfenn/ktordocs/interface/HasParams.kt b/docs/src/me/jfenn/ktordocs/interface/HasParams.kt index 5764e66..74501d0 100644 --- a/docs/src/me/jfenn/ktordocs/interface/HasParams.kt +++ b/docs/src/me/jfenn/ktordocs/interface/HasParams.kt @@ -6,6 +6,10 @@ interface HasParams { val params: HashMap + /** + * Provide information about a parameter or argument of a + * particular endpoint / request. + */ fun param(name: String, configure: ParameterInfo.() -> Unit = {}) { params[name] = (params[name] ?: ParameterInfo(name)).apply { configure() } } diff --git a/docs/src/me/jfenn/ktordocs/interface/HasReferences.kt b/docs/src/me/jfenn/ktordocs/interface/HasReferences.kt index cae677e..7dd8576 100644 --- a/docs/src/me/jfenn/ktordocs/interface/HasReferences.kt +++ b/docs/src/me/jfenn/ktordocs/interface/HasReferences.kt @@ -6,6 +6,9 @@ interface HasReferences { val references: ArrayList + /** + * Reference a link or URL. + */ fun reference(url: String, title: String = url) { references.add(ReferenceInfo(url, title)) } diff --git a/docs/src/me/jfenn/ktordocs/model/EndpointInfo.kt b/docs/src/me/jfenn/ktordocs/model/EndpointInfo.kt index ee6e1af..761ffea 100644 --- a/docs/src/me/jfenn/ktordocs/model/EndpointInfo.kt +++ b/docs/src/me/jfenn/ktordocs/model/EndpointInfo.kt @@ -21,6 +21,9 @@ class EndpointInfo( override val params = HashMap() internal val responses = HashMap() + /** + * Specify a particular response behavior of the current endpoint. + */ fun responds(code: HttpStatusCode = HttpStatusCode.OK, configure: ResponseInfo.() -> Unit = {}) { responses[code] = (responses[code] ?: ResponseInfo(code)).apply { configure() } } diff --git a/docs/src/me/jfenn/ktordocs/model/ResponseInfo.kt b/docs/src/me/jfenn/ktordocs/model/ResponseInfo.kt index a303b9c..5e88b5b 100644 --- a/docs/src/me/jfenn/ktordocs/model/ResponseInfo.kt +++ b/docs/src/me/jfenn/ktordocs/model/ResponseInfo.kt @@ -11,6 +11,14 @@ data class ResponseInfo( var example: String? = null ) { + /** + * Create an "example" JSON preview based on the + * provided data class. + * + * (this is intended for when there is a specific + * data class which is passed through a serializer + * to provide a response) + */ fun exampleJson(type: KClass<*>) { example = buildString { appendln("{") -- GitLab