Skip to content

Commit

Permalink
docs: initial gitbook docs (#336)
Browse files Browse the repository at this point in the history
  • Loading branch information
brizzbuzz committed Sep 30, 2022
1 parent 622dd6a commit 1759be5
Show file tree
Hide file tree
Showing 10 changed files with 474 additions and 57 deletions.
1 change: 1 addition & 0 deletions .gitbook.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
root: ./docs/
53 changes: 1 addition & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,4 @@

[![version](https://img.shields.io/maven-central/v/io.bkbn/kompendium-core?style=flat-square)](https://search.maven.org/search?q=io.bkbn%20kompendium)

## Table of Contents

- [What Is Kompendium](#what-is-kompendium)
- [How to Install](#how-to-install)
- [Local Development](#local-development)
- [The Playground](#the-playground)

## What is Kompendium

Kompendium is intended to be a minimally invasive OpenApi Specification generator for Ktor. Minimally invasive meaning
that users will use only Ktor native functions when implementing their API, and will supplement with Kompendium code in
order to generate the appropriate spec.

### Compatability

| Kompendium | Ktor | OpenAPI |
|------------|------|---------|
| 1.X | 1 | 3.0 |
| 2.X | 1 | 3.0 |
| 3.X | 2 | 3.1 |

## How to install

Kompendium publishes all releases to Maven Central. As such, using the release versions of `Kompendium` is as simple as
declaring it as an implementation dependency in your `build.gradle.kts`

```kotlin
repositories {
mavenCentral()
}

dependencies {
implementation("io.bkbn:kompendium-core:latest.release")
}
```

In addition to publishing releases to Maven Central, a snapshot version gets published to GitHub Packages on every merge
to `main`. These can be consumed by adding the repository to your gradle build file. Instructions can be
found [here](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-gradle-registry#using-a-published-package)

## Local Development

Kompendium should run locally right out of the box, no configuration necessary (assuming you have JDK 11+ installed).
New features can be built locally and published to your local maven repository with the `./gradlew publishToMavenLocal`
command!

## The Playground

This repo contains a `playground` module that contains a number of working examples showcasing the capabilities of
Kompendium.

Feel free to check it out, or even create your own example!
Documentation is stored in the `docs` folder and is hosted [here](https://bkbn.gitbook.io/kompendium)
3 changes: 0 additions & 3 deletions book.json

This file was deleted.

8 changes: 8 additions & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Summary

* [Introduction](index.md)
* [Plugins](plugins/index.md)
* [Notarized Application](plugins/notarized_application.md)
* [Notarized Route](plugins/notarized_route.md)
* [Notarized Locations](plugins/notarized_locations.md)
* [The Playground](playground.md)
102 changes: 100 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,101 @@
# Kompendium
Kompendium is intended to be a non-invasive OpenAPI spec generator for [Ktor](https://ktor.io) APIs. By operating
entirely through Ktor's plugin architecture, Kompendium allows you to incrementally document your API without requiring
you to rip out and replace the amazing code you have already written.

Hi :)
# Compatibility

| Kompendium | Ktor | OpenAPI |
|------------|------|---------|
| 1.X | 1 | 3.0 |
| 2.X | 1 | 3.0 |
| 3.X | 2 | 3.1 |

> These docs are focused solely on Kompendium 3, previous versions should be considered deprecated and no longer
> maintained
# Getting Started

## Adding the Artifact

All Kompendium artifacts are published to Maven Central. Most Kompendium users will only need to import the core
dependency

```kotlin
dependencies {
// other dependencies...
implementation("io.bkbn:kompendium-core:latest.release")
}
```

## Notarizing a Ktor Application

Once we have added the dependencies, installed the `NotarizedApplication` plugin. This is an application-level
Ktor plugin that is used to instantiate and configure Kompendium. Your OpenAPI spec metadata will go here, along with
custom type overrides (typically useful for custom scalars such as dates and times), along with other configurations.

```kotlin
private fun Application.mainModule() {
install(NotarizedApplication()) {
spec = OpenApiSpec(
// ...
)
}
}
```

At this point, you will have a valid OpenAPI specification generated at runtime, which can be accessed by default
at the `/openapi.json` path of your api.

For more detail on the `NotarizedApplication` plugin, please see the [docs](./plugins/notarized_application.md)

## Notarizing a Ktor Route

Once you have notarized your application, you can begin to notarize individual routes using the `NotarizedRoute` plugin.
This is a route-level Ktor plugin that is used to configure the documentation for a specific endpoint of your API. The
route documentation will be piped back to the application-level plugin, and will be automatically injected into the
OpenApi specification.

Setting up documentation on a route is easiest achieved by creating an extension function on the Ktor `Route` class

```kotlin
private fun Route.documentation() {
install(NotarizedRoute()) {
parameters = listOf(
Parameter(
name = "id",
`in` = Parameter.Location.path,
schema = TypeDefinition.STRING
)
)
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 😱")
}
}
}
}
```

Once you have created your documentation function, it can be attached to the route simply by calling it at the desired
path.

```kotlin
private fun Application.mainModule() {
// ...
routing {
// ...
route("/{id}") {
documentation()
get {
// ...
}
}
}
}
```

For more details on the `NotarizedRoute` plugin, please see the [docs](./plugins/notarized_route.md)
19 changes: 19 additions & 0 deletions docs/playground.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
The Playground is a module inside the Kompendium repository that provides out of the box examples for a variety of
Kompendium features.

At the moment, the following playground applications are

| Example | Description |
|--------------|------------------------------------------------------------|
| Basic | A minimally viable Kompendium application |
| Auth | Documenting authenticated routes |
| Custom Types | Documenting custom scalars to be used by Kompendium |
| Exceptions | Documenting exception responses |
| Gson | Serialization using Gson instead of the default Kotlinx |
| Hidden Docs | Place your generated documentation behind authorization |
| Jackson | Serialization using Jackson instead of the default KotlinX |
| Locations | Using the Ktor Locations API to define routes |

You can find all of the playground
examples [here](https://github.com/bkbnio/kompendium/tree/main/playground/src/main/kotlin/io/bkbn/kompendium/playground)
in the Kompendium repository
11 changes: 11 additions & 0 deletions docs/plugins/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Plugins are the lifeblood of Kompendium.

It starts with the `NotarizedApplication`, where Kompendium is instantiated and attached to the API. This is where spec
metadata is defined, custom types are defined, and more.

From there, a `NotarizedRoute` plugin is attached to each route you wish to document. This allows API documentation to
be an iterative process. Each route you notarize will be picked up and injected into the OpenAPI spec that Kompendium
generates for you.

Finally, there is the `NotarizedLocations` plugin that allows you to leverage and document your usage of the
Ktor [Locations](https://ktor.io/docs/locations.html) API.
105 changes: 105 additions & 0 deletions docs/plugins/notarized_application.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
The `NotarizedApplication` plugin sits at the center of the entire Kompendium setup. It is a pre-requisite to
installing any other Kompendium plugins.

# Configuration

Very little configuration is needed for a basic documentation setup, but
several configuration options are available that allow you to modify Kompendium to fit your needs.

## Spec

This is where you will define the server metadata that lives outside the scope of any specific route. For
full information, you can inspect the `OpenApiSpec` data class, and of course
reference [OpenAPI spec](https://spec.openapis.org/oas/v3.1.0) itself.

> ⚠️ Please note, the `path` field of the `OpenApiSpec` is intended to be filled in by `NotarizedRoute` plugin
> definitions. Writing custom paths manually could lead to unexpected behavior
## Custom Routing

For public facing APIs, having the default endpoint exposed at `/openapi.json` is totally fine. However, if you need
more granular control over the route that exposes the generated schema, you can modify the `openApiJson` config value.

For example, if we want to hide our schema behind a basic auth check, we could do the following

```kotlin
private fun Application.mainModule() {
// Install content negotiation, auth, etc...
install(NotarizedApplication()) {
// ...
openApiJson = {
authenticate("basic") {
route("/openapi.json") {
get {
call.respond(
HttpStatusCode.OK,
this@route.application.attributes[KompendiumAttributes.openApiSpec]
)
}
}
}
}
}
}
```

## Custom Types

Kompendium is _really_ good at converting simple scalar and complex objects into JsonSchema compliant specs. However,
there is a subset of values that cause it trouble. These are most commonly classes that produce "complex scalars",
such as dates and times, along with object representations of scalars such as `BigInteger`.

In situations like this, you will need to define a map of custom types to JsonSchema definitions that Kompendium can use
to short-circuit its type analysis.

For example, say we would like to serialize `kotlinx.datetime.Instant` entities as a field in our response objects. We
would need to add it as a custom type.

```kotlin
private fun Application.mainModule() {
// ...
install(NotarizedApplication()) {
spec = baseSpec
customTypes = mapOf(
typeOf<Instant>() to TypeDefinition(type = "string", format = "date-time")
)
}
}
```

Doing this will save it in a cache that our `NotarizedRoute` plugin definitions will check from prior to attempting to
perform type inspection.

This means that we only need to define our custom type once, and then Kompendium will reuse it across the entire
application.

> While intended for custom scalars, there is nothing stopping you from leveraging custom types to circumvent type
> analysis
> on any class you choose. If you have an alternative method of generating JsonSchema definitions, you could put them
> all
> in this map and effectively prevent Kompendium from having to do any reflection
## Schema Configurator

The `SchemaConfigurator` is an interface that allows users to bridge the gap between Kompendium serialization and custom
serialization strategies that the serializer they are using for their API. For example, if you are using KotlinX
serialization in order to convert kotlin fields from camel case to snake case, you could leverage
the `KotlinXSchemaConfigurator` in order to instruct Kompendium on how to serialize values properly.

```kotlin
private fun Application.mainModule() {
install(ContentNegotiation) {
json(Json {
serializersModule = KompendiumSerializersModule.module
encodeDefaults = true
explicitNulls = false
})
}
install(NotarizedApplication()) {
spec = baseSpec
// Adds support for @Transient and @SerialName
// If you are not using them this is not required.
schemaConfigurator = KotlinXSchemaConfigurator()
}
}
```
62 changes: 62 additions & 0 deletions docs/plugins/notarized_locations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
The Ktor Locations API is an experimental API that allows users to add increased type safety to their defined routes.

You can read more about it [here](https://ktor.io/docs/locations.html).

Kompendium supports Locations through an ancillary module `kompendium-locations`

## Adding the Artifact

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

```kotlin
dependencies {
implementation("io.bkbn:kompendium-locations:latest.release")
}
```

## Installing Plugin

Once you have installed the dependency, you can install the plugin. The `NotarizedLocations` plugin is an _application_
level plugin, and **must** be install after both the `NotarizedApplication` plugin and the Ktor `Locations` plugin.

```kotlin
private fun Application.mainModule() {
install(Locations)
install(NotarizedApplication()) {
spec = baseSpec
}
install(NotarizedLocations()) {
locations = mapOf(
Listing::class to NotarizedLocations.LocationMetadata(
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 `locations` property is a map of `KClass<*>` to metadata describing that locations metadata. This
metadata is functionally identical to how a standard `NotarizedRoute` is defined.

> ⚠️ If you try to map a class that is not annotated with the ktor `@Location` annotation, you will get a runtime
> exception!
Loading

0 comments on commit 1759be5

Please sign in to comment.