Compare commits

..

240 Commits

Author SHA1 Message Date
c3526dc807 fix(deps): update dependency com.charleskorn.kaml:kaml to v0.74.0 (#715)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-31 18:56:14 +00:00
a24abad7ad fix(deps): update kotestversion to v6.0.0.m3 (#714)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-31 06:25:34 +00:00
ef92254b99 fix(deps): update dependency joda-time:joda-time to v2.14.0 (#711)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-29 13:46:55 +00:00
0ef755a0f4 fix(deps): update ktor to v3.1.2 (#710)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-27 12:31:59 +00:00
1d16bcccd6 fix(deps): update dependency com.charleskorn.kaml:kaml to v0.73.0 (#709)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-20 21:59:12 +00:00
90d78a1898 fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v2.1.20 (#708)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-20 20:04:48 +00:00
797fdabf5d chore(deps): update plugin org.jetbrains.kotlin.jvm to v2.1.20 (#706)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-20 15:13:24 +00:00
140130fd34 chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v2.1.20 (#707)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-20 11:59:45 +00:00
b449545460 chore(deps): update plugin com.vanniktech.maven.publish to v0.31.0 (#703)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 12:04:09 +00:00
8f711bbd62 fix(deps): update slf4j monorepo to v2.0.17 (#701)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-25 22:43:33 +00:00
1d0d18b254 chore(deps): update dependency gradle to v8.13 (#700)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-25 12:01:39 +00:00
e021efd8f2 fix(deps): update ktor to v3.1.1 (#699)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-24 18:33:31 +00:00
97a46ae8c6 fix(deps): update dependency io.gitlab.arturbosch.detekt:detekt-formatting to v1.23.8 (#698)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-21 16:10:09 +00:00
f7b90bc795 fix(deps): update dependency com.charleskorn.kaml:kaml to v0.72.0 (#697)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-12 07:39:52 +00:00
99b9addb00 fix(deps): update ktor to v3.1.0 (#696)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-11 20:09:06 +00:00
b452d95764 fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-datetime to v0.6.2 (#695)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-11 12:38:34 +00:00
641ab78ebd fix(deps): update dependency com.charleskorn.kaml:kaml to v0.71.0 (#694)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-10 01:46:15 +00:00
60aa7b885a fix(deps): update kotestversion to v6.0.0.m2 (#693)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-04 14:47:02 +00:00
9fcb591795 fix(deps): update dependency joda-time:joda-time to v2.13.1 (#692)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-03 16:31:55 +00:00
1a70e66daf fix(deps): update dependency com.charleskorn.kaml:kaml to v0.70.0 (#691)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-01 21:09:35 +00:00
afc69f447d fix(deps): update dependency com.charleskorn.kaml:kaml to v0.68.0 (#690)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-01 04:33:51 +00:00
0fbf7361d0 fix(deps): update dependency com.charleskorn.kaml:kaml to v0.67.1 (#689)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-30 04:26:08 +00:00
05bf4475cc chore(deps): update plugin org.jetbrains.kotlin.jvm to v2.1.10 (#686)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-28 00:37:03 +00:00
bdea0de2c5 fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v2.1.10 (#688)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-27 22:25:46 +00:00
d0c91d1ec1 chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v2.1.10 (#687)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-27 17:00:19 +00:00
819739d7f1 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.25.6 (#685)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-25 00:46:47 +00:00
6ccefae81c chore(deps): update dependency gradle to v8.12.1 (#684)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-24 13:39:30 +00:00
6b7c789dd2 chore(deps): update plugin org.jetbrains.kotlinx.kover to v0.9.1 (#679)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-08 17:28:50 +00:00
054f6aad44 fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.8.0 (#678)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-07 19:13:42 +00:00
958beb1b9c chore(deps): update dependency gradle to v8.12 (#675)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-20 17:34:43 +00:00
a0489d4a00 fix(deps): update dependency com.charleskorn.kaml:kaml to v0.67.0 (#674)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-20 04:53:15 +00:00
20cdf6bcad fix(deps): update ktor to v3.0.3 (#673)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-18 22:59:50 +00:00
803d1c5451 fix(deps): update log4j2 monorepo to v2.24.3 (#671)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-13 13:08:16 +00:00
b9b26ea8eb chore(deps): update plugin org.jetbrains.kotlinx.kover to v0.9.0 (#670)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-12 20:20:30 +00:00
08c7ad08bc fix(deps): update ktor to v3.0.2 (#669)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-03 19:33:56 +00:00
506372b74c fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v2.1.0 (#668)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-28 00:07:39 +00:00
29a38f72b8 chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v2.1.0 (#667)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-27 15:34:00 +00:00
fd1996bdd4 chore(deps): update plugin org.jetbrains.kotlin.jvm to v2.1.0 (#666)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-27 14:10:10 +00:00
2084828eec fix(deps): update dependency com.charleskorn.kaml:kaml to v0.66.0 (#665)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 06:57:50 +00:00
417e21c0a7 fix(deps): update dependency org.apache.logging.log4j:log4j-api to v2.24.2 (#663)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-22 17:35:12 +00:00
641c995171 fix(deps): update dependency org.apache.logging.log4j:log4j-core to v2.24.2 (#662)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-22 14:10:31 +00:00
a7d6b0dd70 chore(deps): update dependency gradle to v8.11.1 (#660)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-20 17:51:51 +00:00
c9eb45ff1d fix(deps): update dependency com.charleskorn.kaml:kaml to v0.65.0 (#658)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-14 04:24:42 +00:00
38081606f3 chore: prep for 4.0.3 2024-11-11 14:39:25 -05:00
4562c8f7e5 fix(deps): update dependency com.charleskorn.kaml:kaml to v0.63.0 (#657)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 19:36:28 +00:00
0e2f7acb24 chore(deps): update burrunan/gradle-cache-action action to v2 (#632)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 14:33:54 -05:00
636bf65c36 fix: add missing mapping of BooleanEnrichment to EnrichmentHandler (#655) 2024-11-11 14:33:45 -05:00
4a9165fd3a chore(deps): update dependency gradle to v8.11 (#656)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 18:11:31 +00:00
c2ce172024 fix: resources plugin not published 2024-11-04 14:39:31 -05:00
d94eae93ad fix(deps): update dependency com.charleskorn.kaml:kaml to v0.62.2 (#651)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-01 04:53:08 +00:00
f874cb74e3 chore: add stacktrace to release workflow 2024-10-31 11:47:03 -04:00
9bd3b2e1e6 fix: maybe actually fixed gradle publishing for real this time?? 2024-10-31 11:41:14 -04:00
0958d5a874 fix(deps): update dependency com.charleskorn.kaml:kaml to v0.62.1 (#649)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-31 00:09:06 +00:00
c53c0b045d chore: add test suffix to version for now 2024-10-30 16:50:26 -04:00
fb0d3bb1dd fix: on the path to fixing publishing to maven central (#648) 2024-10-30 16:49:26 -04:00
1580d679d0 fix(deps): update ktor to v3.0.1 (#647)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-30 20:41:40 +00:00
540dad1f00 fix(deps): update dependency com.charleskorn.kaml:kaml to v0.62.0 (#614)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-30 20:27:07 +00:00
21f922a296 major: ktor 3.0.0 support - fixes #644 (#645) 2024-10-30 16:21:46 -04:00
fa7b1e5833 fix(deps): update log4j2 monorepo to v2.24.1 (#641)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-29 16:17:59 +00:00
35110e8ad4 chore(deps): update dependency gradle to v8.10.2 (#639)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-24 00:31:10 +00:00
18d64a2ed1 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.25.5 (#638)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-19 02:17:32 +00:00
4ffb04976a fix(deps): update dependency joda-time:joda-time to v2.13.0 (#637)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-16 02:03:13 +00:00
76b6288216 chore(deps): update dependency gradle to v8.10.1 (#636)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-09 10:14:04 +00:00
80f6f28b57 fix(deps): update dependency io.gitlab.arturbosch.detekt:detekt-formatting to v1.23.7 (#635)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-08 17:23:03 +00:00
bf8b2b40f6 fix(deps): update log4j2 monorepo to v2.24.0 (#634)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-06 22:22:21 +00:00
7c6826b366 fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-datetime to v0.6.1 (#633)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-20 14:45:36 +00:00
ee56c8023e feat: add nix flake (#631) 2024-08-15 08:10:05 +00:00
01c4e0558d chore(deps): update dependency gradle to v8.10 (#630)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-14 14:17:30 +00:00
a760121af5 fix(deps): update slf4j monorepo to v2.0.16 (#629)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-10 11:35:03 +00:00
b80ff3a998 fix(deps): update slf4j monorepo to v2.0.15 (#628)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-08 13:50:11 +00:00
8141be4b21 fix(deps): update slf4j monorepo to v2.0.14 (#627)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-06 22:59:39 +00:00
7fbc2523e2 fix(deps): update dependency org.apache.logging.log4j:log4j-api-kotlin to v1.5.0 (#626)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-06 13:46:51 +00:00
3349e9dab7 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.25.4 (#624)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-25 00:22:31 +00:00
da8439e1b7 fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.9.25 (#623)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-19 22:17:39 +00:00
e2d7d16571 chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.9.25 (#621)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-19 20:25:38 +00:00
f348910b63 chore(deps): update plugin org.jetbrains.kotlinx.kover to v0.8.3 (#622)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-19 17:47:28 +00:00
7ed4c8075b chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.9.25 (#620)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-19 12:58:27 +00:00
87ba80b6bb chore(deps): update dependency gradle to v8.9 (#619)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-11 18:12:10 +00:00
e10f3b4c47 chore(deps): update plugin org.jetbrains.kotlinx.kover to v0.8.2 (#617)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-27 18:06:06 +00:00
a7853ce353 fix(deps): update ktor to v2.3.12 (#602)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-20 22:25:00 +00:00
da654e5664 chore(deps): update plugin org.jetbrains.kotlinx.kover to v0.8.1 (#616)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-10 16:46:32 +00:00
d21434fdd0 fix(deps): update kotestversion to v5.9.1 (#611)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-06 13:00:49 +00:00
8a94f6e498 chore(deps): update dependency gradle to v8.8 (#609)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-31 23:30:31 +00:00
7a58914466 chore(deps): update plugin org.jetbrains.kotlinx.kover to v0.8.0 (#605)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 21:31:02 +00:00
2da6088303 fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-datetime to v0.6.0 (#604)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-14 20:19:24 +00:00
1ad82f7e8e fix(deps): update kotestversion to v5.9.0 (#603)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-09 19:50:12 +00:00
6117443c8b fix(deps): update ktor to v2.3.11 (#601)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-08 12:18:50 +00:00
f8e098eb07 chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.9.24 (#600)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-07 14:24:10 +00:00
e2affe3f4b chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.9.24 (#599)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-07 09:49:42 +00:00
a78b51be07 fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.9.24 (#598)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-07 08:09:51 +00:00
fa96923a5a fix(deps): update dependency com.charleskorn.kaml:kaml to v0.59.0 (#595)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-23 06:23:17 +00:00
464fa2d98a fix(deps): update slf4j monorepo to v2.0.13 (#594)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-12 15:34:54 +00:00
11e0d248b5 fix(deps): update ktor to v2.3.10 (#593)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-08 11:53:56 +00:00
2612010a88 fix(deps): update dependency io.gitlab.arturbosch.detekt:detekt-formatting to v1.23.6 (#591)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-25 02:40:23 +00:00
cb78d19b89 chore(deps): update dependency gradle to v8.7 (#590)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-22 16:44:44 +00:00
28bce9c443 fix(deps): update dependency com.charleskorn.kaml:kaml to v0.58.0 (#589)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-20 06:50:06 +00:00
d7dad48808 fix(deps): update kotestversion to v5.8.1 (#586)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-11 08:17:38 +00:00
2ea97ba2c2 fix(deps): update log4j2 monorepo to v2.23.1 (#585)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-10 19:59:12 +00:00
944c632a1d chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.9.23 (#583)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-07 17:26:42 +00:00
d1c52c010e fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.9.23 (#584)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-07 13:31:27 +00:00
d9f78b4e9f chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.9.23 (#582)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-07 11:01:23 +00:00
dcde50de0a chore: rollback docs due to sonatype disaster (#581) 2024-03-06 10:16:00 -05:00
889fdb41d7 fix(deps): update ktor to v2.3.9 (#580)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-04 13:41:49 +00:00
837108bbef fix(deps): update log4j2 monorepo to v2.23.0 (#578)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-21 10:41:07 +00:00
ee9e3b03b3 chore(deps): update plugin org.jetbrains.kotlinx.kover to v0.7.6 (#577)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-17 04:24:06 +00:00
3cc6e9f2e7 fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.6.3 (#576)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-16 19:14:23 +00:00
60eb3b6474 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.25.3 (#575)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-16 07:37:42 +00:00
65c0137a46 fix(deps): update slf4j monorepo to v2.0.12 (#574)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-06 00:39:17 +00:00
c277e559f4 fix(deps): update dependency joda-time:joda-time to v2.12.7 (#573)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-04 22:52:44 +00:00
8a161466d6 chore(deps): update dependency gradle to v8.6 (#572)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-02 19:58:27 +00:00
9a4ad2f737 fix(deps): update ktor to v2.3.8 (#570)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-31 14:20:13 +00:00
eb4d3ca7de fix(deps): update dependency io.gitlab.arturbosch.detekt:detekt-formatting to v1.23.5 (#569)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-31 10:56:32 +00:00
7a8bb43675 docs: update docs for 4.0 release (#567) 2024-01-21 16:12:02 -05:00
ac464ea9ca feat: enriched enrichments (#566) 2024-01-21 14:15:21 -05:00
c7545b1072 chore: yaml example (#564) 2024-01-17 16:30:37 -05:00
353637bb94 fix: enum type def (#563) 2024-01-17 16:14:47 -05:00
3d1fc566d4 chore: bump sourdough (#562) 2024-01-15 11:43:13 -05:00
79ddb2e4ae fix(deps): update dependency com.google.protobuf:protobuf-java to v3.25.2 (#560)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 16:07:21 +00:00
d004166a2e fix(deps): update dependency org.slf4j:slf4j-simple to v2.0.11 (#559)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-08 21:42:05 +00:00
dc6dbdf1c0 fix(deps): update dependency org.slf4j:slf4j-api to v2.0.11 (#558)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-08 19:46:53 +00:00
0b9b8325ce fix(deps): update dependency joda-time:joda-time to v2.12.6 (#557)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-07 01:21:56 +00:00
6d89773448 fix(deps): update dependency org.slf4j:slf4j-api to v2.0.10 (#555)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-29 05:01:16 +00:00
b236530991 fix(deps): update dependency org.slf4j:slf4j-simple to v2.0.10 (#556)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-28 21:55:33 +00:00
8caee55f43 fix(deps): update dependency org.apache.logging.log4j:log4j-api-kotlin to v1.4.0 (#554)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-27 13:33:24 +00:00
13042ba385 fix(deps): update log4j2 monorepo to v2.22.1 (#553)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-27 09:33:10 +00:00
26bd7178c9 Create documentation.md 2023-12-24 08:40:39 -05:00
9bc39e9767 chore(deps): update actions/setup-java action to v4 (#544) 2023-12-24 08:32:17 -05:00
57555587e0 chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.9.22 (#549)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-21 22:00:24 +00:00
47a9f0a145 fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.9.22 (#550)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-21 18:53:01 +00:00
789b750994 chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.9.22 (#548)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-21 16:51:58 +00:00
65fb7fbd55 fix(deps): update ktor to v2.3.7 (#547)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-07 14:07:12 +00:00
89bd9dadd0 fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-datetime to v0.5.0 (#546)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-01 18:19:45 +00:00
6ca8261cd2 fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.6.2 (#545)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-30 15:11:22 +00:00
ae5ddc35e6 chore(deps): update dependency gradle to v8.5 (#543)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-29 16:44:20 +00:00
dde9e1c0a7 chore(deps): update plugin org.jetbrains.kotlinx.kover to v0.7.5 (#542)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-29 01:31:39 +00:00
8328351227 fix(deps): update dependency io.gitlab.arturbosch.detekt:detekt-formatting to v1.23.4 (#540)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-26 13:14:22 +00:00
36a09ef3ca chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.9.21 (#539)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-23 18:34:14 +00:00
261e91a750 chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.9.21 (#537)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-23 15:14:38 +00:00
701ab7670e fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.9.21 (#538)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-23 12:53:35 +00:00
62280435cd fix(deps): update dependency org.apache.logging.log4j:log4j-core to v2.22.0 (#536)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-20 15:44:22 +00:00
18ddb13625 fix(deps): update dependency org.apache.logging.log4j:log4j-api to v2.22.0 (#535)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-20 09:15:04 +00:00
b5b2e462ac fix(deps): update dependency com.google.protobuf:protobuf-java to v3.25.1 (#534)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-16 01:24:50 +00:00
1bb52347a0 fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.6.1 (#533)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 15:32:12 +00:00
80f8ce6e52 fix(deps): update ktor to v2.3.6 (#532)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-07 11:07:26 +00:00
1f504e8850 fix(deps): update kotestversion to v5.8.0 (#531)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-03 22:08:09 +00:00
18d545bbfe fix(deps): update dependency com.google.protobuf:protobuf-java to v3.25.0 (#530)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-02 00:18:38 +00:00
e03868c42e chore: enable k2 compiler (#529) 2023-11-01 09:57:08 -04:00
e888207773 fix(deps): update dependency io.gitlab.arturbosch.detekt:detekt-formatting to v1.23.3 (#528)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-31 17:47:34 +00:00
66943ceb5a fix(deps): update dependency io.gitlab.arturbosch.detekt:detekt-formatting to v1.23.2 (#525)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-31 03:38:30 +00:00
e9342b9354 fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.9.20 (#526)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-31 02:03:44 +00:00
480b1ccdff fix(deps): update ktor to v2.3.5 (#514)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Ryan Brink <5607577+unredundant@users.noreply.github.com>
2023-10-30 19:57:44 -04:00
95009090ba chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.9.20 (#523)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-30 23:48:24 +00:00
10ce370c9e chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.9.20 (#524)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-30 23:19:11 +00:00
1814fe4eb2 fix(deps): update dependency org.apache.logging.log4j:log4j-core to v2.21.1 (#520)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-24 16:37:12 +00:00
b0387313fd fix(deps): update dependency org.apache.logging.log4j:log4j-api to v2.21.1 (#519)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-24 13:04:20 +00:00
86c4800748 fix(deps): update dependency org.apache.logging.log4j:log4j-api to v2.21.0 (#517)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-17 00:19:14 +00:00
01052268f8 fix(deps): update dependency org.apache.logging.log4j:log4j-core to v2.21.0 (#518)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-16 23:13:19 +00:00
5c6f2c93e8 chore(deps): update plugin org.jetbrains.kotlinx.kover to v0.7.4 (#516)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-11 00:59:56 +00:00
ccd46b15e7 fix(deps): update dependency org.apache.logging.log4j:log4j-api-kotlin to v1.3.0 (#515)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-06 15:09:10 +00:00
eab1bb4ce7 fix(deps): update ktor to v2.3.5 (#513)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-05 09:29:17 +00:00
3fdfe875f4 chore(deps): update dependency gradle to v8.4 (#512)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-05 00:18:50 +00:00
1b3cf0dbeb fix(deps): update dependency com.google.protobuf:protobuf-java to v3.24.4 (#511)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-04 18:38:54 +00:00
2410c81797 fix(deps): update dependency io.gitlab.arturbosch.detekt:detekt-formatting to v1.23.1 (#471)
* fix(deps): update dependency io.gitlab.arturbosch.detekt:detekt-formatting to v1.23.1

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Ryan Brink <rbweb@pm.me>
2023-09-10 18:02:42 -04:00
833bf463e7 chore(deps): update plugin org.jetbrains.kotlinx.kover to v0.7.3 (#468) 2023-09-10 17:04:28 -04:00
b7e96019be fix(deps): update dependency com.google.protobuf:protobuf-java to v3.24.3 (#510)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-07 22:55:12 +00:00
aa5eb39a30 chore(deps): update actions/checkout action to v4 (#506)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-06 23:59:32 -04:00
d002ec7fd9 fix(deps): update kotestversion to v5.7.2 (#507)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-05 22:54:30 +00:00
650eb0f0d3 Merge branch 'main' of github.com:bkbnio/kompendium 2023-09-04 11:34:12 -04:00
1a4568a49b chore: docs 2023-09-04 11:33:04 -04:00
f2786fec08 major: v4 alpha (#505) 2023-09-04 04:22:46 +00:00
904cc6816d fix(deps): update kotestversion to v5.7.1 (#501)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-03 21:54:20 +00:00
a06821a910 fix(deps): update dependency org.slf4j:slf4j-api to v2.0.9 (#499)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-03 19:34:31 +00:00
a9dffcf8a5 fix(deps): update dependency org.slf4j:slf4j-simple to v2.0.9 (#500)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-03 17:08:11 +00:00
548b1ff4bc fix(deps): update kotestversion to v5.7.0 (#498)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-02 01:20:46 +00:00
6f85ee476a fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-datetime to v0.4.1 (#497)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-01 08:02:24 +00:00
326bbb4419 fix(deps): update ktor to v2.3.4 (#496)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-31 19:30:07 +00:00
438eb52dc8 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.24.2 (#495)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-26 01:50:52 +00:00
1fd59db4e1 fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.9.10 (#494)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-23 19:09:49 +00:00
238e372460 chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.9.10 (#492)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-23 17:12:05 +00:00
473e2c22af chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.9.10 (#493)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-23 13:30:22 +00:00
7fb7e688ac fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.6.0 (#491)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-22 19:10:33 +00:00
9f2c27aa0f fix(deps): update dependency com.google.protobuf:protobuf-java to v3.24.1 (#490)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-18 21:11:22 +00:00
dc762d1d3e chore(deps): update dependency gradle to v8.3 (#489)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-17 08:22:47 +00:00
b039803246 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.24.0 (#488)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-09 06:42:32 +00:00
6ec240d7cd fix(deps): update ktor to v2.3.3 (#487)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-01 17:30:05 +00:00
dd57347b90 chore(deps): update dependency gradle to v8.2.1 (#486)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-10 16:31:44 +00:00
43c8fd1338 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.23.4 (#485)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-07 05:14:32 +00:00
6c2725680e fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.9.0 (#484)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-06 22:00:21 +00:00
84dfe4e6fe chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.9.0 (#483)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-06 18:02:48 +00:00
a0c1abf011 chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.9.0 (#482)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-06 13:19:39 +00:00
25820d0920 chore(deps): update dependency gradle to v8.2 (#481)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-30 23:11:04 +00:00
7c18283ac8 fix(deps): update ktor to v2.3.2 (#480)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-28 19:10:33 +00:00
c5f3b7fa8b fix(deps): update dependency com.google.protobuf:protobuf-java to v3.23.3 (#478)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-15 00:06:06 +00:00
8b81010d72 fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.8.22 (#477)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-08 10:28:12 +00:00
c07ffa6a14 chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.8.22 (#476)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-08 08:04:51 +00:00
7793908ab6 chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.8.22 (#475)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-08 03:19:07 +00:00
bf6d08c2bd chore: prep for 3.14.4 release 2023-06-05 16:13:54 -04:00
68bae4918e fix: References for for protobuf objects (#466) 2023-06-05 16:12:31 -04:00
592c116c3b fix(deps): update dependency io.ktor:ktor-server-core to v2.3.1 (#474)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-01 10:46:44 +00:00
c7fe5c288f fix(deps): update ktor to v2.3.1 (#473)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-31 08:54:22 -04:00
e059633055 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.23.2 (#472)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-26 20:27:33 +00:00
884a50fc83 chore: prep for 3.14.3 release 2023-05-22 09:39:54 -04:00
588e52c9df fix: allow for request bodies to be marked as required=false (#470) 2023-05-22 09:39:04 -04:00
f49fcb2a22 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.23.1 (#469)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-17 23:39:18 +00:00
0a9475a7ab fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.5.1 (#463)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-11 21:54:50 +00:00
f8fbb7ad25 fix(deps): update kotestversion to v5.6.2 (#462)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-11 02:53:10 +00:00
f792fb5d1f fix(deps): update dependency com.google.protobuf:protobuf-java to v3.23.0 (#461)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-10 11:08:22 +00:00
845d1a971d fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.8.21 (#460)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-10 06:19:56 +00:00
9396b2ecfe chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.8.21 (#459)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-10 03:36:01 +00:00
d74b7b3f28 chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.8.21 (#458)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-10 03:31:13 +00:00
e783630845 chore(deps): update dependency gradle to v8.1.1 (#457)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-09 23:17:06 +00:00
d907ba004a chore: prep for 3.14.2 release 2023-05-08 11:50:45 -04:00
5c7ec4fdb4 fix: route with parameter declared via ktor function (#455) 2023-05-08 11:49:29 -04:00
097413067b chore: prep for 3.14.1 release 2023-04-28 10:59:27 -04:00
eb7360b8d2 fix: fixed generic property enrichment (#454) 2023-04-28 10:58:20 -04:00
3ec467c1d8 fix(deps): update ktor to v2.3.0 (#452)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-22 18:14:04 +00:00
152476c26e fix(deps): update dependency io.kotest:kotest-assertions-json-jvm to v5.6.1 (#451)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-18 21:15:51 +00:00
c4df4c7b2c fix(deps): update dependency io.kotest:kotest-runner-junit5-jvm to v5.6.0 (#450)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-17 05:49:54 +00:00
87fa0b5602 chore(deps): update dependency gradle to v8.1 (#449)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-15 17:00:27 +00:00
53c76d6037 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.22.3 (#448)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-13 08:56:13 +00:00
44324ca3a4 chore: rearrange docs (#447) 2023-04-10 19:00:26 +00:00
9364fb19e4 chore: prep for 3.14.0 release 2023-04-06 15:49:07 -04:00
ca1f632665 feat: Introduce Support for Response Headers (#446) 2023-04-06 19:47:48 +00:00
9bb3184735 docs: add showcase link to readme 2023-04-03 19:44:42 -04:00
9a139b5713 chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.8.20 (#440)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-03 10:54:36 -04:00
9861c8e258 chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.8.20 (#439)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-03 13:10:37 +00:00
02f8ed04f2 fix(deps): update dependency dev.forst:ktor-api-key to v2.2.4 (#442)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-03 12:54:06 +00:00
3e23939386 fix(deps): update dependency joda-time:joda-time to v2.12.5 (#441)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-31 00:21:18 +00:00
d0575944db fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.8.20 (#438)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-30 11:17:39 +00:00
ccc81c2813 fix(deps): update dependency joda-time:joda-time to v2.12.4 (#436)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-24 10:20:45 +00:00
e8da52fd75 fix(deps): update dependency joda-time:joda-time to v2.12.3 (#435)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-23 12:49:37 +00:00
34c14e26da fix(deps): update dependency org.slf4j:slf4j-simple to v2.0.7 (#434)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-18 01:17:47 +00:00
209b5e38a3 fix(deps): update dependency org.slf4j:slf4j-api to v2.0.7 (#433)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-17 23:50:21 +00:00
902faa9471 fix(deps): update dependency io.gitlab.arturbosch.detekt:detekt-formatting to v1.22.0 (#388) 2023-03-16 12:53:15 +00:00
c7ef70a844 fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.5.0 (#432)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-16 12:25:44 +00:00
f83c3d203d fix(deps): update ktor to v2.2.4 (#430)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-16 10:38:18 +00:00
bd05dbcfcb chore(deps): update plugin io.github.gradle-nexus.publish-plugin to v1.3.0 (#431)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-16 08:48:23 +00:00
cb5c0e71a3 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.22.2 (#429)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-16 08:45:44 +00:00
a209cafa74 chore(deps): update dependency gradle to v7.6.1 (#428)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-16 07:27:45 +00:00
3d27d30a31 feat: support no request body for post, put and patch (#427) 2023-03-15 12:39:35 +00:00
166 changed files with 5092 additions and 1982 deletions

10
.envrc Normal file
View File

@ -0,0 +1,10 @@
if ! has nix_direnv_version || ! nix_direnv_version 3.0.5; then
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.5/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs="
fi
watch_file flake.nix
watch_file flake.lock
if ! use flake . --impure
then
echo "Flake could not be used... something is broken :(" >&2
fi

17
.github/ISSUE_TEMPLATE/documentation.md vendored Normal file
View File

@ -0,0 +1,17 @@
---
name: Documentation
about: Suggest an improvement to the documentation for Kompendium
title: ''
labels: ''
assignees: ''
---
**Please describe the problem with the current documentation.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Link any docs references**
Link to existing docs if incorrect, or references from another project if you have an example.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -4,28 +4,28 @@ jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Set up JDK 17 - name: Set up JDK 21
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'adopt' distribution: 'adopt'
java-version: '17' java-version: '21'
- name: Lint - name: Lint
uses: burrunan/gradle-cache-action@v1 uses: burrunan/gradle-cache-action@v2
with: with:
gradle-version: wrapper gradle-version: wrapper
arguments: detekt arguments: detekt
unit: unit:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Set up JDK 17 - name: Set up JDK 21
uses: actions/setup-java@v3 uses: actions/setup-java@v4
with: with:
distribution: 'adopt' distribution: 'adopt'
java-version: '17' java-version: '21'
- name: Unit Tests - name: Unit Tests
uses: burrunan/gradle-cache-action@v1 uses: burrunan/gradle-cache-action@v2
with: with:
gradle-version: wrapper gradle-version: wrapper
arguments: test koverMergedReport arguments: test koverHtmlReport

View File

@ -1,25 +0,0 @@
name: Publish to GitHub Packages
on:
push:
branches: [ main ]
paths-ignore:
- docs/**
env:
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SONATYPE_SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SONATYPE_SIGNING_PASSWORD }}
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: '17'
- name: Publish to GitHub Packages
uses: burrunan/gradle-cache-action@v1
with:
gradle-version: wrapper
arguments: publishAllPublicationsToGithubPackagesRepository
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -4,25 +4,26 @@ on:
types: types:
- prereleased - prereleased
- released - released
env:
ORG_GRADLE_PROJECT_signingKey: ${{ secrets.SONATYPE_SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.SONATYPE_SIGNING_PASSWORD }}
jobs: jobs:
publish-to-nexus: publish-to-maven-central:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: actions/setup-java@v3 - uses: actions/setup-java@v4
with: with:
distribution: 'adopt' distribution: 'adopt'
java-version: '17' java-version: '21'
- name: Publish to Maven Central - name: Publish to Maven Central
uses: burrunan/gradle-cache-action@v1 uses: burrunan/gradle-cache-action@v2
with: with:
gradle-version: wrapper gradle-version: wrapper
arguments: publishToSonatype closeAndReleaseSonatypeStagingRepository arguments: publishAndReleaseToMavenCentral --no-configuration-cache --stacktrace
properties: | properties: |
release=true release=true
env: env:
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.SONATYPE_USER }} ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.SONATYPE_PASSWORD }} ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.MAVEN_SIGNING_KEY }}
# NOTE: FML https://stackoverflow.com/a/39573795
ORG_GRADLE_PROJECT_signingInMemoryKeyId: FF618132
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.MAVEN_SIGNING_PASSWORD }}

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.gradle .gradle
build build
.idea .idea
.direnv

File diff suppressed because it is too large Load Diff

View File

@ -3,3 +3,7 @@
[![version](https://img.shields.io/maven-central/v/io.bkbn/kompendium-core?style=flat-square)](https://search.maven.org/search?q=io.bkbn%20kompendium) [![version](https://img.shields.io/maven-central/v/io.bkbn/kompendium-core?style=flat-square)](https://search.maven.org/search?q=io.bkbn%20kompendium)
Documentation is stored in the `docs` folder and is hosted [here](https://bkbn.gitbook.io/kompendium) Documentation is stored in the `docs` folder and is hosted [here](https://bkbn.gitbook.io/kompendium)
## Showcase
If you would like to showcase docs that you build using Kompendium, add them to [the showcase discussion](https://github.com/bkbnio/kompendium/discussions/444)

View File

@ -1,21 +1,19 @@
import com.vanniktech.maven.publish.SonatypeHost
import io.bkbn.sourdough.gradle.library.jvm.LibraryJvmPlugin
import io.bkbn.sourdough.gradle.library.jvm.LibraryJvmExtension
plugins { plugins {
kotlin("jvm") version "1.8.10" apply false kotlin("jvm") version "2.1.20" apply false
kotlin("plugin.serialization") version "1.8.10" apply false kotlin("plugin.serialization") version "2.1.20" apply false
id("io.bkbn.sourdough.library.jvm") version "0.12.0" apply false id("io.bkbn.sourdough.library.jvm") version "0.13.1" apply false
id("io.bkbn.sourdough.application.jvm") version "0.12.0" apply false id("io.bkbn.sourdough.application.jvm") version "0.13.1" apply false
id("io.bkbn.sourdough.root") version "0.12.0" id("com.vanniktech.maven.publish") version "0.31.0" apply false
id("com.github.jakemarsden.git-hooks") version "0.0.2" id("io.bkbn.sourdough.root") version "0.13.1"
id("org.jetbrains.kotlinx.kover") version "0.6.1" id("org.jetbrains.kotlinx.kover") version "0.9.1"
id("io.github.gradle-nexus.publish-plugin") version "1.2.0"
} }
gitHooks { dependencies {
setHooks( subprojects.forEach { kover(it) }
mapOf(
"pre-commit" to "detekt",
"pre-push" to "test"
)
)
} }
allprojects { allprojects {
@ -31,15 +29,16 @@ allprojects {
} }
subprojects { subprojects {
plugins.withType(io.bkbn.sourdough.gradle.library.jvm.LibraryJvmPlugin::class) { plugins.withType(LibraryJvmPlugin::class) {
extensions.configure(io.bkbn.sourdough.gradle.library.jvm.LibraryJvmExtension::class) { extensions.configure(LibraryJvmExtension::class) {
githubOrg.set("bkbnio") githubOrg.set("bkbnio")
githubRepo.set("kompendium") githubRepo.set("kompendium")
licenseName.set("MIT License") licenseName.set("MIT License")
licenseUrl.set("https://mit-license.org") licenseUrl.set("https://mit-license.org")
developerId.set("unredundant") developerId.set("brizzbuzz")
developerName.set("Ryan Brink") developerName.set("Ryan Brink")
developerEmail.set("admin@bkbn.io") developerEmail.set("admin@bkbn.io")
sonatypeHost.set(SonatypeHost.CENTRAL_PORTAL)
} }
} }
} }

View File

@ -4,7 +4,7 @@ plugins {
id("io.bkbn.sourdough.library.jvm") id("io.bkbn.sourdough.library.jvm")
id("io.gitlab.arturbosch.detekt") id("io.gitlab.arturbosch.detekt")
id("com.adarshr.test-logger") id("com.adarshr.test-logger")
id("maven-publish") id("com.vanniktech.maven.publish")
id("java-library") id("java-library")
id("signing") id("signing")
id("java-test-fixtures") id("java-test-fixtures")
@ -20,6 +20,7 @@ sourdoughLibrary {
dependencies { dependencies {
// VERSIONS // VERSIONS
val kotestVersion: String by project val kotestVersion: String by project
val kotlinSerializeVersion: String by project
val ktorVersion: String by project val ktorVersion: String by project
val detektVersion: String by project val detektVersion: String by project
@ -43,13 +44,11 @@ dependencies {
testFixturesApi("io.kotest:kotest-assertions-core-jvm:$kotestVersion") testFixturesApi("io.kotest:kotest-assertions-core-jvm:$kotestVersion")
testFixturesApi("io.kotest:kotest-property-jvm:$kotestVersion") testFixturesApi("io.kotest:kotest-property-jvm:$kotestVersion")
testFixturesApi("io.kotest:kotest-assertions-json-jvm:$kotestVersion") testFixturesApi("io.kotest:kotest-assertions-json-jvm:$kotestVersion")
testFixturesApi("io.kotest:kotest-assertions-ktor-jvm:4.4.3") testFixturesApi("io.kotest.extensions:kotest-assertions-ktor:2.0.0")
testFixturesApi("io.ktor:ktor-server-core:$ktorVersion") testFixturesApi("io.ktor:ktor-server-core:$ktorVersion")
testFixturesApi("io.ktor:ktor-server-test-host:$ktorVersion") testFixturesApi("io.ktor:ktor-server-test-host:$ktorVersion")
testFixturesApi("io.ktor:ktor-serialization:$ktorVersion") testFixturesApi("io.ktor:ktor-serialization:$ktorVersion")
testFixturesApi("io.ktor:ktor-serialization-jackson:$ktorVersion")
testFixturesApi("io.ktor:ktor-serialization-gson:$ktorVersion")
testFixturesApi("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") testFixturesApi("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
testFixturesApi("io.ktor:ktor-server-content-negotiation:$ktorVersion") testFixturesApi("io.ktor:ktor-server-content-negotiation:$ktorVersion")
testFixturesApi("io.ktor:ktor-server-auth:$ktorVersion") testFixturesApi("io.ktor:ktor-server-auth:$ktorVersion")
@ -57,9 +56,9 @@ dependencies {
testFixturesApi("io.ktor:ktor-client:$ktorVersion") testFixturesApi("io.ktor:ktor-client:$ktorVersion")
testFixturesApi("io.ktor:ktor-client-cio:$ktorVersion") testFixturesApi("io.ktor:ktor-client-cio:$ktorVersion")
testFixturesApi("dev.forst:ktor-api-key:2.2.2") testFixturesApi("dev.forst:ktor-api-key:2.2.4")
testFixturesApi("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") testFixturesApi("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializeVersion")
} }
testing { testing {

View File

@ -10,6 +10,7 @@ class DeleteInfo private constructor(
override val summary: String, override val summary: String,
override val description: String, override val description: String,
override val externalDocumentation: ExternalDocumentation?, override val externalDocumentation: ExternalDocumentation?,
override val security: Map<String, List<String>>?,
override val operationId: String?, override val operationId: String?,
override val deprecated: Boolean, override val deprecated: Boolean,
override val parameters: List<Parameter> override val parameters: List<Parameter>
@ -33,7 +34,8 @@ class DeleteInfo private constructor(
externalDocumentation = externalDocumentation, externalDocumentation = externalDocumentation,
operationId = operationId, operationId = operationId,
deprecated = deprecated, deprecated = deprecated,
parameters = parameters parameters = parameters,
security = security
) )
} }
} }

View File

@ -12,7 +12,8 @@ class GetInfo private constructor(
override val externalDocumentation: ExternalDocumentation?, override val externalDocumentation: ExternalDocumentation?,
override val operationId: String?, override val operationId: String?,
override val deprecated: Boolean, override val deprecated: Boolean,
override val parameters: List<Parameter> override val parameters: List<Parameter>,
override val security: Map<String, List<String>>?
) : MethodInfo { ) : MethodInfo {
companion object { companion object {
@ -33,7 +34,8 @@ class GetInfo private constructor(
externalDocumentation = externalDocumentation, externalDocumentation = externalDocumentation,
operationId = operationId, operationId = operationId,
deprecated = deprecated, deprecated = deprecated,
parameters = parameters parameters = parameters,
security = security
) )
} }
} }

View File

@ -12,7 +12,8 @@ class HeadInfo private constructor(
override val externalDocumentation: ExternalDocumentation?, override val externalDocumentation: ExternalDocumentation?,
override val operationId: String?, override val operationId: String?,
override val deprecated: Boolean, override val deprecated: Boolean,
override val parameters: List<Parameter> override val parameters: List<Parameter>,
override val security: Map<String, List<String>>?,
) : MethodInfo { ) : MethodInfo {
companion object { companion object {
@ -33,7 +34,8 @@ class HeadInfo private constructor(
externalDocumentation = externalDocumentation, externalDocumentation = externalDocumentation,
operationId = operationId, operationId = operationId,
deprecated = deprecated, deprecated = deprecated,
parameters = parameters parameters = parameters,
security = security,
) )
} }
} }

View File

@ -9,6 +9,9 @@ sealed interface MethodInfo {
val tags: Set<String> val tags: Set<String>
val summary: String val summary: String
val description: String val description: String
val security: Map<String, List<String>>?
get() = null
val externalDocumentation: ExternalDocumentation? val externalDocumentation: ExternalDocumentation?
get() = null get() = null
val operationId: String? val operationId: String?
@ -28,6 +31,7 @@ sealed interface MethodInfo {
internal var tags: Set<String> = emptySet() internal var tags: Set<String> = emptySet()
internal var parameters: List<Parameter> = emptyList() internal var parameters: List<Parameter> = emptyList()
internal var errors: MutableList<ResponseInfo> = mutableListOf() internal var errors: MutableList<ResponseInfo> = mutableListOf()
internal var security: Map<String, List<String>>? = null
fun response(init: ResponseInfo.Builder.() -> Unit) = apply { fun response(init: ResponseInfo.Builder.() -> Unit) = apply {
val builder = ResponseInfo.Builder() val builder = ResponseInfo.Builder()
@ -59,6 +63,8 @@ sealed interface MethodInfo {
fun parameters(vararg parameters: Parameter) = apply { this.parameters = parameters.toList() } fun parameters(vararg parameters: Parameter) = apply { this.parameters = parameters.toList() }
fun security(security: Map<String, List<String>>) = apply { this.security = security }
abstract fun build(): T abstract fun build(): T
} }
} }

View File

@ -1,7 +1,7 @@
package io.bkbn.kompendium.core.metadata package io.bkbn.kompendium.core.metadata
sealed interface MethodInfoWithRequest : MethodInfo { sealed interface MethodInfoWithRequest : MethodInfo {
val request: RequestInfo val request: RequestInfo?
abstract class Builder<T : MethodInfoWithRequest> : MethodInfo.Builder<T>() { abstract class Builder<T : MethodInfoWithRequest> : MethodInfo.Builder<T>() {
internal var request: RequestInfo? = null internal var request: RequestInfo? = null

View File

@ -12,7 +12,8 @@ class OptionsInfo private constructor(
override val externalDocumentation: ExternalDocumentation?, override val externalDocumentation: ExternalDocumentation?,
override val operationId: String?, override val operationId: String?,
override val deprecated: Boolean, override val deprecated: Boolean,
override val parameters: List<Parameter> override val parameters: List<Parameter>,
override val security: Map<String, List<String>>?,
) : MethodInfo { ) : MethodInfo {
companion object { companion object {
@ -33,7 +34,8 @@ class OptionsInfo private constructor(
externalDocumentation = externalDocumentation, externalDocumentation = externalDocumentation,
operationId = operationId, operationId = operationId,
deprecated = deprecated, deprecated = deprecated,
parameters = parameters parameters = parameters,
security = security,
) )
} }
} }

View File

@ -4,7 +4,7 @@ import io.bkbn.kompendium.oas.common.ExternalDocumentation
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
class PatchInfo private constructor( class PatchInfo private constructor(
override val request: RequestInfo, override val request: RequestInfo?,
override val errors: MutableList<ResponseInfo>, override val errors: MutableList<ResponseInfo>,
override val response: ResponseInfo, override val response: ResponseInfo,
override val tags: Set<String>, override val tags: Set<String>,
@ -13,7 +13,8 @@ class PatchInfo private constructor(
override val externalDocumentation: ExternalDocumentation?, override val externalDocumentation: ExternalDocumentation?,
override val operationId: String?, override val operationId: String?,
override val deprecated: Boolean, override val deprecated: Boolean,
override val parameters: List<Parameter> override val parameters: List<Parameter>,
override val security: Map<String, List<String>>?,
) : MethodInfoWithRequest { ) : MethodInfoWithRequest {
companion object { companion object {
@ -26,7 +27,7 @@ class PatchInfo private constructor(
class Builder : MethodInfoWithRequest.Builder<PatchInfo>() { class Builder : MethodInfoWithRequest.Builder<PatchInfo>() {
override fun build() = PatchInfo( override fun build() = PatchInfo(
request = request ?: error("request info must be present"), request = request,
errors = errors, errors = errors,
response = response ?: error("response info must be present"), response = response ?: error("response info must be present"),
tags = tags, tags = tags,
@ -35,7 +36,8 @@ class PatchInfo private constructor(
externalDocumentation = externalDocumentation, externalDocumentation = externalDocumentation,
operationId = operationId, operationId = operationId,
deprecated = deprecated, deprecated = deprecated,
parameters = parameters parameters = parameters,
security = security,
) )
} }
} }

View File

@ -4,7 +4,7 @@ import io.bkbn.kompendium.oas.common.ExternalDocumentation
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
class PostInfo private constructor( class PostInfo private constructor(
override val request: RequestInfo, override val request: RequestInfo?,
override val errors: MutableList<ResponseInfo>, override val errors: MutableList<ResponseInfo>,
override val response: ResponseInfo, override val response: ResponseInfo,
override val tags: Set<String>, override val tags: Set<String>,
@ -13,7 +13,8 @@ class PostInfo private constructor(
override val externalDocumentation: ExternalDocumentation?, override val externalDocumentation: ExternalDocumentation?,
override val operationId: String?, override val operationId: String?,
override val deprecated: Boolean, override val deprecated: Boolean,
override val parameters: List<Parameter> override val parameters: List<Parameter>,
override val security: Map<String, List<String>>?,
) : MethodInfoWithRequest { ) : MethodInfoWithRequest {
companion object { companion object {
@ -26,7 +27,7 @@ class PostInfo private constructor(
class Builder : MethodInfoWithRequest.Builder<PostInfo>() { class Builder : MethodInfoWithRequest.Builder<PostInfo>() {
override fun build() = PostInfo( override fun build() = PostInfo(
request = request ?: error("request info must be present"), request = request,
errors = errors, errors = errors,
response = response ?: error("response info must be present"), response = response ?: error("response info must be present"),
tags = tags, tags = tags,
@ -35,7 +36,8 @@ class PostInfo private constructor(
externalDocumentation = externalDocumentation, externalDocumentation = externalDocumentation,
operationId = operationId, operationId = operationId,
deprecated = deprecated, deprecated = deprecated,
parameters = parameters parameters = parameters,
security = security,
) )
} }
} }

View File

@ -4,7 +4,7 @@ import io.bkbn.kompendium.oas.common.ExternalDocumentation
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
class PutInfo private constructor( class PutInfo private constructor(
override val request: RequestInfo, override val request: RequestInfo?,
override val errors: MutableList<ResponseInfo>, override val errors: MutableList<ResponseInfo>,
override val response: ResponseInfo, override val response: ResponseInfo,
override val tags: Set<String>, override val tags: Set<String>,
@ -13,7 +13,8 @@ class PutInfo private constructor(
override val externalDocumentation: ExternalDocumentation?, override val externalDocumentation: ExternalDocumentation?,
override val operationId: String?, override val operationId: String?,
override val deprecated: Boolean, override val deprecated: Boolean,
override val parameters: List<Parameter> override val parameters: List<Parameter>,
override val security: Map<String, List<String>>?,
) : MethodInfoWithRequest { ) : MethodInfoWithRequest {
companion object { companion object {
@ -26,7 +27,7 @@ class PutInfo private constructor(
class Builder : MethodInfoWithRequest.Builder<PutInfo>() { class Builder : MethodInfoWithRequest.Builder<PutInfo>() {
override fun build() = PutInfo( override fun build() = PutInfo(
request = request ?: error("request info must be present"), request = request,
errors = errors, errors = errors,
response = response ?: error("response info must be present"), response = response ?: error("response info must be present"),
tags = tags, tags = tags,
@ -35,7 +36,8 @@ class PutInfo private constructor(
externalDocumentation = externalDocumentation, externalDocumentation = externalDocumentation,
operationId = operationId, operationId = operationId,
deprecated = deprecated, deprecated = deprecated,
parameters = parameters parameters = parameters,
security = security,
) )
} }
} }

View File

@ -7,10 +7,11 @@ import kotlin.reflect.typeOf
class RequestInfo private constructor( class RequestInfo private constructor(
val requestType: KType, val requestType: KType,
val typeEnrichment: TypeEnrichment<*>?, val enrichment: TypeEnrichment<*>?,
val description: String, val description: String,
val examples: Map<String, MediaType.Example>?, val examples: Map<String, MediaType.Example>?,
val mediaTypes: Set<String> val mediaTypes: Set<String>,
val required: Boolean
) { ) {
companion object { companion object {
@ -27,6 +28,11 @@ class RequestInfo private constructor(
private var description: String? = null private var description: String? = null
private var examples: Map<String, MediaType.Example>? = null private var examples: Map<String, MediaType.Example>? = null
private var mediaTypes: Set<String>? = null private var mediaTypes: Set<String>? = null
private var required: Boolean? = null
fun required(r: Boolean) = apply {
this.required = r
}
fun requestType(t: KType) = apply { fun requestType(t: KType) = apply {
this.requestType = t this.requestType = t
@ -43,8 +49,8 @@ class RequestInfo private constructor(
fun description(s: String) = apply { this.description = s } fun description(s: String) = apply { this.description = s }
fun examples(vararg e: Pair<String, Any>) = apply { fun examples(vararg e: Pair<String, MediaType.Example>) = apply {
this.examples = e.toMap().mapValues { (_, v) -> MediaType.Example(v) } this.examples = e.toMap()
} }
fun mediaTypes(vararg m: String) = apply { fun mediaTypes(vararg m: String) = apply {
@ -54,9 +60,10 @@ class RequestInfo private constructor(
fun build() = RequestInfo( fun build() = RequestInfo(
requestType = requestType ?: error("Request type must be present"), requestType = requestType ?: error("Request type must be present"),
description = description ?: error("Description must be present"), description = description ?: error("Description must be present"),
typeEnrichment = typeEnrichment, enrichment = typeEnrichment,
examples = examples, examples = examples,
mediaTypes = mediaTypes ?: setOf("application/json") mediaTypes = mediaTypes ?: setOf("application/json"),
required = required ?: true
) )
} }
} }

View File

@ -1,6 +1,7 @@
package io.bkbn.kompendium.core.metadata package io.bkbn.kompendium.core.metadata
import io.bkbn.kompendium.enrichment.TypeEnrichment import io.bkbn.kompendium.enrichment.TypeEnrichment
import io.bkbn.kompendium.oas.payload.Header
import io.bkbn.kompendium.oas.payload.MediaType import io.bkbn.kompendium.oas.payload.MediaType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import kotlin.reflect.KType import kotlin.reflect.KType
@ -9,10 +10,11 @@ import kotlin.reflect.typeOf
class ResponseInfo private constructor( class ResponseInfo private constructor(
val responseCode: HttpStatusCode, val responseCode: HttpStatusCode,
val responseType: KType, val responseType: KType,
val typeEnrichment: TypeEnrichment<*>?, val enrichment: TypeEnrichment<*>?,
val description: String, val description: String,
val examples: Map<String, MediaType.Example>?, val examples: Map<String, MediaType.Example>?,
val mediaTypes: Set<String> val mediaTypes: Set<String>,
val responseHeaders: Map<String, Header>?
) { ) {
companion object { companion object {
@ -30,6 +32,11 @@ class ResponseInfo private constructor(
private var description: String? = null private var description: String? = null
private var examples: Map<String, MediaType.Example>? = null private var examples: Map<String, MediaType.Example>? = null
private var mediaTypes: Set<String>? = null private var mediaTypes: Set<String>? = null
private var responseHeaders: Map<String, Header>? = null
fun responseHeaders(headers: Map<String, Header>) = apply {
this.responseHeaders = headers
}
fun responseCode(code: HttpStatusCode) = apply { fun responseCode(code: HttpStatusCode) = apply {
this.responseCode = code this.responseCode = code
@ -50,8 +57,8 @@ class ResponseInfo private constructor(
fun description(s: String) = apply { this.description = s } fun description(s: String) = apply { this.description = s }
fun examples(vararg e: Pair<String, Any>) = apply { fun examples(vararg e: Pair<String, MediaType.Example>) = apply {
this.examples = e.toMap().mapValues { (_, v) -> MediaType.Example(v) } this.examples = e.toMap()
} }
fun mediaTypes(vararg m: String) = apply { fun mediaTypes(vararg m: String) = apply {
@ -62,9 +69,10 @@ class ResponseInfo private constructor(
responseCode = responseCode ?: error("You must provide a response code in order to build a Response!"), responseCode = responseCode ?: error("You must provide a response code in order to build a Response!"),
responseType = responseType ?: error("You must provide a response type in order to build a Response!"), responseType = responseType ?: error("You must provide a response type in order to build a Response!"),
description = description ?: error("You must provide a description in order to build a Response!"), description = description ?: error("You must provide a description in order to build a Response!"),
typeEnrichment = typeEnrichment, enrichment = typeEnrichment,
examples = examples, examples = examples,
mediaTypes = mediaTypes ?: setOf("application/json") mediaTypes = mediaTypes ?: setOf("application/json"),
responseHeaders = responseHeaders
) )
} }
} }

View File

@ -1,16 +1,14 @@
package io.bkbn.kompendium.core.plugin package io.bkbn.kompendium.core.plugin
import io.bkbn.kompendium.core.attribute.KompendiumAttributes import io.bkbn.kompendium.core.attribute.KompendiumAttributes
import io.bkbn.kompendium.json.schema.KotlinXSchemaConfigurator
import io.bkbn.kompendium.json.schema.SchemaConfigurator import io.bkbn.kompendium.json.schema.SchemaConfigurator
import io.bkbn.kompendium.json.schema.definition.JsonSchema import io.bkbn.kompendium.json.schema.definition.JsonSchema
import io.bkbn.kompendium.json.schema.util.Helpers.getSimpleSlug import io.bkbn.kompendium.json.schema.util.Helpers.getSimpleSlug
import io.bkbn.kompendium.oas.OpenApiSpec import io.bkbn.kompendium.oas.OpenApiSpec
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.call
import io.ktor.server.application.createApplicationPlugin import io.ktor.server.application.createApplicationPlugin
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.Routing import io.ktor.server.routing.Routing
import io.ktor.server.routing.application
import io.ktor.server.routing.get import io.ktor.server.routing.get
import io.ktor.server.routing.route import io.ktor.server.routing.route
import io.ktor.server.routing.routing import io.ktor.server.routing.routing
@ -19,25 +17,26 @@ import kotlin.reflect.KType
object NotarizedApplication { object NotarizedApplication {
class Config { class Config {
lateinit var spec: OpenApiSpec lateinit var spec: () -> OpenApiSpec
var openApiJson: Routing.() -> Unit = { var specRoute: (OpenApiSpec, Routing) -> Unit = { spec, routing ->
route("/openapi.json") { routing.route("/openapi.json") {
get { get {
call.respond(HttpStatusCode.OK, this@route.application.attributes[KompendiumAttributes.openApiSpec]) call.respond(spec)
} }
} }
} }
var customTypes: Map<KType, JsonSchema> = emptyMap() var customTypes: Map<KType, JsonSchema> = emptyMap()
var schemaConfigurator: SchemaConfigurator = SchemaConfigurator.Default() var schemaConfigurator: SchemaConfigurator = KotlinXSchemaConfigurator()
} }
operator fun invoke() = createApplicationPlugin( operator fun invoke() = createApplicationPlugin(
name = "NotarizedApplication", name = "NotarizedApplication",
createConfiguration = ::Config createConfiguration = ::Config
) { ) {
val spec = pluginConfig.spec val spec = pluginConfig.spec()
val routing = application.routing { } val routing = application.routing {}
pluginConfig.openApiJson(routing) this@createApplicationPlugin.pluginConfig.specRoute(spec, routing)
// pluginConfig.openApiJson(routing)
pluginConfig.customTypes.forEach { (type, schema) -> pluginConfig.customTypes.forEach { (type, schema) ->
spec.components.schemas[type.getSimpleSlug()] = schema spec.components.schemas[type.getSimpleSlug()] = schema
} }

View File

@ -78,7 +78,7 @@ object NotarizedRoute {
fun Route.calculateRoutePath() = toString() fun Route.calculateRoutePath() = toString()
.let { .let {
application.environment.rootPath.takeIf { root -> root.isNotEmpty() } application.rootPath.takeIf { root -> root.isNotEmpty() }
?.let { root -> ?.let { root ->
val sanitizedRoute = if (root.startsWith("/")) root else "/$root" val sanitizedRoute = if (root.startsWith("/")) root else "/$root"
it.replace(sanitizedRoute, "") it.replace(sanitizedRoute, "")
@ -86,6 +86,7 @@ object NotarizedRoute {
?: it ?: it
} }
.replace(Regex("/\\(.+\\)"), "") .replace(Regex("/\\(.+\\)"), "")
.replace(Regex("/\\[.+\\]"), "")
fun Route.collectAuthMethods() = toString() fun Route.collectAuthMethods() = toString()
.split("/") .split("/")

View File

@ -42,6 +42,7 @@ object Helpers {
} }
} }
@Suppress("CyclomaticComplexMethod")
fun MethodInfo.addToSpec( fun MethodInfo.addToSpec(
path: Path, path: Path,
spec: OpenApiSpec, spec: OpenApiSpec,
@ -50,35 +51,46 @@ object Helpers {
routePath: String, routePath: String,
authMethods: List<String> = emptyList() authMethods: List<String> = emptyList()
) { ) {
val type = this.response.responseType
val enrichment = this.response.enrichment
SchemaGenerator.fromTypeOrUnit( SchemaGenerator.fromTypeOrUnit(
type = this.response.responseType, type = type,
cache = spec.components.schemas, cache = spec.components.schemas,
schemaConfigurator = schemaConfigurator, schemaConfigurator = schemaConfigurator,
enrichment = this.response.typeEnrichment, enrichment = enrichment,
)?.let { schema -> )?.let { schema ->
spec.components.schemas[this.response.responseType.getSlug(this.response.typeEnrichment)] = schema val slug = type.getSlug(enrichment)
spec.components.schemas[slug] = schema
} }
errors.forEach { error -> errors.forEach { error ->
val errorEnrichment = error.enrichment
val errorType = error.responseType
SchemaGenerator.fromTypeOrUnit( SchemaGenerator.fromTypeOrUnit(
type = error.responseType, type = errorType,
cache = spec.components.schemas, cache = spec.components.schemas,
schemaConfigurator = schemaConfigurator, schemaConfigurator = schemaConfigurator,
enrichment = error.typeEnrichment, enrichment = errorEnrichment,
)?.let { schema -> )?.let { schema ->
spec.components.schemas[error.responseType.getSlug(error.typeEnrichment)] = schema val slug = errorType.getSlug(errorEnrichment)
spec.components.schemas[slug] = schema
} }
} }
when (this) { when (this) {
is MethodInfoWithRequest -> { is MethodInfoWithRequest -> {
SchemaGenerator.fromTypeOrUnit( this.request?.let { reqInfo ->
type = this.request.requestType, val reqEnrichment = reqInfo.enrichment
cache = spec.components.schemas, val reqType = reqInfo.requestType
schemaConfigurator = schemaConfigurator, SchemaGenerator.fromTypeOrUnit(
enrichment = this.request.typeEnrichment, type = reqType,
)?.let { schema -> cache = spec.components.schemas,
spec.components.schemas[this.request.requestType.getSlug(this.request.typeEnrichment)] = schema schemaConfigurator = schemaConfigurator,
enrichment = reqEnrichment,
)?.let { schema ->
val slug = reqType.getSlug(reqEnrichment)
spec.components.schemas[slug] = schema
}
} }
} }
@ -116,42 +128,62 @@ object Helpers {
operationId = this.operationId, operationId = this.operationId,
deprecated = this.deprecated, deprecated = this.deprecated,
parameters = this.parameters, parameters = this.parameters,
security = config.security security = this.createCombinedSecurityContext(config),
?.map { (k, v) -> k to v }
?.map { listOf(it).toMap() }
?.toMutableList(),
requestBody = when (this) { requestBody = when (this) {
is MethodInfoWithRequest -> Request( is MethodInfoWithRequest -> this.request?.let { reqInfo ->
description = this.request.description, Request(
content = this.request.requestType.toReferenceContent( description = reqInfo.description,
examples = this.request.examples, content = reqInfo.requestType.toReferenceContent(
mediaTypes = this.request.mediaTypes, examples = reqInfo.examples,
enrichment = this.request.typeEnrichment mediaTypes = reqInfo.mediaTypes,
), enrichment = reqInfo.enrichment
required = true ),
) required = reqInfo.required
)
}
else -> null else -> null
}, },
responses = mapOf( responses = mapOf(
this.response.responseCode.value to Response( this.response.responseCode.value to Response(
description = this.response.description, description = this.response.description,
headers = this.response.responseHeaders,
content = this.response.responseType.toReferenceContent( content = this.response.responseType.toReferenceContent(
examples = this.response.examples, examples = this.response.examples,
mediaTypes = this.response.mediaTypes, mediaTypes = this.response.mediaTypes,
enrichment = this.response.typeEnrichment enrichment = this.response.enrichment
) )
) )
).plus(this.errors.toResponseMap()) ).plus(this.errors.toResponseMap())
) )
private fun MethodInfo.createCombinedSecurityContext(config: SpecConfig): MutableList<Map<String, List<String>>>? {
val configSecurity = config.security
?.map { (k, v) -> k to v }
?.map { listOf(it).toMap() }
?.toMutableList()
val methodSecurity = this.security
?.map { (k, v) -> k to v }
?.map { listOf(it).toMap() }
?.toMutableList()
return when {
configSecurity == null && methodSecurity == null -> null
configSecurity == null -> methodSecurity
methodSecurity == null -> configSecurity
else -> configSecurity.plus(methodSecurity).toMutableList()
}
}
private fun List<ResponseInfo>.toResponseMap(): Map<Int, Response> = associate { error -> private fun List<ResponseInfo>.toResponseMap(): Map<Int, Response> = associate { error ->
error.responseCode.value to Response( error.responseCode.value to Response(
description = error.description, description = error.description,
headers = error.responseHeaders,
content = error.responseType.toReferenceContent( content = error.responseType.toReferenceContent(
examples = error.examples, examples = error.examples,
mediaTypes = error.mediaTypes, mediaTypes = error.mediaTypes,
enrichment = error.typeEnrichment enrichment = error.enrichment
) )
) )
} }

View File

@ -0,0 +1,172 @@
package io.bkbn.kompendium.core
import dev.forst.ktor.apikey.apiKey
import io.bkbn.kompendium.core.fixtures.TestHelpers
import io.bkbn.kompendium.core.util.customAuthConfig
import io.bkbn.kompendium.core.util.customScopesOnSiblingPathOperations
import io.bkbn.kompendium.core.util.defaultAuthConfig
import io.bkbn.kompendium.core.util.multipleAuthStrategies
import io.bkbn.kompendium.oas.component.Components
import io.bkbn.kompendium.oas.security.ApiKeyAuth
import io.bkbn.kompendium.oas.security.BasicAuth
import io.bkbn.kompendium.oas.security.BearerAuth
import io.bkbn.kompendium.oas.security.OAuth
import io.kotest.core.spec.style.DescribeSpec
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.http.HttpMethod
import io.ktor.server.application.install
import io.ktor.server.auth.Authentication
import io.ktor.server.auth.OAuthServerSettings
import io.ktor.server.auth.Principal
import io.ktor.server.auth.UserIdPrincipal
import io.ktor.server.auth.basic
import io.ktor.server.auth.jwt.jwt
import io.ktor.server.auth.oauth
class KompendiumAuthenticationTest : DescribeSpec({
describe("Authentication") {
it("Can add a default auth config by default") {
TestHelpers.openApiTestAllSerializers(
snapshotName = "T0045__default_auth_config.json",
applicationSetup = {
install(Authentication) {
basic("basic") {
realm = "Ktor Server"
validate { UserIdPrincipal("Placeholder") }
}
}
},
specOverrides = {
this.copy(
components = Components(
securitySchemes = mutableMapOf(
"basic" to BasicAuth()
)
)
)
}
) { defaultAuthConfig() }
}
it("Can provide custom auth config with proper scopes") {
TestHelpers.openApiTestAllSerializers(
snapshotName = "T0046__custom_auth_config.json",
applicationSetup = {
install(Authentication) {
oauth("auth-oauth-google") {
urlProvider = { "http://localhost:8080/callback" }
providerLookup = {
OAuthServerSettings.OAuth2ServerSettings(
name = "google",
authorizeUrl = "https://accounts.google.com/o/oauth2/auth",
accessTokenUrl = "https://accounts.google.com/o/oauth2/token",
requestMethod = HttpMethod.Post,
clientId = "DUMMY_VAL",
clientSecret = "DUMMY_VAL",
defaultScopes = listOf("https://www.googleapis.com/auth/userinfo.profile"),
extraTokenParameters = listOf("access_type" to "offline")
)
}
client = HttpClient(CIO)
}
}
},
specOverrides = {
this.copy(
components = Components(
securitySchemes = mutableMapOf(
"auth-oauth-google" to OAuth(
flows = OAuth.Flows(
implicit = OAuth.Flows.Implicit(
authorizationUrl = "https://accounts.google.com/o/oauth2/auth",
scopes = mapOf(
"write:pets" to "modify pets in your account",
"read:pets" to "read your pets"
)
)
)
)
)
)
)
}
) { customAuthConfig() }
}
it("Can provide multiple authentication strategies") {
data class TestAppPrincipal(val key: String) : Principal
TestHelpers.openApiTestAllSerializers(
snapshotName = "T0047__multiple_auth_strategies.json",
applicationSetup = {
install(Authentication) {
apiKey("api-key") {
headerName = "X-API-KEY"
validate { key ->
// api key library (dev.forst.ktor.apikey) is using the deprecated `Principal` class
key
.takeIf { it == "api-key" }
?.let { TestAppPrincipal(it) }
}
}
jwt("jwt") {
realm = "Server"
}
}
},
specOverrides = {
this.copy(
components = Components(
securitySchemes = mutableMapOf(
"jwt" to BearerAuth("JWT"),
"api-key" to ApiKeyAuth(ApiKeyAuth.ApiKeyLocation.HEADER, "X-API-KEY")
)
)
)
}
) { multipleAuthStrategies() }
}
it("Can provide different scopes on path operations in the same route") {
TestHelpers.openApiTestAllSerializers(
snapshotName = "T0074__auth_on_specific_path_operation.json",
applicationSetup = {
install(Authentication) {
oauth("auth-oauth-google") {
urlProvider = { "http://localhost:8080/callback" }
providerLookup = {
OAuthServerSettings.OAuth2ServerSettings(
name = "google",
authorizeUrl = "https://accounts.google.com/o/oauth2/auth",
accessTokenUrl = "https://accounts.google.com/o/oauth2/token",
requestMethod = HttpMethod.Post,
clientId = "DUMMY_VAL",
clientSecret = "DUMMY_VAL",
defaultScopes = listOf("https://www.googleapis.com/auth/userinfo.profile"),
extraTokenParameters = listOf("access_type" to "offline")
)
}
client = HttpClient(CIO)
}
}
},
specOverrides = {
this.copy(
components = Components(
securitySchemes = mutableMapOf(
"auth-oauth-google" to OAuth(
flows = OAuth.Flows(
implicit = OAuth.Flows.Implicit(
authorizationUrl = "https://accounts.google.com/o/oauth2/auth",
scopes = mapOf(
"write:pets" to "modify pets in your account",
"read:pets" to "read your pets"
)
)
)
)
)
)
)
}
) { customScopesOnSiblingPathOperations() }
}
}
})

View File

@ -0,0 +1,35 @@
package io.bkbn.kompendium.core
import io.bkbn.kompendium.core.fixtures.TestHelpers
import io.bkbn.kompendium.core.util.arrayConstraints
import io.bkbn.kompendium.core.util.doubleConstraints
import io.bkbn.kompendium.core.util.intConstraints
import io.bkbn.kompendium.core.util.stringConstraints
import io.bkbn.kompendium.core.util.stringContentEncodingConstraints
import io.bkbn.kompendium.core.util.stringPatternConstraints
import io.kotest.core.spec.style.DescribeSpec
class KompendiumConstraintsTest : DescribeSpec({
describe("Constraints") {
it("Can apply constraints to an int field") {
TestHelpers.openApiTestAllSerializers("T0059__int_constraints.json") { intConstraints() }
}
it("Can apply constraints to a double field") {
TestHelpers.openApiTestAllSerializers("T0060__double_constraints.json") { doubleConstraints() }
}
it("Can apply a min and max length to a string field") {
TestHelpers.openApiTestAllSerializers("T0061__string_min_max_constraints.json") { stringConstraints() }
}
it("Can apply a pattern to a string field") {
TestHelpers.openApiTestAllSerializers("T0062__string_pattern_constraints.json") { stringPatternConstraints() }
}
it("Can apply a content encoding and media type to a string field") {
TestHelpers.openApiTestAllSerializers("T0063__string_content_encoding_constraints.json") {
stringContentEncodingConstraints()
}
}
it("Can apply constraints to an array field") {
TestHelpers.openApiTestAllSerializers("T0064__array_constraints.json") { arrayConstraints() }
}
}
})

View File

@ -0,0 +1,13 @@
package io.bkbn.kompendium.core
import io.bkbn.kompendium.core.fixtures.TestHelpers
import io.bkbn.kompendium.core.util.defaultParameter
import io.kotest.core.spec.style.DescribeSpec
class KompendiumDefaultsTest : DescribeSpec({
describe("Defaults") {
it("Can generate a default parameter value") {
TestHelpers.openApiTestAllSerializers("T0022__query_with_default_parameter.json") { defaultParameter() }
}
}
})

View File

@ -0,0 +1,39 @@
package io.bkbn.kompendium.core
import io.bkbn.kompendium.core.fixtures.TestHelpers.openApiTestAllSerializers
import io.bkbn.kompendium.core.util.enrichedComplexGenericType
import io.bkbn.kompendium.core.util.enrichedGenericResponse
import io.bkbn.kompendium.core.util.enrichedMap
import io.bkbn.kompendium.core.util.enrichedNestedCollection
import io.bkbn.kompendium.core.util.enrichedSimpleRequest
import io.bkbn.kompendium.core.util.enrichedSimpleResponse
import io.bkbn.kompendium.core.util.enrichedTopLevelCollection
import io.kotest.core.spec.style.DescribeSpec
class KompendiumEnrichmentTest : DescribeSpec({
describe("Enrichment") {
it("Can enrich a simple request") {
openApiTestAllSerializers("T0055__enriched_simple_request.json") { enrichedSimpleRequest() }
}
it("Can enrich a simple response") {
openApiTestAllSerializers("T0058__enriched_simple_response.json") { enrichedSimpleResponse() }
}
it("Can enrich a nested collection") {
openApiTestAllSerializers("T0056__enriched_nested_collection.json") { enrichedNestedCollection() }
}
it("Can enrich a complex generic type") {
openApiTestAllSerializers(
"T0057__enriched_complex_generic_type.json"
) { enrichedComplexGenericType() }
}
it("Can enrich a generic object") {
openApiTestAllSerializers("T0067__enriched_generic_object.json") { enrichedGenericResponse() }
}
it("Can enrich a top level list type") {
openApiTestAllSerializers("T0077__enriched_top_level_list.json") { enrichedTopLevelCollection() }
}
it("can enrich a map type") {
openApiTestAllSerializers("T0078__enriched_top_level_map.json") { enrichedMap() }
}
}
})

View File

@ -0,0 +1,45 @@
package io.bkbn.kompendium.core
import io.bkbn.kompendium.core.fixtures.TestHelpers
import io.bkbn.kompendium.core.util.dateTimeString
import io.bkbn.kompendium.core.util.samePathSameMethod
import io.bkbn.kompendium.json.schema.exception.UnknownSchemaException
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.DescribeSpec
import io.kotest.matchers.should
import io.kotest.matchers.string.startWith
import io.ktor.server.application.install
import io.ktor.server.auth.Authentication
import io.ktor.server.auth.UserIdPrincipal
import io.ktor.server.auth.basic
class KompendiumErrorHandlingTest : DescribeSpec({
describe("Error Handling") {
it("Throws a clear exception when an unidentified type is encountered") {
val exception = shouldThrow<UnknownSchemaException> {
TestHelpers.openApiTestAllSerializers(
""
) { dateTimeString() }
}
exception.message should startWith("An unknown type was encountered: class java.time.Instant")
}
it("Throws an exception when same method for same path has been previously registered") {
val exception = shouldThrow<IllegalArgumentException> {
TestHelpers.openApiTestAllSerializers(
snapshotName = "",
applicationSetup = {
install(Authentication) {
basic("basic") {
realm = "Ktor Server"
validate { UserIdPrincipal("Placeholder") }
}
}
},
) {
samePathSameMethod()
}
}
exception.message should startWith("A route has already been registered for path: /test/{a} and method: GET")
}
}
})

View File

@ -0,0 +1,27 @@
package io.bkbn.kompendium.core
import io.bkbn.kompendium.core.fixtures.TestHelpers
import io.bkbn.kompendium.core.util.exampleParams
import io.bkbn.kompendium.core.util.exampleSummaryAndDescription
import io.bkbn.kompendium.core.util.optionalReqExample
import io.bkbn.kompendium.core.util.reqRespExamples
import io.kotest.core.spec.style.DescribeSpec
class KompendiumExamplesTest : DescribeSpec({
describe("Examples") {
it("Can generate example response and request bodies") {
TestHelpers.openApiTestAllSerializers("T0020__example_req_and_resp.json") { reqRespExamples() }
}
it("Can describe example parameters") {
TestHelpers.openApiTestAllSerializers("T0021__example_parameters.json") { exampleParams() }
}
it("Can generate example optional request body") {
TestHelpers.openApiTestAllSerializers("T0069__example_optional_req.json") { optionalReqExample() }
}
it("Can generate example summary and description") {
TestHelpers.openApiTestAllSerializers(
"T0075__example_summary_and_description.json"
) { exampleSummaryAndDescription() }
}
}
})

View File

@ -0,0 +1,27 @@
package io.bkbn.kompendium.core
import io.bkbn.kompendium.core.fixtures.TestHelpers
import io.bkbn.kompendium.core.util.genericException
import io.bkbn.kompendium.core.util.multipleExceptions
import io.bkbn.kompendium.core.util.polymorphicException
import io.bkbn.kompendium.core.util.singleException
import io.kotest.core.spec.style.DescribeSpec
class KompendiumExceptionsTest : DescribeSpec({
describe("Exceptions") {
it("Can add an exception status code to a response") {
TestHelpers.openApiTestAllSerializers("T0016__notarized_get_with_exception_response.json") { singleException() }
}
it("Can support multiple response codes") {
TestHelpers.openApiTestAllSerializers("T0017__notarized_get_with_multiple_exception_responses.json") {
multipleExceptions()
}
}
it("Can add a polymorphic exception response") {
TestHelpers.openApiTestAllSerializers("T0018__polymorphic_error_status_codes.json") { polymorphicException() }
}
it("Can add a generic exception response") {
TestHelpers.openApiTestAllSerializers("T0019__generic_exception.json") { genericException() }
}
}
})

View File

@ -0,0 +1,7 @@
package io.bkbn.kompendium.core
import io.kotest.core.spec.style.DescribeSpec
class KompendiumFreeFormTest : DescribeSpec({
// todo Assess strategies here
})

View File

@ -0,0 +1,67 @@
package io.bkbn.kompendium.core
import io.bkbn.kompendium.core.fixtures.TestHelpers
import io.bkbn.kompendium.core.util.genericPolymorphicResponse
import io.bkbn.kompendium.core.util.genericPolymorphicResponseMultipleImpls
import io.bkbn.kompendium.core.util.gnarlyGenericResponse
import io.bkbn.kompendium.core.util.nestedGenericCollection
import io.bkbn.kompendium.core.util.nestedGenericMultipleParamsCollection
import io.bkbn.kompendium.core.util.nestedGenericResponse
import io.bkbn.kompendium.core.util.overrideSealedTypeIdentifier
import io.bkbn.kompendium.core.util.polymorphicCollectionResponse
import io.bkbn.kompendium.core.util.polymorphicMapResponse
import io.bkbn.kompendium.core.util.polymorphicResponse
import io.bkbn.kompendium.core.util.simpleGenericResponse
import io.bkbn.kompendium.core.util.subtypeNotCompleteSetOfParentProperties
import io.kotest.core.spec.style.DescribeSpec
class KompendiumPolymorphismAndGenericsTest : DescribeSpec({
describe("Polymorphism and Generics") {
it("can generate a polymorphic response type") {
TestHelpers.openApiTestAllSerializers("T0027__polymorphic_response.json") { polymorphicResponse() }
}
it("Can generate a collection with polymorphic response type") {
TestHelpers.openApiTestAllSerializers("T0028__polymorphic_list_response.json") { polymorphicCollectionResponse() }
}
it("Can generate a map with a polymorphic response type") {
TestHelpers.openApiTestAllSerializers("T0029__polymorphic_map_response.json") { polymorphicMapResponse() }
}
it("Can generate a response type with a generic type") {
TestHelpers.openApiTestAllSerializers("T0030__simple_generic_response.json") { simpleGenericResponse() }
}
it("Can generate a response type with a nested generic type") {
TestHelpers.openApiTestAllSerializers("T0031__nested_generic_response.json") { nestedGenericResponse() }
}
it("Can generate a polymorphic response type with generics") {
TestHelpers.openApiTestAllSerializers(
"T0032__polymorphic_response_with_generics.json"
) { genericPolymorphicResponse() }
}
it("Can handle an absolutely psycho inheritance test") {
TestHelpers.openApiTestAllSerializers("T0033__crazy_polymorphic_example.json") {
genericPolymorphicResponseMultipleImpls()
}
}
it("Can support nested generic collections") {
TestHelpers.openApiTestAllSerializers("T0039__nested_generic_collection.json") { nestedGenericCollection() }
}
it("Can support nested generics with multiple type parameters") {
TestHelpers.openApiTestAllSerializers("T0040__nested_generic_multiple_type_params.json") {
nestedGenericMultipleParamsCollection()
}
}
it("Can handle a really gnarly generic example") {
TestHelpers.openApiTestAllSerializers("T0043__gnarly_generic_example.json") { gnarlyGenericResponse() }
}
it("Can override the type name for a sealed interface implementation") {
TestHelpers.openApiTestAllSerializers("T0070__sealed_interface_type_name_override.json") {
overrideSealedTypeIdentifier()
}
}
it("Can serialize an object where the subtype is not a complete set of parent properties") {
TestHelpers.openApiTestAllSerializers("T0071__subtype_not_complete_set_of_parent_properties.json") {
subtypeNotCompleteSetOfParentProperties()
}
}
}
})

View File

@ -0,0 +1,25 @@
package io.bkbn.kompendium.core
import io.bkbn.kompendium.core.fixtures.TestHelpers
import io.bkbn.kompendium.core.util.defaultField
import io.bkbn.kompendium.core.util.nonRequiredParam
import io.bkbn.kompendium.core.util.nullableField
import io.bkbn.kompendium.core.util.requiredParams
import io.kotest.core.spec.style.DescribeSpec
class KompendiumRequiredFieldsTest : DescribeSpec({
describe("Required Fields") {
it("Marks a parameter as required if there is no default and it is not marked nullable") {
TestHelpers.openApiTestAllSerializers("T0023__required_param.json") { requiredParams() }
}
it("Can mark a parameter as not required") {
TestHelpers.openApiTestAllSerializers("T0024__non_required_param.json") { nonRequiredParam() }
}
it("Does not mark a field as required if a default value is provided") {
TestHelpers.openApiTestAllSerializers("T0025__default_field.json") { defaultField() }
}
it("Does not mark a nullable field as required") {
TestHelpers.openApiTestAllSerializers("T0026__nullable_field.json") { nullableField() }
}
}
})

View File

@ -0,0 +1,29 @@
package io.bkbn.kompendium.core
import io.bkbn.kompendium.core.fixtures.TestHelpers
import io.bkbn.kompendium.core.util.nestedUnderRoot
import io.bkbn.kompendium.core.util.paramWrapper
import io.bkbn.kompendium.core.util.rootRoute
import io.bkbn.kompendium.core.util.simplePathParsing
import io.bkbn.kompendium.core.util.trailingSlash
import io.kotest.core.spec.style.DescribeSpec
class KompendiumRouteParsingTest : DescribeSpec({
describe("Route Parsing") {
it("Can parse a simple path and store it under the expected route") {
TestHelpers.openApiTestAllSerializers("T0012__path_parser.json") { simplePathParsing() }
}
it("Can notarize the root route") {
TestHelpers.openApiTestAllSerializers("T0013__root_route.json") { rootRoute() }
}
it("Can notarize a route under the root module without appending trailing slash") {
TestHelpers.openApiTestAllSerializers("T0014__nested_under_root.json") { nestedUnderRoot() }
}
it("Can notarize a route with a trailing slash") {
TestHelpers.openApiTestAllSerializers("T0015__trailing_slash.json") { trailingSlash() }
}
it("Can notarize a route with a parameter") {
TestHelpers.openApiTestAllSerializers("T0068__param_wrapper.json") { paramWrapper() }
}
}
})

View File

@ -1,35 +1,13 @@
package io.bkbn.kompendium.core package io.bkbn.kompendium.core
import dev.forst.ktor.apikey.apiKey
import io.bkbn.kompendium.core.fixtures.TestHelpers.openApiTestAllSerializers import io.bkbn.kompendium.core.fixtures.TestHelpers.openApiTestAllSerializers
import io.bkbn.kompendium.core.util.arrayConstraints
import io.bkbn.kompendium.core.util.complexRequest import io.bkbn.kompendium.core.util.complexRequest
import io.bkbn.kompendium.core.util.customAuthConfig
import io.bkbn.kompendium.core.util.customFieldNameResponse import io.bkbn.kompendium.core.util.customFieldNameResponse
import io.bkbn.kompendium.core.util.dateTimeString
import io.bkbn.kompendium.core.util.defaultAuthConfig
import io.bkbn.kompendium.core.util.defaultField import io.bkbn.kompendium.core.util.defaultField
import io.bkbn.kompendium.core.util.defaultParameter import io.bkbn.kompendium.core.util.fieldOutsideConstructor
import io.bkbn.kompendium.core.util.doubleConstraints
import io.bkbn.kompendium.core.util.enrichedComplexGenericType
import io.bkbn.kompendium.core.util.enrichedNestedCollection
import io.bkbn.kompendium.core.util.enrichedSimpleRequest
import io.bkbn.kompendium.core.util.enrichedSimpleResponse
import io.bkbn.kompendium.core.util.exampleParams
import io.bkbn.kompendium.core.util.genericException
import io.bkbn.kompendium.core.util.genericPolymorphicResponse
import io.bkbn.kompendium.core.util.genericPolymorphicResponseMultipleImpls
import io.bkbn.kompendium.core.util.gnarlyGenericResponse
import io.bkbn.kompendium.core.util.headerParameter import io.bkbn.kompendium.core.util.headerParameter
import io.bkbn.kompendium.core.util.ignoredFieldsResponse import io.bkbn.kompendium.core.util.ignoredFieldsResponse
import io.bkbn.kompendium.core.util.intConstraints
import io.bkbn.kompendium.core.util.multipleAuthStrategies
import io.bkbn.kompendium.core.util.multipleExceptions
import io.bkbn.kompendium.core.util.nestedGenericCollection
import io.bkbn.kompendium.core.util.nestedGenericMultipleParamsCollection
import io.bkbn.kompendium.core.util.nestedGenericResponse
import io.bkbn.kompendium.core.util.nestedTypeName import io.bkbn.kompendium.core.util.nestedTypeName
import io.bkbn.kompendium.core.util.nestedUnderRoot
import io.bkbn.kompendium.core.util.nonRequiredParam import io.bkbn.kompendium.core.util.nonRequiredParam
import io.bkbn.kompendium.core.util.nonRequiredParams import io.bkbn.kompendium.core.util.nonRequiredParams
import io.bkbn.kompendium.core.util.notarizedDelete import io.bkbn.kompendium.core.util.notarizedDelete
@ -44,52 +22,32 @@ import io.bkbn.kompendium.core.util.nullableField
import io.bkbn.kompendium.core.util.nullableNestedObject import io.bkbn.kompendium.core.util.nullableNestedObject
import io.bkbn.kompendium.core.util.nullableReference import io.bkbn.kompendium.core.util.nullableReference
import io.bkbn.kompendium.core.util.overrideMediaTypes import io.bkbn.kompendium.core.util.overrideMediaTypes
import io.bkbn.kompendium.core.util.polymorphicCollectionResponse import io.bkbn.kompendium.core.util.postNoReqBody
import io.bkbn.kompendium.core.util.polymorphicException
import io.bkbn.kompendium.core.util.polymorphicMapResponse
import io.bkbn.kompendium.core.util.polymorphicResponse
import io.bkbn.kompendium.core.util.primitives import io.bkbn.kompendium.core.util.primitives
import io.bkbn.kompendium.core.util.reqRespExamples
import io.bkbn.kompendium.core.util.requiredParams import io.bkbn.kompendium.core.util.requiredParams
import io.bkbn.kompendium.core.util.responseHeaders
import io.bkbn.kompendium.core.util.returnsEnumList
import io.bkbn.kompendium.core.util.returnsList import io.bkbn.kompendium.core.util.returnsList
import io.bkbn.kompendium.core.util.rootRoute
import io.bkbn.kompendium.core.util.samePathDifferentMethodsAndAuth import io.bkbn.kompendium.core.util.samePathDifferentMethodsAndAuth
import io.bkbn.kompendium.core.util.samePathSameMethod
import io.bkbn.kompendium.core.util.simpleGenericResponse
import io.bkbn.kompendium.core.util.simplePathParsing
import io.bkbn.kompendium.core.util.simpleRecursive import io.bkbn.kompendium.core.util.simpleRecursive
import io.bkbn.kompendium.core.util.singleException
import io.bkbn.kompendium.core.util.stringConstraints
import io.bkbn.kompendium.core.util.stringContentEncodingConstraints
import io.bkbn.kompendium.core.util.stringPatternConstraints
import io.bkbn.kompendium.core.util.topLevelNullable import io.bkbn.kompendium.core.util.topLevelNullable
import io.bkbn.kompendium.core.util.trailingSlash
import io.bkbn.kompendium.core.util.unbackedFieldsResponse import io.bkbn.kompendium.core.util.unbackedFieldsResponse
import io.bkbn.kompendium.core.util.withOperationId import io.bkbn.kompendium.core.util.withOperationId
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
import io.bkbn.kompendium.json.schema.exception.UnknownSchemaException
import io.bkbn.kompendium.oas.component.Components import io.bkbn.kompendium.oas.component.Components
import io.bkbn.kompendium.oas.security.ApiKeyAuth
import io.bkbn.kompendium.oas.security.BasicAuth import io.bkbn.kompendium.oas.security.BasicAuth
import io.bkbn.kompendium.oas.security.BearerAuth import io.bkbn.kompendium.oas.serialization.KompendiumSerializersModule
import io.bkbn.kompendium.oas.security.OAuth
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.DescribeSpec import io.kotest.core.spec.style.DescribeSpec
import io.kotest.matchers.should import io.ktor.serialization.kotlinx.json.json
import io.kotest.matchers.string.startWith
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.http.HttpMethod
import io.ktor.server.application.install import io.ktor.server.application.install
import io.ktor.server.auth.Authentication import io.ktor.server.auth.Authentication
import io.ktor.server.auth.OAuthServerSettings
import io.ktor.server.auth.UserIdPrincipal import io.ktor.server.auth.UserIdPrincipal
import io.ktor.server.auth.basic import io.ktor.server.auth.basic
import io.ktor.server.auth.jwt.jwt import io.ktor.server.response.respondText
import io.ktor.server.auth.oauth import io.ktor.server.routing.get
import io.ktor.server.routing.route
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.net.URI import java.net.URI
import java.time.Instant
import kotlin.reflect.typeOf
class KompendiumTest : DescribeSpec({ class KompendiumTest : DescribeSpec({
describe("Notarized Open API Metadata Tests") { describe("Notarized Open API Metadata Tests") {
@ -129,46 +87,11 @@ class KompendiumTest : DescribeSpec({
it("Can override media types") { it("Can override media types") {
openApiTestAllSerializers("T0052__override_media_types.json") { overrideMediaTypes() } openApiTestAllSerializers("T0052__override_media_types.json") { overrideMediaTypes() }
} }
} it("Can support a post request with no request body") {
describe("Route Parsing") { openApiTestAllSerializers("T0065__post_no_req_body.json") { postNoReqBody() }
it("Can parse a simple path and store it under the expected route") {
openApiTestAllSerializers("T0012__path_parser.json") { simplePathParsing() }
} }
it("Can notarize the root route") { it("Can notarize a route with response headers") {
openApiTestAllSerializers("T0013__root_route.json") { rootRoute() } openApiTestAllSerializers("T0066__notarized_get_with_response_headers.json") { responseHeaders() }
}
it("Can notarize a route under the root module without appending trailing slash") {
openApiTestAllSerializers("T0014__nested_under_root.json") { nestedUnderRoot() }
}
it("Can notarize a route with a trailing slash") {
openApiTestAllSerializers("T0015__trailing_slash.json") { trailingSlash() }
}
}
describe("Exceptions") {
it("Can add an exception status code to a response") {
openApiTestAllSerializers("T0016__notarized_get_with_exception_response.json") { singleException() }
}
it("Can support multiple response codes") {
openApiTestAllSerializers("T0017__notarized_get_with_multiple_exception_responses.json") { multipleExceptions() }
}
it("Can add a polymorphic exception response") {
openApiTestAllSerializers("T0018__polymorphic_error_status_codes.json") { polymorphicException() }
}
it("Can add a generic exception response") {
openApiTestAllSerializers("T0019__generic_exception.json") { genericException() }
}
}
describe("Examples") {
it("Can generate example response and request bodies") {
openApiTestAllSerializers("T0020__example_req_and_resp.json") { reqRespExamples() }
}
it("Can describe example parameters") {
openApiTestAllSerializers("T0021__example_parameters.json") { exampleParams() }
}
}
describe("Defaults") {
it("Can generate a default parameter value") {
openApiTestAllSerializers("T0022__query_with_default_parameter.json") { defaultParameter() }
} }
} }
describe("Required Fields") { describe("Required Fields") {
@ -185,40 +108,6 @@ class KompendiumTest : DescribeSpec({
openApiTestAllSerializers("T0026__nullable_field.json") { nullableField() } openApiTestAllSerializers("T0026__nullable_field.json") { nullableField() }
} }
} }
describe("Polymorphism and Generics") {
it("can generate a polymorphic response type") {
openApiTestAllSerializers("T0027__polymorphic_response.json") { polymorphicResponse() }
}
it("Can generate a collection with polymorphic response type") {
openApiTestAllSerializers("T0028__polymorphic_list_response.json") { polymorphicCollectionResponse() }
}
it("Can generate a map with a polymorphic response type") {
openApiTestAllSerializers("T0029__polymorphic_map_response.json") { polymorphicMapResponse() }
}
it("Can generate a response type with a generic type") {
openApiTestAllSerializers("T0030__simple_generic_response.json") { simpleGenericResponse() }
}
it("Can generate a response type with a nested generic type") {
openApiTestAllSerializers("T0031__nested_generic_response.json") { nestedGenericResponse() }
}
it("Can generate a polymorphic response type with generics") {
openApiTestAllSerializers("T0032__polymorphic_response_with_generics.json") { genericPolymorphicResponse() }
}
it("Can handle an absolutely psycho inheritance test") {
openApiTestAllSerializers("T0033__crazy_polymorphic_example.json") { genericPolymorphicResponseMultipleImpls() }
}
it("Can support nested generic collections") {
openApiTestAllSerializers("T0039__nested_generic_collection.json") { nestedGenericCollection() }
}
it("Can support nested generics with multiple type parameters") {
openApiTestAllSerializers("T0040__nested_generic_multiple_type_params.json") {
nestedGenericMultipleParamsCollection()
}
}
it("Can handle a really gnarly generic example") {
openApiTestAllSerializers("T0043__gnarly_generic_example.json") { gnarlyGenericResponse() }
}
}
describe("Custom Serializable Reader tests") { describe("Custom Serializable Reader tests") {
it("Can support ignoring fields") { it("Can support ignoring fields") {
openApiTestAllSerializers("T0048__ignored_property.json") { ignoredFieldsResponse() } openApiTestAllSerializers("T0048__ignored_property.json") { ignoredFieldsResponse() }
@ -255,6 +144,9 @@ class KompendiumTest : DescribeSpec({
it("Can have a nullable enum as a member field") { it("Can have a nullable enum as a member field") {
openApiTestAllSerializers("T0037__nullable_enum_field.json") { nullableEnumField() } openApiTestAllSerializers("T0037__nullable_enum_field.json") { nullableEnumField() }
} }
it("Can have a list of enums as a field") {
openApiTestAllSerializers("T0076__list_of_enums.json") { returnsEnumList() }
}
it("Can have a nullable reference without impacting base type") { it("Can have a nullable reference without impacting base type") {
openApiTestAllSerializers("T0041__nullable_reference.json") { nullableReference() } openApiTestAllSerializers("T0041__nullable_reference.json") { nullableReference() }
} }
@ -289,182 +181,49 @@ class KompendiumTest : DescribeSpec({
it("Can generate paths without application root-path") { it("Can generate paths without application root-path") {
openApiTestAllSerializers( openApiTestAllSerializers(
"T0054__app_with_rootpath.json", "T0054__app_with_rootpath.json",
applicationEnvironmentBuilder = { applicationSetup = {
rootPath = "/example" rootPath = "/example"
}, },
specOverrides = { specOverrides = {
copy( copy(
servers = servers.map { it.copy(url = URI("${it.url}/example")) }.toMutableList() servers = servers.map { it.copy(url = URI("${it.url}/example")) }.toMutableList()
) )
},
serverConfigSetup = {
rootPath = "/example"
} }
) { notarizedGet() } ) { notarizedGet() }
} }
} it("Can apply a custom serialization strategy to the openapi document") {
describe("Error Handling") { val customJsonEncoder = Json {
it("Throws a clear exception when an unidentified type is encountered") { serializersModule = KompendiumSerializersModule.module
val exception = shouldThrow<UnknownSchemaException> { openApiTestAllSerializers("") { dateTimeString() } } encodeDefaults = true
exception.message should startWith("An unknown type was encountered: class java.time.Instant") explicitNulls = false
}
it("Throws an exception when same method for same path has been previously registered") {
val exception = shouldThrow<IllegalArgumentException> {
openApiTestAllSerializers(
snapshotName = "",
applicationSetup = {
install(Authentication) {
basic("basic") {
realm = "Ktor Server"
validate { UserIdPrincipal("Placeholder") }
}
}
},
) {
samePathSameMethod()
}
} }
exception.message should startWith("A route has already been registered for path: /test/{a} and method: GET")
}
}
describe("Formats") {
it("Can set a format for a simple type schema") {
openApiTestAllSerializers( openApiTestAllSerializers(
snapshotName = "T0038__formatted_date_time_string.json", snapshotName = "T0072__custom_serialization_strategy.json",
customTypes = mapOf(typeOf<Instant>() to TypeDefinition(type = "string", format = "date")) notarizedApplicationConfigOverrides = {
) { dateTimeString() } specRoute = { spec, routing ->
} routing.route("/openapi.json") {
} get {
describe("Free Form") { call.response.headers.append("Content-Type", "application/json")
// todo Assess strategies here call.respondText { customJsonEncoder.encodeToString(spec) }
}
describe("Authentication") {
it("Can add a default auth config by default") {
openApiTestAllSerializers(
snapshotName = "T0045__default_auth_config.json",
applicationSetup = {
install(Authentication) {
basic("basic") {
realm = "Ktor Server"
validate { UserIdPrincipal("Placeholder") }
}
}
},
specOverrides = {
this.copy(
components = Components(
securitySchemes = mutableMapOf(
"basic" to BasicAuth()
)
)
)
}
) { defaultAuthConfig() }
}
it("Can provide custom auth config with proper scopes") {
openApiTestAllSerializers(
snapshotName = "T0046__custom_auth_config.json",
applicationSetup = {
install(Authentication) {
oauth("auth-oauth-google") {
urlProvider = { "http://localhost:8080/callback" }
providerLookup = {
OAuthServerSettings.OAuth2ServerSettings(
name = "google",
authorizeUrl = "https://accounts.google.com/o/oauth2/auth",
accessTokenUrl = "https://accounts.google.com/o/oauth2/token",
requestMethod = HttpMethod.Post,
clientId = "DUMMY_VAL",
clientSecret = "DUMMY_VAL",
defaultScopes = listOf("https://www.googleapis.com/auth/userinfo.profile"),
extraTokenParameters = listOf("access_type" to "offline")
)
}
client = HttpClient(CIO)
}
}
},
specOverrides = {
this.copy(
components = Components(
securitySchemes = mutableMapOf(
"auth-oauth-google" to OAuth(
flows = OAuth.Flows(
implicit = OAuth.Flows.Implicit(
authorizationUrl = "https://accounts.google.com/o/oauth2/auth",
scopes = mapOf(
"write:pets" to "modify pets in your account",
"read:pets" to "read your pets"
)
)
)
)
)
)
)
}
) { customAuthConfig() }
}
it("Can provide multiple authentication strategies") {
openApiTestAllSerializers(
snapshotName = "T0047__multiple_auth_strategies.json",
applicationSetup = {
install(Authentication) {
apiKey("api-key") {
headerName = "X-API-KEY"
validate {
UserIdPrincipal("Placeholder")
} }
} }
jwt("jwt") {
realm = "Server"
}
} }
}, },
specOverrides = { contentNegotiation = {
this.copy( json(
components = Components( Json {
securitySchemes = mutableMapOf( encodeDefaults = true
"jwt" to BearerAuth("JWT"), explicitNulls = true
"api-key" to ApiKeyAuth(ApiKeyAuth.ApiKeyLocation.HEADER, "X-API-KEY") }
)
)
) )
} }
) { multipleAuthStrategies() } ) { notarizedGet() }
} }
} it("Can serialize a data class with a field outside of the constructor") {
describe("Enrichment") { openApiTestAllSerializers("T0073__data_class_with_field_outside_constructor.json") { fieldOutsideConstructor() }
it("Can enrich a simple request") {
openApiTestAllSerializers("T0055__enriched_simple_request.json") { enrichedSimpleRequest() }
}
it("Can enrich a simple response") {
openApiTestAllSerializers("T0058__enriched_simple_response.json") { enrichedSimpleResponse() }
}
it("Can enrich a nested collection") {
openApiTestAllSerializers("T0056__enriched_nested_collection.json") { enrichedNestedCollection() }
}
it("Can enrich a complex generic type") {
openApiTestAllSerializers("T0057__enriched_complex_generic_type.json") { enrichedComplexGenericType() }
}
}
describe("Constraints") {
it("Can apply constraints to an int field") {
openApiTestAllSerializers("T0059__int_constraints.json") { intConstraints() }
}
it("Can apply constraints to a double field") {
openApiTestAllSerializers("T0060__double_constraints.json") { doubleConstraints() }
}
it("Can apply a min and max length to a string field") {
openApiTestAllSerializers("T0061__string_min_max_constraints.json") { stringConstraints() }
}
it("Can apply a pattern to a string field") {
openApiTestAllSerializers("T0062__string_pattern_constraints.json") { stringPatternConstraints() }
}
it("Can apply a content encoding and media type to a string field") {
openApiTestAllSerializers("T0063__string_content_encoding_constraints.json") {
stringContentEncodingConstraints()
}
}
it("Can apply constraints to an array field") {
openApiTestAllSerializers("T0064__array_constraints.json") { arrayConstraints() }
} }
} }
}) })

View File

@ -0,0 +1,19 @@
package io.bkbn.kompendium.core
import io.bkbn.kompendium.core.fixtures.TestHelpers
import io.bkbn.kompendium.core.util.dateTimeString
import io.bkbn.kompendium.json.schema.definition.TypeDefinition
import io.kotest.core.spec.style.DescribeSpec
import java.time.Instant
import kotlin.reflect.typeOf
class KompendiumTypeFormatTest : DescribeSpec({
describe("Formats") {
it("Can set a format for a simple type schema") {
TestHelpers.openApiTestAllSerializers(
snapshotName = "T0038__formatted_date_time_string.json",
customTypes = mapOf(typeOf<Instant>() to TypeDefinition(type = "string", format = "date"))
) { dateTimeString() }
}
}
})

View File

@ -2,18 +2,18 @@ package io.bkbn.kompendium.core.util
import io.bkbn.kompendium.core.fixtures.TestResponse import io.bkbn.kompendium.core.fixtures.TestResponse
import io.bkbn.kompendium.core.metadata.GetInfo import io.bkbn.kompendium.core.metadata.GetInfo
import io.bkbn.kompendium.core.metadata.PostInfo
import io.bkbn.kompendium.core.plugin.NotarizedRoute import io.bkbn.kompendium.core.plugin.NotarizedRoute
import io.bkbn.kompendium.core.util.TestModules.defaultPathDescription import io.bkbn.kompendium.core.util.TestModules.defaultPathDescription
import io.bkbn.kompendium.core.util.TestModules.defaultPathSummary import io.bkbn.kompendium.core.util.TestModules.defaultPathSummary
import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription
import io.bkbn.kompendium.core.util.TestModules.rootPath import io.bkbn.kompendium.core.util.TestModules.rootPath
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.application.install
import io.ktor.server.auth.authenticate import io.ktor.server.auth.authenticate
import io.ktor.server.routing.Routing import io.ktor.server.routing.Route
import io.ktor.server.routing.route import io.ktor.server.routing.route
fun Routing.defaultAuthConfig() { fun Route.defaultAuthConfig() {
authenticate("basic") { authenticate("basic") {
route(rootPath) { route(rootPath) {
basicGetGenerator<TestResponse>() basicGetGenerator<TestResponse>()
@ -21,7 +21,7 @@ fun Routing.defaultAuthConfig() {
} }
} }
fun Routing.customAuthConfig() { fun Route.customAuthConfig() {
authenticate("auth-oauth-google") { authenticate("auth-oauth-google") {
route(rootPath) { route(rootPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
@ -42,7 +42,44 @@ fun Routing.customAuthConfig() {
} }
} }
fun Routing.multipleAuthStrategies() { fun Route.customScopesOnSiblingPathOperations() {
authenticate("auth-oauth-google") {
route(rootPath) {
install(NotarizedRoute()) {
get = GetInfo.builder {
summary(defaultPathSummary)
description(defaultPathDescription)
response {
description(defaultResponseDescription)
responseCode(HttpStatusCode.OK)
responseType<TestResponse>()
}
security = mapOf(
"auth-oauth-google" to listOf("read:pets")
)
}
post = PostInfo.builder {
summary(defaultPathSummary)
description(defaultPathDescription)
response {
description(defaultResponseDescription)
responseCode(HttpStatusCode.OK)
responseType<TestResponse>()
}
request {
description(defaultResponseDescription)
requestType<TestResponse>()
}
security = mapOf(
"auth-oauth-google" to listOf("write:pets")
)
}
}
}
}
}
fun Route.multipleAuthStrategies() {
authenticate("jwt", "api-key") { authenticate("jwt", "api-key") {
route(rootPath) { route(rootPath) {
basicGetGenerator<TestResponse>() basicGetGenerator<TestResponse>()

View File

@ -7,13 +7,15 @@ import io.bkbn.kompendium.core.fixtures.TestNested
import io.bkbn.kompendium.core.metadata.GetInfo import io.bkbn.kompendium.core.metadata.GetInfo
import io.bkbn.kompendium.core.plugin.NotarizedRoute import io.bkbn.kompendium.core.plugin.NotarizedRoute
import io.bkbn.kompendium.core.util.TestModules.defaultPath import io.bkbn.kompendium.core.util.TestModules.defaultPath
import io.bkbn.kompendium.enrichment.TypeEnrichment import io.bkbn.kompendium.enrichment.CollectionEnrichment
import io.bkbn.kompendium.enrichment.NumberEnrichment
import io.bkbn.kompendium.enrichment.ObjectEnrichment
import io.bkbn.kompendium.enrichment.StringEnrichment
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.application.install import io.ktor.server.routing.Route
import io.ktor.server.routing.Routing
import io.ktor.server.routing.route import io.ktor.server.routing.route
fun Routing.intConstraints() { fun Route.intConstraints() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
get = GetInfo.builder { get = GetInfo.builder {
@ -23,22 +25,24 @@ fun Routing.intConstraints() {
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
description("An int") description("An int")
responseType( responseType(
enrichment = TypeEnrichment("example") { enrichment = ObjectEnrichment("example") {
TestCreatedResponse::id { TestCreatedResponse::id {
minimum = 2 NumberEnrichment("blah-blah-blah") {
maximum = 100 minimum = 2
multipleOf = 2 maximum = 100
multipleOf = 2
}
} }
responseCode(HttpStatusCode.OK)
} }
) )
responseCode(HttpStatusCode.OK)
} }
} }
} }
} }
} }
fun Routing.doubleConstraints() { fun Route.doubleConstraints() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
get = GetInfo.builder { get = GetInfo.builder {
@ -48,11 +52,13 @@ fun Routing.doubleConstraints() {
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
description("A double") description("A double")
responseType( responseType(
enrichment = TypeEnrichment("example") { enrichment = ObjectEnrichment("example") {
DoubleResponse::payload { DoubleResponse::payload {
minimum = 2.0 NumberEnrichment("blah-blah-blah") {
maximum = 100.0 minimum = 2.0
multipleOf = 2.0 maximum = 100.0
multipleOf = 2.0
}
} }
} }
) )
@ -63,7 +69,7 @@ fun Routing.doubleConstraints() {
} }
} }
fun Routing.stringConstraints() { fun Route.stringConstraints() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
get = GetInfo.builder { get = GetInfo.builder {
@ -73,10 +79,12 @@ fun Routing.stringConstraints() {
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
description("A string") description("A string")
responseType( responseType(
enrichment = TypeEnrichment("example") { enrichment = ObjectEnrichment("example") {
TestNested::nesty { TestNested::nesty {
maxLength = 10 StringEnrichment("blah") {
minLength = 2 maxLength = 10
minLength = 2
}
} }
} }
) )
@ -87,7 +95,7 @@ fun Routing.stringConstraints() {
} }
} }
fun Routing.stringPatternConstraints() { fun Route.stringPatternConstraints() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
get = GetInfo.builder { get = GetInfo.builder {
@ -97,9 +105,11 @@ fun Routing.stringPatternConstraints() {
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
description("A string") description("A string")
responseType( responseType(
enrichment = TypeEnrichment("example") { enrichment = ObjectEnrichment("example") {
TestNested::nesty { TestNested::nesty {
pattern = "[a-z]+" StringEnrichment("blah") {
pattern = "[a-z]+"
}
} }
} }
) )
@ -110,7 +120,7 @@ fun Routing.stringPatternConstraints() {
} }
} }
fun Routing.stringContentEncodingConstraints() { fun Route.stringContentEncodingConstraints() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
get = GetInfo.builder { get = GetInfo.builder {
@ -120,10 +130,12 @@ fun Routing.stringContentEncodingConstraints() {
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
description("A string") description("A string")
responseType( responseType(
enrichment = TypeEnrichment("example") { enrichment = ObjectEnrichment("example") {
TestNested::nesty { TestNested::nesty {
contentEncoding = "base64" StringEnrichment("blah") {
contentMediaType = "image/png" contentEncoding = "base64"
contentMediaType = "image/png"
}
} }
} }
) )
@ -134,7 +146,7 @@ fun Routing.stringContentEncodingConstraints() {
} }
} }
fun Routing.arrayConstraints() { fun Route.arrayConstraints() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
get = GetInfo.builder { get = GetInfo.builder {
@ -144,11 +156,13 @@ fun Routing.arrayConstraints() {
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
description("An array") description("An array")
responseType( responseType(
enrichment = TypeEnrichment("example") { enrichment = ObjectEnrichment("example") {
Page<String>::content { Page<String>::content {
minItems = 2 CollectionEnrichment<String>("blah") {
maxItems = 10 minItems = 2
uniqueItems = true maxItems = 10
uniqueItems = true
}
} }
} }
) )

View File

@ -3,8 +3,8 @@ package io.bkbn.kompendium.core.util
import io.bkbn.kompendium.core.fixtures.SerialNameObject import io.bkbn.kompendium.core.fixtures.SerialNameObject
import io.bkbn.kompendium.core.fixtures.TransientObject import io.bkbn.kompendium.core.fixtures.TransientObject
import io.bkbn.kompendium.core.fixtures.UnbackedObject import io.bkbn.kompendium.core.fixtures.UnbackedObject
import io.ktor.server.routing.Routing import io.ktor.server.routing.Route
fun Routing.ignoredFieldsResponse() = basicGetGenerator<TransientObject>() fun Route.ignoredFieldsResponse() = basicGetGenerator<TransientObject>()
fun Routing.unbackedFieldsResponse() = basicGetGenerator<UnbackedObject>() fun Route.unbackedFieldsResponse() = basicGetGenerator<UnbackedObject>()
fun Routing.customFieldNameResponse() = basicGetGenerator<SerialNameObject>() fun Route.customFieldNameResponse() = basicGetGenerator<SerialNameObject>()

View File

@ -3,9 +3,9 @@ package io.bkbn.kompendium.core.util
import io.bkbn.kompendium.core.fixtures.TestResponse import io.bkbn.kompendium.core.fixtures.TestResponse
import io.bkbn.kompendium.json.schema.definition.TypeDefinition import io.bkbn.kompendium.json.schema.definition.TypeDefinition
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
import io.ktor.server.routing.Routing import io.ktor.server.routing.Route
fun Routing.defaultParameter() = basicGetGenerator<TestResponse>( fun Route.defaultParameter() = basicGetGenerator<TestResponse>(
params = listOf( params = listOf(
Parameter( Parameter(
name = "id", name = "id",

View File

@ -1,6 +1,7 @@
package io.bkbn.kompendium.core.util package io.bkbn.kompendium.core.util
import io.bkbn.kompendium.core.fixtures.ComplexRequest import io.bkbn.kompendium.core.fixtures.ComplexRequest
import io.bkbn.kompendium.core.fixtures.GenericObject
import io.bkbn.kompendium.core.fixtures.MultiNestedGenerics import io.bkbn.kompendium.core.fixtures.MultiNestedGenerics
import io.bkbn.kompendium.core.fixtures.NestedComplexItem import io.bkbn.kompendium.core.fixtures.NestedComplexItem
import io.bkbn.kompendium.core.fixtures.TestCreatedResponse import io.bkbn.kompendium.core.fixtures.TestCreatedResponse
@ -9,13 +10,17 @@ import io.bkbn.kompendium.core.fixtures.TestSimpleRequest
import io.bkbn.kompendium.core.metadata.GetInfo import io.bkbn.kompendium.core.metadata.GetInfo
import io.bkbn.kompendium.core.metadata.PostInfo import io.bkbn.kompendium.core.metadata.PostInfo
import io.bkbn.kompendium.core.plugin.NotarizedRoute import io.bkbn.kompendium.core.plugin.NotarizedRoute
import io.bkbn.kompendium.enrichment.TypeEnrichment import io.bkbn.kompendium.enrichment.BooleanEnrichment
import io.bkbn.kompendium.enrichment.CollectionEnrichment
import io.bkbn.kompendium.enrichment.MapEnrichment
import io.bkbn.kompendium.enrichment.NumberEnrichment
import io.bkbn.kompendium.enrichment.ObjectEnrichment
import io.bkbn.kompendium.enrichment.StringEnrichment
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.application.install import io.ktor.server.routing.Route
import io.ktor.server.routing.Routing
import io.ktor.server.routing.route import io.ktor.server.routing.route
fun Routing.enrichedSimpleResponse() { fun Route.enrichedSimpleResponse() {
route("/enriched") { route("/enriched") {
install(NotarizedRoute()) { install(NotarizedRoute()) {
get = GetInfo.builder { get = GetInfo.builder {
@ -23,9 +28,11 @@ fun Routing.enrichedSimpleResponse() {
description(TestModules.defaultPathDescription) description(TestModules.defaultPathDescription)
response { response {
responseType( responseType(
enrichment = TypeEnrichment("simple") { enrichment = ObjectEnrichment("simple") {
TestResponse::c { TestResponse::c {
description = "A simple description" StringEnrichment("blah-blah-blah") {
description = "A simple description"
}
} }
} }
) )
@ -37,7 +44,7 @@ fun Routing.enrichedSimpleResponse() {
} }
} }
fun Routing.enrichedSimpleRequest() { fun Route.enrichedSimpleRequest() {
route("/example") { route("/example") {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = TestModules.defaultParams parameters = TestModules.defaultParams
@ -46,45 +53,20 @@ fun Routing.enrichedSimpleRequest() {
description(TestModules.defaultPathDescription) description(TestModules.defaultPathDescription)
request { request {
requestType( requestType(
enrichment = TypeEnrichment("simple") { enrichment = ObjectEnrichment("simple") {
TestSimpleRequest::a { TestSimpleRequest::a {
description = "A simple description" StringEnrichment("blah-blah-blah") {
} description = "A simple description"
TestSimpleRequest::b {
deprecated = true
}
}
)
description("A test request")
}
response {
responseCode(HttpStatusCode.Created)
responseType<TestCreatedResponse>()
description(TestModules.defaultResponseDescription)
}
}
}
}
}
fun Routing.enrichedNestedCollection() {
route("/example") {
install(NotarizedRoute()) {
parameters = TestModules.defaultParams
post = PostInfo.builder {
summary(TestModules.defaultPathSummary)
description(TestModules.defaultPathDescription)
request {
requestType(
enrichment = TypeEnrichment("simple") {
ComplexRequest::tables {
description = "A nested item"
typeEnrichment = TypeEnrichment("nested") {
NestedComplexItem::name {
description = "A nested description"
}
} }
} }
TestSimpleRequest::b {
NumberEnrichment("blah-blah-blah") {
deprecated = true
}
}
TestSimpleRequest::c {
BooleanEnrichment("blah-blah-blah") { }
}
} }
) )
description("A test request") description("A test request")
@ -99,7 +81,7 @@ fun Routing.enrichedNestedCollection() {
} }
} }
fun Routing.enrichedComplexGenericType() { fun Route.enrichedNestedCollection() {
route("/example") { route("/example") {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = TestModules.defaultParams parameters = TestModules.defaultParams
@ -108,14 +90,13 @@ fun Routing.enrichedComplexGenericType() {
description(TestModules.defaultPathDescription) description(TestModules.defaultPathDescription)
request { request {
requestType( requestType(
enrichment = TypeEnrichment("simple") { enrichment = ObjectEnrichment("simple") {
MultiNestedGenerics<String, ComplexRequest>::content { ComplexRequest::tables {
description = "Getting pretty crazy" CollectionEnrichment<NestedComplexItem>("blah-blah") {
typeEnrichment = TypeEnrichment("nested") { description = "A nested description"
ComplexRequest::tables { itemEnrichment = ObjectEnrichment("nested") {
description = "A nested item" NestedComplexItem::name {
typeEnrichment = TypeEnrichment("nested") { StringEnrichment("beleheh") {
NestedComplexItem::name {
description = "A nested description" description = "A nested description"
} }
} }
@ -135,3 +116,149 @@ fun Routing.enrichedComplexGenericType() {
} }
} }
} }
fun Route.enrichedTopLevelCollection() {
route("/example") {
install(NotarizedRoute()) {
parameters = TestModules.defaultParams
post = PostInfo.builder {
summary(TestModules.defaultPathSummary)
description(TestModules.defaultPathDescription)
request {
requestType(
enrichment = CollectionEnrichment<List<TestSimpleRequest>>("blah-blah") {
itemEnrichment = ObjectEnrichment("simple") {
TestSimpleRequest::a {
StringEnrichment("blah-blah-blah") {
description = "A simple description"
}
}
TestSimpleRequest::b {
NumberEnrichment("blah-blah-blah") {
deprecated = true
}
}
}
}
)
description("A test request")
}
response {
responseCode(HttpStatusCode.Created)
responseType<TestCreatedResponse>()
description(TestModules.defaultResponseDescription)
}
}
}
}
}
fun Route.enrichedComplexGenericType() {
route("/example") {
install(NotarizedRoute()) {
parameters = TestModules.defaultParams
post = PostInfo.builder {
summary(TestModules.defaultPathSummary)
description(TestModules.defaultPathDescription)
request {
requestType(
enrichment = ObjectEnrichment("simple") {
MultiNestedGenerics<String, ComplexRequest>::content {
MapEnrichment<ComplexRequest>("blah") {
description = "A nested description"
valueEnrichment = ObjectEnrichment("nested") {
ComplexRequest::tables {
CollectionEnrichment<NestedComplexItem>("blah-blah") {
description = "A nested description"
itemEnrichment = ObjectEnrichment("nested") {
NestedComplexItem::name {
StringEnrichment("beleheh") {
description = "A nested description"
}
}
}
}
}
}
}
}
}
)
description("A test request")
}
response {
responseCode(HttpStatusCode.Created)
responseType<TestCreatedResponse>()
description(TestModules.defaultResponseDescription)
}
}
}
}
}
fun Route.enrichedGenericResponse() {
route("/example") {
install(NotarizedRoute()) {
get = GetInfo.builder {
summary(TestModules.defaultPathSummary)
description(TestModules.defaultPathDescription)
response {
responseType(
enrichment = ObjectEnrichment("generic") {
description = "another description"
GenericObject<TestSimpleRequest>::data {
ObjectEnrichment("simple") {
description = "also a description"
TestSimpleRequest::a {
StringEnrichment("blah-blah-blah") {
description = "A simple description"
}
}
TestSimpleRequest::b {
NumberEnrichment("blah-blah-blah") {
deprecated = true
}
}
}
}
}
)
description("A good response")
responseCode(HttpStatusCode.Created)
}
}
}
}
}
fun Route.enrichedMap() {
route("/example") {
install(NotarizedRoute()) {
get = GetInfo.builder {
summary(TestModules.defaultPathSummary)
description(TestModules.defaultPathDescription)
response {
responseType<Map<String, TestSimpleRequest>>(
enrichment = MapEnrichment("blah") {
description = "A nested description"
valueEnrichment = ObjectEnrichment("nested") {
TestSimpleRequest::a {
StringEnrichment("blah-blah-blah") {
description = "A simple description"
}
}
TestSimpleRequest::b {
NumberEnrichment("blah-blah-blah") {
deprecated = true
}
}
}
}
)
description("A good response")
responseCode(HttpStatusCode.Created)
}
}
}
}
}

View File

@ -3,10 +3,10 @@ package io.bkbn.kompendium.core.util
import io.bkbn.kompendium.core.fixtures.TestResponse import io.bkbn.kompendium.core.fixtures.TestResponse
import io.bkbn.kompendium.core.util.TestModules.defaultPath import io.bkbn.kompendium.core.util.TestModules.defaultPath
import io.ktor.server.auth.authenticate import io.ktor.server.auth.authenticate
import io.ktor.server.routing.Routing import io.ktor.server.routing.Route
import io.ktor.server.routing.route import io.ktor.server.routing.route
fun Routing.samePathSameMethod() { fun Route.samePathSameMethod() {
route(defaultPath) { route(defaultPath) {
basicGetGenerator<TestResponse>() basicGetGenerator<TestResponse>()
authenticate("basic") { authenticate("basic") {

View File

@ -11,13 +11,13 @@ import io.bkbn.kompendium.core.util.TestModules.defaultRequestDescription
import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription
import io.bkbn.kompendium.core.util.TestModules.rootPath import io.bkbn.kompendium.core.util.TestModules.rootPath
import io.bkbn.kompendium.json.schema.definition.TypeDefinition import io.bkbn.kompendium.json.schema.definition.TypeDefinition
import io.bkbn.kompendium.oas.payload.MediaType
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.application.install import io.ktor.server.routing.Route
import io.ktor.server.routing.Routing
import io.ktor.server.routing.route import io.ktor.server.routing.route
fun Routing.reqRespExamples() { fun Route.reqRespExamples() {
route(rootPath) { route(rootPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
post = PostInfo.builder { post = PostInfo.builder {
@ -27,7 +27,7 @@ fun Routing.reqRespExamples() {
description(defaultRequestDescription) description(defaultRequestDescription)
requestType<TestRequest>() requestType<TestRequest>()
examples( examples(
"Testerina" to TestRequest(TestNested("asdf"), 1.5, emptyList()) "Testerina" to MediaType.Example(TestRequest(TestNested("asdf"), 1.5, emptyList()))
) )
} }
response { response {
@ -35,7 +35,7 @@ fun Routing.reqRespExamples() {
responseCode(HttpStatusCode.OK) responseCode(HttpStatusCode.OK)
responseType<TestResponse>() responseType<TestResponse>()
examples( examples(
"Testerino" to TestResponse("Heya") "Testerino" to MediaType.Example(TestResponse("Heya"))
) )
} }
} }
@ -43,15 +43,72 @@ fun Routing.reqRespExamples() {
} }
} }
fun Routing.exampleParams() = basicGetGenerator<TestResponse>( fun Route.exampleParams() = basicGetGenerator<TestResponse>(
params = listOf( params = listOf(
Parameter( Parameter(
name = "id", name = "id",
`in` = Parameter.Location.path, `in` = Parameter.Location.path,
schema = TypeDefinition.STRING, schema = TypeDefinition.STRING,
examples = mapOf( examples = mapOf(
"foo" to Parameter.Example("testing") "foo" to MediaType.Example("testing")
) )
) )
) )
) )
fun Route.optionalReqExample() {
route(rootPath) {
install(NotarizedRoute()) {
post = PostInfo.builder {
summary(defaultPathSummary)
description(defaultPathDescription)
request {
description(defaultRequestDescription)
requestType<TestRequest>()
examples(
"Testerina" to MediaType.Example(TestRequest(TestNested("asdf"), 1.5, emptyList()))
)
required(false)
}
response {
description(defaultResponseDescription)
responseCode(HttpStatusCode.OK)
responseType<TestResponse>()
examples(
"Testerino" to MediaType.Example(TestResponse("Heya"))
)
}
}
}
}
}
fun Route.exampleSummaryAndDescription() {
route(rootPath) {
install(NotarizedRoute()) {
post = PostInfo.builder {
summary("This is a summary")
description("This is a description")
request {
description("This is a request description")
requestType<TestRequest>()
examples(
"Testerina" to MediaType.Example(
TestRequest(TestNested("asdf"), 1.5, emptyList()),
"summary",
"description"
)
)
}
response {
description("This is a response description")
responseCode(HttpStatusCode.OK)
responseType<TestResponse>()
examples(
"Testerino" to MediaType.Example(TestResponse("Heya"), "summary", "description")
)
}
}
}
}
}

View File

@ -11,11 +11,10 @@ import io.bkbn.kompendium.core.util.TestModules.defaultPathSummary
import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription
import io.bkbn.kompendium.core.util.TestModules.rootPath import io.bkbn.kompendium.core.util.TestModules.rootPath
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.application.install import io.ktor.server.routing.Route
import io.ktor.server.routing.Routing
import io.ktor.server.routing.route import io.ktor.server.routing.route
fun Routing.singleException() { fun Route.singleException() {
route(rootPath) { route(rootPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
get = GetInfo.builder { get = GetInfo.builder {
@ -36,7 +35,7 @@ fun Routing.singleException() {
} }
} }
fun Routing.multipleExceptions() { fun Route.multipleExceptions() {
route(rootPath) { route(rootPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
get = GetInfo.builder { get = GetInfo.builder {
@ -62,7 +61,7 @@ fun Routing.multipleExceptions() {
} }
} }
fun Routing.polymorphicException() { fun Route.polymorphicException() {
route(rootPath) { route(rootPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
get = GetInfo.builder { get = GetInfo.builder {
@ -83,7 +82,7 @@ fun Routing.polymorphicException() {
} }
} }
fun Routing.genericException() { fun Route.genericException() {
route(rootPath) { route(rootPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
get = GetInfo.builder { get = GetInfo.builder {

View File

@ -21,17 +21,16 @@ import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription
import io.bkbn.kompendium.json.schema.definition.TypeDefinition import io.bkbn.kompendium.json.schema.definition.TypeDefinition
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.application.install
import io.ktor.server.auth.authenticate import io.ktor.server.auth.authenticate
import io.ktor.server.routing.Routing import io.ktor.server.routing.Route
import io.ktor.server.routing.route import io.ktor.server.routing.route
fun Routing.withOperationId() = basicGetGenerator<TestResponse>(operationId = "getThisDude") fun Route.withOperationId() = basicGetGenerator<TestResponse>(operationId = "getThisDude")
fun Routing.nullableNestedObject() = basicGetGenerator<ProfileUpdateRequest>() fun Route.nullableNestedObject() = basicGetGenerator<ProfileUpdateRequest>()
fun Routing.nullableEnumField() = basicGetGenerator<NullableEnum>() fun Route.nullableEnumField() = basicGetGenerator<NullableEnum>()
fun Routing.nullableReference() = basicGetGenerator<ManyThings>() fun Route.nullableReference() = basicGetGenerator<ManyThings>()
fun Routing.dateTimeString() = basicGetGenerator<DateTimeString>() fun Route.dateTimeString() = basicGetGenerator<DateTimeString>()
fun Routing.headerParameter() = basicGetGenerator<TestResponse>( fun Route.headerParameter() = basicGetGenerator<TestResponse>(
params = listOf( params = listOf(
Parameter( Parameter(
name = "X-User-Email", name = "X-User-Email",
@ -42,10 +41,10 @@ fun Routing.headerParameter() = basicGetGenerator<TestResponse>(
) )
) )
fun Routing.nestedTypeName() = basicGetGenerator<Nested.Response>() fun Route.nestedTypeName() = basicGetGenerator<Nested.Response>()
fun Routing.topLevelNullable() = basicGetGenerator<TestResponse?>() fun Route.topLevelNullable() = basicGetGenerator<TestResponse?>()
fun Routing.simpleRecursive() = basicGetGenerator<ColumnSchema>() fun Route.simpleRecursive() = basicGetGenerator<ColumnSchema>()
fun Routing.samePathDifferentMethodsAndAuth() { fun Route.samePathDifferentMethodsAndAuth() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = defaultParams parameters = defaultParams

View File

@ -1,7 +1,9 @@
package io.bkbn.kompendium.core.util package io.bkbn.kompendium.core.util
import io.bkbn.kompendium.core.fixtures.ComplexRequest import io.bkbn.kompendium.core.fixtures.ComplexRequest
import io.bkbn.kompendium.core.fixtures.SomethingSimilar
import io.bkbn.kompendium.core.fixtures.TestCreatedResponse import io.bkbn.kompendium.core.fixtures.TestCreatedResponse
import io.bkbn.kompendium.core.fixtures.TestEnum
import io.bkbn.kompendium.core.fixtures.TestRequest import io.bkbn.kompendium.core.fixtures.TestRequest
import io.bkbn.kompendium.core.fixtures.TestResponse import io.bkbn.kompendium.core.fixtures.TestResponse
import io.bkbn.kompendium.core.fixtures.TestSimpleRequest import io.bkbn.kompendium.core.fixtures.TestSimpleRequest
@ -20,13 +22,13 @@ import io.bkbn.kompendium.core.util.TestModules.defaultPathSummary
import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription
import io.bkbn.kompendium.core.util.TestModules.rootPath import io.bkbn.kompendium.core.util.TestModules.rootPath
import io.bkbn.kompendium.json.schema.definition.TypeDefinition import io.bkbn.kompendium.json.schema.definition.TypeDefinition
import io.bkbn.kompendium.oas.payload.Header
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.application.call
import io.ktor.server.application.install
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.response.respondText import io.ktor.server.response.respondText
import io.ktor.server.routing.Routing import io.ktor.server.routing.Route
import io.ktor.server.routing.delete import io.ktor.server.routing.delete
import io.ktor.server.routing.get import io.ktor.server.routing.get
import io.ktor.server.routing.head import io.ktor.server.routing.head
@ -36,7 +38,7 @@ import io.ktor.server.routing.post
import io.ktor.server.routing.put import io.ktor.server.routing.put
import io.ktor.server.routing.route import io.ktor.server.routing.route
fun Routing.notarizedGet() { fun Route.notarizedGet() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = defaultParams parameters = defaultParams
@ -56,7 +58,39 @@ fun Routing.notarizedGet() {
} }
} }
fun Routing.notarizedPost() { fun Route.responseHeaders() {
route(defaultPath) {
install(NotarizedRoute()) {
parameters = defaultParams
get = GetInfo.builder {
response {
responseCode(HttpStatusCode.OK)
responseType<TestResponse>()
description(defaultResponseDescription)
responseHeaders(
mapOf(
HttpHeaders.ETag to Header(
TypeDefinition.STRING,
"https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag"
),
HttpHeaders.LastModified to Header(
TypeDefinition.STRING,
"https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified"
),
)
)
}
summary(defaultPathSummary)
description(defaultPathDescription)
}
}
get {
call.respondText { "hey dude ‼️ congrats on the get request" }
}
}
}
fun Route.notarizedPost() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = defaultParams parameters = defaultParams
@ -80,7 +114,7 @@ fun Routing.notarizedPost() {
} }
} }
fun Routing.notarizedPut() { fun Route.notarizedPut() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = defaultParams parameters = defaultParams
@ -104,7 +138,7 @@ fun Routing.notarizedPut() {
} }
} }
fun Routing.notarizedDelete() { fun Route.notarizedDelete() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = defaultParams parameters = defaultParams
@ -124,7 +158,7 @@ fun Routing.notarizedDelete() {
} }
} }
fun Routing.notarizedPatch() { fun Route.notarizedPatch() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = defaultParams parameters = defaultParams
@ -148,7 +182,7 @@ fun Routing.notarizedPatch() {
} }
} }
fun Routing.notarizedHead() { fun Route.notarizedHead() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = defaultParams parameters = defaultParams
@ -169,7 +203,7 @@ fun Routing.notarizedHead() {
} }
} }
fun Routing.notarizedOptions() { fun Route.notarizedOptions() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = defaultParams parameters = defaultParams
@ -189,7 +223,7 @@ fun Routing.notarizedOptions() {
} }
} }
fun Routing.complexRequest() { fun Route.complexRequest() {
route(rootPath) { route(rootPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
put = PutInfo.builder { put = PutInfo.builder {
@ -212,7 +246,7 @@ fun Routing.complexRequest() {
} }
} }
fun Routing.primitives() { fun Route.primitives() {
route(rootPath) { route(rootPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
put = PutInfo.builder { put = PutInfo.builder {
@ -232,7 +266,7 @@ fun Routing.primitives() {
} }
} }
fun Routing.returnsList() { fun Route.returnsList() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = defaultParams parameters = defaultParams
@ -249,7 +283,24 @@ fun Routing.returnsList() {
} }
} }
fun Routing.nonRequiredParams() { fun Route.returnsEnumList() {
route(defaultPath) {
install(NotarizedRoute()) {
parameters = defaultParams
get = GetInfo.builder {
summary(defaultPathSummary)
description(defaultPathDescription)
response {
description("A Successful List-y Endeavor")
responseCode(HttpStatusCode.OK)
responseType<List<TestEnum>>()
}
}
}
}
}
fun Route.nonRequiredParams() {
route("/optional") { route("/optional") {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = listOf( parameters = listOf(
@ -278,7 +329,7 @@ fun Routing.nonRequiredParams() {
} }
} }
fun Routing.overrideMediaTypes() { fun Route.overrideMediaTypes() {
route("/media_types") { route("/media_types") {
install(NotarizedRoute()) { install(NotarizedRoute()) {
put = PutInfo.builder { put = PutInfo.builder {
@ -299,3 +350,39 @@ fun Routing.overrideMediaTypes() {
} }
} }
} }
fun Route.postNoReqBody() {
route("/no_req_body") {
install(NotarizedRoute()) {
post = PostInfo.builder {
summary(defaultPathSummary)
description(defaultPathDescription)
response {
responseType<TestResponse>()
description("Cool response")
responseCode(HttpStatusCode.Created)
}
}
}
}
}
fun Route.fieldOutsideConstructor() {
route("/field_outside_constructor") {
install(NotarizedRoute()) {
post = PostInfo.builder {
summary(defaultPathSummary)
description(defaultPathDescription)
request {
requestType<SomethingSimilar>()
description("A cool request")
}
response {
responseType<TestResponse>()
description("Cool response")
responseCode(HttpStatusCode.Created)
}
}
}
}
}

View File

@ -1,22 +1,26 @@
package io.bkbn.kompendium.core.util package io.bkbn.kompendium.core.util
import io.bkbn.kompendium.core.fixtures.Barzo import io.bkbn.kompendium.core.fixtures.Barzo
import io.bkbn.kompendium.core.fixtures.ChillaxificationMaximization
import io.bkbn.kompendium.core.fixtures.ComplexRequest import io.bkbn.kompendium.core.fixtures.ComplexRequest
import io.bkbn.kompendium.core.fixtures.Flibbity import io.bkbn.kompendium.core.fixtures.Flibbity
import io.bkbn.kompendium.core.fixtures.FlibbityGibbit import io.bkbn.kompendium.core.fixtures.FlibbityGibbit
import io.bkbn.kompendium.core.fixtures.Foosy import io.bkbn.kompendium.core.fixtures.Foosy
import io.bkbn.kompendium.core.fixtures.Gibbity import io.bkbn.kompendium.core.fixtures.Gibbity
import io.bkbn.kompendium.core.fixtures.Gizmo
import io.bkbn.kompendium.core.fixtures.MultiNestedGenerics import io.bkbn.kompendium.core.fixtures.MultiNestedGenerics
import io.bkbn.kompendium.core.fixtures.Page import io.bkbn.kompendium.core.fixtures.Page
import io.ktor.server.routing.Routing import io.ktor.server.routing.Route
fun Routing.polymorphicResponse() = basicGetGenerator<FlibbityGibbit>() fun Route.polymorphicResponse() = basicGetGenerator<FlibbityGibbit>()
fun Routing.polymorphicCollectionResponse() = basicGetGenerator<List<FlibbityGibbit>>() fun Route.polymorphicCollectionResponse() = basicGetGenerator<List<FlibbityGibbit>>()
fun Routing.polymorphicMapResponse() = basicGetGenerator<Map<String, FlibbityGibbit>>() fun Route.polymorphicMapResponse() = basicGetGenerator<Map<String, FlibbityGibbit>>()
fun Routing.simpleGenericResponse() = basicGetGenerator<Gibbity<String>>() fun Route.simpleGenericResponse() = basicGetGenerator<Gibbity<String>>()
fun Routing.gnarlyGenericResponse() = basicGetGenerator<Foosy<Barzo<Int>, String>>() fun Route.gnarlyGenericResponse() = basicGetGenerator<Foosy<Barzo<Int>, String>>()
fun Routing.nestedGenericResponse() = basicGetGenerator<Gibbity<Map<String, String>>>() fun Route.nestedGenericResponse() = basicGetGenerator<Gibbity<Map<String, String>>>()
fun Routing.genericPolymorphicResponse() = basicGetGenerator<Flibbity<Double>>() fun Route.genericPolymorphicResponse() = basicGetGenerator<Flibbity<Double>>()
fun Routing.genericPolymorphicResponseMultipleImpls() = basicGetGenerator<Flibbity<FlibbityGibbit>>() fun Route.genericPolymorphicResponseMultipleImpls() = basicGetGenerator<Flibbity<FlibbityGibbit>>()
fun Routing.nestedGenericCollection() = basicGetGenerator<Page<Int>>() fun Route.nestedGenericCollection() = basicGetGenerator<Page<Int>>()
fun Routing.nestedGenericMultipleParamsCollection() = basicGetGenerator<MultiNestedGenerics<String, ComplexRequest>>() fun Route.nestedGenericMultipleParamsCollection() = basicGetGenerator<MultiNestedGenerics<String, ComplexRequest>>()
fun Route.overrideSealedTypeIdentifier() = basicGetGenerator<ChillaxificationMaximization>()
fun Route.subtypeNotCompleteSetOfParentProperties() = basicGetGenerator<Gizmo>()

View File

@ -5,9 +5,9 @@ import io.bkbn.kompendium.core.fixtures.NullableField
import io.bkbn.kompendium.core.fixtures.TestResponse import io.bkbn.kompendium.core.fixtures.TestResponse
import io.bkbn.kompendium.json.schema.definition.TypeDefinition import io.bkbn.kompendium.json.schema.definition.TypeDefinition
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
import io.ktor.server.routing.Routing import io.ktor.server.routing.Route
fun Routing.requiredParams() = basicGetGenerator<TestResponse>( fun Route.requiredParams() = basicGetGenerator<TestResponse>(
params = listOf( params = listOf(
Parameter( Parameter(
name = "id", name = "id",
@ -17,7 +17,7 @@ fun Routing.requiredParams() = basicGetGenerator<TestResponse>(
) )
) )
fun Routing.nonRequiredParam() = basicGetGenerator<TestResponse>( fun Route.nonRequiredParam() = basicGetGenerator<TestResponse>(
params = listOf( params = listOf(
Parameter( Parameter(
name = "id", name = "id",
@ -28,5 +28,5 @@ fun Routing.nonRequiredParam() = basicGetGenerator<TestResponse>(
) )
) )
fun Routing.defaultField() = basicGetGenerator<DefaultField>() fun Route.defaultField() = basicGetGenerator<DefaultField>()
fun Routing.nullableField() = basicGetGenerator<NullableField>() fun Route.nullableField() = basicGetGenerator<NullableField>()

View File

@ -11,11 +11,11 @@ import io.bkbn.kompendium.core.util.TestModules.rootPath
import io.bkbn.kompendium.json.schema.definition.TypeDefinition import io.bkbn.kompendium.json.schema.definition.TypeDefinition
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.application.install import io.ktor.server.routing.Route
import io.ktor.server.routing.Routing
import io.ktor.server.routing.route import io.ktor.server.routing.route
import io.ktor.server.routing.param
fun Routing.simplePathParsing() { fun Route.simplePathParsing() {
route("/this") { route("/this") {
route("/is") { route("/is") {
route("/a") { route("/a") {
@ -48,7 +48,7 @@ fun Routing.simplePathParsing() {
} }
} }
fun Routing.rootRoute() { fun Route.rootRoute() {
route(rootPath) { route(rootPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
parameters = listOf(defaultParams.last()) parameters = listOf(defaultParams.last())
@ -65,7 +65,7 @@ fun Routing.rootRoute() {
} }
} }
fun Routing.nestedUnderRoot() { fun Route.nestedUnderRoot() {
route("/") { route("/") {
route("/testerino") { route("/testerino") {
install(NotarizedRoute()) { install(NotarizedRoute()) {
@ -83,7 +83,7 @@ fun Routing.nestedUnderRoot() {
} }
} }
fun Routing.trailingSlash() { fun Route.trailingSlash() {
route("/test") { route("/test") {
route("/") { route("/") {
install(NotarizedRoute()) { install(NotarizedRoute()) {
@ -100,3 +100,32 @@ fun Routing.trailingSlash() {
} }
} }
} }
fun Route.paramWrapper() {
route("/test") {
param("a") {
param("b") {
param("c") {
install(NotarizedRoute()) {
parameters = listOf(
Parameter(
name = "test",
`in` = Parameter.Location.query,
schema = TypeDefinition.STRING
)
)
get = GetInfo.builder {
summary(defaultPathSummary)
description(defaultPathDescription)
response {
description(defaultResponseDescription)
responseCode(HttpStatusCode.OK)
responseType<TestResponse>()
}
}
}
}
}
}
}
}

View File

@ -9,7 +9,6 @@ import io.bkbn.kompendium.core.util.TestModules.rootPath
import io.bkbn.kompendium.json.schema.definition.TypeDefinition import io.bkbn.kompendium.json.schema.definition.TypeDefinition
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.application.install
import io.ktor.server.routing.Route import io.ktor.server.routing.Route
import io.ktor.server.routing.Routing import io.ktor.server.routing.Routing
import io.ktor.server.routing.route import io.ktor.server.routing.route

View File

@ -109,11 +109,15 @@
"b": { "b": {
"type": "number", "type": "number",
"format": "int32" "format": "int32"
},
"c": {
"type": "boolean"
} }
}, },
"required": [ "required": [
"a", "a",
"b" "b",
"c"
] ]
} }
}, },

View File

@ -109,11 +109,15 @@
"b": { "b": {
"type": "number", "type": "number",
"format": "int32" "format": "int32"
},
"c": {
"type": "boolean"
} }
}, },
"required": [ "required": [
"a", "a",
"b" "b",
"c"
] ]
} }
}, },

View File

@ -109,11 +109,15 @@
"b": { "b": {
"type": "number", "type": "number",
"format": "int32" "format": "int32"
},
"c": {
"type": "boolean"
} }
}, },
"required": [ "required": [
"a", "a",
"b" "b",
"c"
] ]
} }
}, },

View File

@ -132,7 +132,6 @@
] ]
}, },
"SimpleEnum": { "SimpleEnum": {
"type": "string",
"enum": [ "enum": [
"ONE", "ONE",
"TWO" "TWO"

View File

@ -86,12 +86,18 @@
}, },
"z": { "z": {
"type": "string" "type": "string"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.ComplexGibbit"
]
} }
}, },
"required": [ "required": [
"b", "b",
"c", "c",
"z" "z",
"type"
] ]
}, },
"SimpleGibbit": { "SimpleGibbit": {
@ -102,10 +108,16 @@
}, },
"z": { "z": {
"type": "string" "type": "string"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.SimpleGibbit"
]
} }
}, },
"required": [ "required": [
"a" "a",
"type"
] ]
}, },
"FlibbityGibbit": { "FlibbityGibbit": {

View File

@ -82,11 +82,17 @@
}, },
"f": { "f": {
"type": "string" "type": "string"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.Bibbity"
]
} }
}, },
"required": [ "required": [
"b", "b",
"f" "f",
"type"
] ]
}, },
"Gibbity-String": { "Gibbity-String": {
@ -94,10 +100,16 @@
"properties": { "properties": {
"a": { "a": {
"type": "string" "type": "string"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.Gibbity"
]
} }
}, },
"required": [ "required": [
"a" "a",
"type"
] ]
}, },
"Flibbity-String": { "Flibbity-String": {

View File

@ -65,12 +65,18 @@
}, },
"z": { "z": {
"type": "string" "type": "string"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.ComplexGibbit"
]
} }
}, },
"required": [ "required": [
"b", "b",
"c", "c",
"z" "z",
"type"
] ]
}, },
"SimpleGibbit": { "SimpleGibbit": {
@ -81,10 +87,16 @@
}, },
"z": { "z": {
"type": "string" "type": "string"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.SimpleGibbit"
]
} }
}, },
"required": [ "required": [
"a" "a",
"type"
] ]
}, },
"FlibbityGibbit": { "FlibbityGibbit": {

View File

@ -65,12 +65,18 @@
}, },
"z": { "z": {
"type": "string" "type": "string"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.ComplexGibbit"
]
} }
}, },
"required": [ "required": [
"b", "b",
"c", "c",
"z" "z",
"type"
] ]
}, },
"SimpleGibbit": { "SimpleGibbit": {
@ -81,10 +87,16 @@
}, },
"z": { "z": {
"type": "string" "type": "string"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.SimpleGibbit"
]
} }
}, },
"required": [ "required": [
"a" "a",
"type"
] ]
}, },
"List-FlibbityGibbit": { "List-FlibbityGibbit": {

View File

@ -65,12 +65,18 @@
}, },
"z": { "z": {
"type": "string" "type": "string"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.ComplexGibbit"
]
} }
}, },
"required": [ "required": [
"b", "b",
"c", "c",
"z" "z",
"type"
] ]
}, },
"SimpleGibbit": { "SimpleGibbit": {
@ -81,10 +87,16 @@
}, },
"z": { "z": {
"type": "string" "type": "string"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.SimpleGibbit"
]
} }
}, },
"required": [ "required": [
"a" "a",
"type"
] ]
}, },
"Map-String-FlibbityGibbit": { "Map-String-FlibbityGibbit": {

View File

@ -62,11 +62,17 @@
"f": { "f": {
"type": "number", "type": "number",
"format": "double" "format": "double"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.Bibbity"
]
} }
}, },
"required": [ "required": [
"b", "b",
"f" "f",
"type"
] ]
}, },
"Gibbity-Double": { "Gibbity-Double": {
@ -75,10 +81,16 @@
"a": { "a": {
"type": "number", "type": "number",
"format": "double" "format": "double"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.Gibbity"
]
} }
}, },
"required": [ "required": [
"a" "a",
"type"
] ]
}, },
"Flibbity-Double": { "Flibbity-Double": {

View File

@ -53,40 +53,6 @@
"webhooks": {}, "webhooks": {},
"components": { "components": {
"schemas": { "schemas": {
"ComplexGibbit": {
"type": "object",
"properties": {
"b": {
"type": "string"
},
"c": {
"type": "number",
"format": "int32"
},
"z": {
"type": "string"
}
},
"required": [
"b",
"c",
"z"
]
},
"SimpleGibbit": {
"type": "object",
"properties": {
"a": {
"type": "string"
},
"z": {
"type": "string"
}
},
"required": [
"a"
]
},
"Bibbity-FlibbityGibbit": { "Bibbity-FlibbityGibbit": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -102,11 +68,63 @@
"$ref": "#/components/schemas/SimpleGibbit" "$ref": "#/components/schemas/SimpleGibbit"
} }
] ]
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.Bibbity"
]
} }
}, },
"required": [ "required": [
"b", "b",
"f" "f",
"type"
]
},
"ComplexGibbit": {
"type": "object",
"properties": {
"b": {
"type": "string"
},
"c": {
"type": "number",
"format": "int32"
},
"z": {
"type": "string"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.ComplexGibbit"
]
}
},
"required": [
"b",
"c",
"z",
"type"
]
},
"SimpleGibbit": {
"type": "object",
"properties": {
"a": {
"type": "string"
},
"z": {
"type": "string"
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.SimpleGibbit"
]
}
},
"required": [
"a",
"type"
] ]
}, },
"Gibbity-FlibbityGibbit": { "Gibbity-FlibbityGibbit": {
@ -121,10 +139,16 @@
"$ref": "#/components/schemas/SimpleGibbit" "$ref": "#/components/schemas/SimpleGibbit"
} }
] ]
},
"type": {
"enum": [
"io.bkbn.kompendium.core.fixtures.Gibbity"
]
} }
}, },
"required": [ "required": [
"a" "a",
"type"
] ]
}, },
"Flibbity-FlibbityGibbit": { "Flibbity-FlibbityGibbit": {

View File

@ -71,7 +71,6 @@
}, },
"TestEnum": "TestEnum":
{ {
"type": "string",
"enum": [ "enum": [
"YES", "YES",
"NO" "NO"

View File

@ -119,7 +119,6 @@
] ]
}, },
"SimpleEnum": { "SimpleEnum": {
"type": "string",
"enum": [ "enum": [
"ONE", "ONE",
"TWO" "TWO"

View File

@ -54,7 +54,6 @@
"components": { "components": {
"schemas": { "schemas": {
"ColumnMode": { "ColumnMode": {
"type": "string",
"enum": [ "enum": [
"NULLABLE", "NULLABLE",
"REQUIRED", "REQUIRED",

View File

@ -144,11 +144,15 @@
"b": { "b": {
"type": "number", "type": "number",
"format": "int32" "format": "int32"
},
"c": {
"type": "boolean"
} }
}, },
"required": [ "required": [
"a", "a",
"b" "b",
"c"
] ]
} }
}, },

View File

@ -111,11 +111,15 @@
"type": "number", "type": "number",
"format": "int32", "format": "int32",
"deprecated": true "deprecated": true
},
"c": {
"type": "boolean"
} }
}, },
"required": [ "required": [
"a", "a",
"b" "b",
"c"
] ]
} }
}, },

View File

@ -111,9 +111,9 @@
}, },
"tables": { "tables": {
"items": { "items": {
"$ref": "#/components/schemas/NestedComplexItem-nested" "$ref": "#/components/schemas/NestedComplexItem-blah-blah"
}, },
"description": "A nested item", "description": "A nested description",
"type": "array" "type": "array"
} }
}, },
@ -154,11 +154,29 @@
] ]
}, },
"SimpleEnum": { "SimpleEnum": {
"type": "string",
"enum": [ "enum": [
"ONE", "ONE",
"TWO" "TWO"
] ]
},
"NestedComplexItem-blah-blah": {
"type": "object",
"properties": {
"alias": {
"additionalProperties": {
"$ref": "#/components/schemas/CrazyItem"
},
"type": "object"
},
"name": {
"type": "string",
"description": "A nested description"
}
},
"required": [
"alias",
"name"
]
} }
}, },
"securitySchemes": {} "securitySchemes": {}

View File

@ -105,9 +105,9 @@
"properties": { "properties": {
"content": { "content": {
"additionalProperties": { "additionalProperties": {
"$ref": "#/components/schemas/ComplexRequest-nested" "$ref": "#/components/schemas/ComplexRequest-blah"
}, },
"description": "Getting pretty crazy", "description": "A nested description",
"type": "object" "type": "object"
} }
}, },
@ -126,9 +126,9 @@
}, },
"tables": { "tables": {
"items": { "items": {
"$ref": "#/components/schemas/NestedComplexItem-nested" "$ref": "#/components/schemas/NestedComplexItem-blah-blah"
}, },
"description": "A nested item", "description": "A nested description",
"type": "array" "type": "array"
} }
}, },
@ -169,11 +169,52 @@
] ]
}, },
"SimpleEnum": { "SimpleEnum": {
"type": "string",
"enum": [ "enum": [
"ONE", "ONE",
"TWO" "TWO"
] ]
},
"NestedComplexItem-blah-blah": {
"type": "object",
"properties": {
"alias": {
"additionalProperties": {
"$ref": "#/components/schemas/CrazyItem"
},
"type": "object"
},
"name": {
"type": "string",
"description": "A nested description"
}
},
"required": [
"alias",
"name"
]
},
"ComplexRequest-blah": {
"type": "object",
"properties": {
"amazingField": {
"type": "string"
},
"org": {
"type": "string"
},
"tables": {
"items": {
"$ref": "#/components/schemas/NestedComplexItem-blah-blah"
},
"description": "A nested description",
"type": "array"
}
},
"required": [
"amazingField",
"org",
"tables"
]
} }
}, },
"securitySchemes": {} "securitySchemes": {}

View File

@ -0,0 +1,72 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/no_req_body": {
"post": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"responses": {
"201": {
"description": "Cool response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
}
}
}
}
},
"deprecated": false
},
"parameters": []
}
},
"webhooks": {},
"components": {
"schemas": {
"TestResponse": {
"type": "object",
"properties": {
"c": {
"type": "string"
}
},
"required": [
"c"
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -27,15 +27,33 @@
} }
], ],
"paths": { "paths": {
"/type/{name}/edit": { "/test/{a}": {
"get": { "get": {
"tags": [], "tags": [],
"summary": "Edit", "summary": "Great Summary!",
"description": "example location", "description": "testing more",
"parameters": [], "parameters": [],
"responses": { "responses": {
"200": { "200": {
"description": "does great things", "description": "A Successful Endeavor",
"headers": {
"ETag": {
"schema": {
"type": "string"
},
"description": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag",
"required": true,
"deprecated": false
},
"Last-Modified": {
"schema": {
"type": "string"
},
"description": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified",
"required": true,
"deprecated": false
}
},
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
@ -49,39 +67,7 @@
}, },
"parameters": [ "parameters": [
{ {
"name": "name", "name": "a",
"in": "path",
"schema": {
"type": "string"
},
"required": true,
"deprecated": false
}
]
},
"/type/{name}/other/{page}": {
"get": {
"tags": [],
"summary": "Other",
"description": "example location",
"parameters": [],
"responses": {
"200": {
"description": "does great things",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
}
}
}
}
},
"deprecated": false
},
"parameters": [
{
"name": "name",
"in": "path", "in": "path",
"schema": { "schema": {
"type": "string" "type": "string"
@ -90,8 +76,8 @@
"deprecated": false "deprecated": false
}, },
{ {
"name": "page", "name": "aa",
"in": "path", "in": "query",
"schema": { "schema": {
"type": "number", "type": "number",
"format": "int32" "format": "int32"

View File

@ -0,0 +1,95 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/example": {
"get": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"responses": {
"201": {
"description": "A good response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenericObject-TestSimpleRequest-generic"
}
}
}
}
},
"deprecated": false
},
"parameters": []
}
},
"webhooks": {},
"components": {
"schemas": {
"GenericObject-TestSimpleRequest-generic": {
"type": "object",
"properties": {
"data": {
"$ref": "#/components/schemas/TestSimpleRequest-simple",
"description": "also a description"
}
},
"required": [
"data"
]
},
"TestSimpleRequest-simple": {
"type": "object",
"properties": {
"a": {
"type": "string",
"description": "A simple description"
},
"b": {
"type": "number",
"format": "int32",
"deprecated": true
},
"c": {
"type": "boolean"
}
},
"required": [
"a",
"b",
"c"
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,82 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/test": {
"get": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"responses": {
"200": {
"description": "A Successful Endeavor",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
}
}
}
}
},
"deprecated": false
},
"parameters": [
{
"name": "test",
"in": "query",
"schema": {
"type": "string"
},
"required": true,
"deprecated": false
}
]
}
},
"webhooks": {},
"components": {
"schemas": {
"TestResponse": {
"type": "object",
"properties": {
"c": {
"type": "string"
}
},
"required": [
"c"
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,136 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/": {
"post": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"requestBody": {
"description": "You gotta send it",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestRequest"
},
"examples": {
"Testerina": {
"value": {
"fieldName": {
"nesty": "asdf"
},
"b": 1.5,
"aaa": []
}
}
}
}
},
"required": false
},
"responses": {
"200": {
"description": "A Successful Endeavor",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
},
"examples": {
"Testerino": {
"value": {
"c": "Heya"
}
}
}
}
}
}
},
"deprecated": false
},
"parameters": []
}
},
"webhooks": {},
"components": {
"schemas": {
"TestResponse": {
"type": "object",
"properties": {
"c": {
"type": "string"
}
},
"required": [
"c"
]
},
"TestRequest": {
"type": "object",
"properties": {
"aaa": {
"items": {
"type": "number",
"format": "int64"
},
"type": "array"
},
"b": {
"type": "number",
"format": "double"
},
"fieldName": {
"$ref": "#/components/schemas/TestNested"
}
},
"required": [
"aaa",
"b",
"fieldName"
]
},
"TestNested": {
"type": "object",
"properties": {
"nesty": {
"type": "string"
}
},
"required": [
"nesty"
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,106 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/": {
"get": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"responses": {
"200": {
"description": "A Successful Endeavor",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ChillaxificationMaximization"
}
}
}
}
},
"deprecated": false
},
"parameters": []
}
},
"webhooks": {},
"components": {
"schemas": {
"Chillax": {
"type": "object",
"properties": {
"a": {
"type": "string"
},
"type": {
"enum": [
"chillax"
]
}
},
"required": [
"a",
"type"
]
},
"ToDaMax": {
"type": "object",
"properties": {
"b": {
"type": "number",
"format": "int32"
},
"type": {
"enum": [
"maximize"
]
}
},
"required": [
"b",
"type"
]
},
"ChillaxificationMaximization": {
"anyOf": [
{
"$ref": "#/components/schemas/Chillax"
},
{
"$ref": "#/components/schemas/ToDaMax"
}
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,72 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/": {
"get": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"responses": {
"200": {
"description": "A Successful Endeavor",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Gizmo"
}
}
}
}
},
"deprecated": false
},
"parameters": []
}
},
"webhooks": {},
"components": {
"schemas": {
"Gizmo": {
"type": "object",
"properties": {
"title": {
"type": "string"
}
},
"required": [
"title"
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -27,15 +27,15 @@
} }
], ],
"paths": { "paths": {
"/list/{name}/page/{page}": { "/test/{a}": {
"get": { "get": {
"tags": [], "tags": [],
"summary": "Location", "summary": "Great Summary!",
"description": "example location", "description": "testing more",
"parameters": [], "parameters": [],
"responses": { "responses": {
"200": { "200": {
"description": "does great things", "description": "A Successful Endeavor",
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
@ -49,7 +49,7 @@
}, },
"parameters": [ "parameters": [
{ {
"name": "name", "name": "a",
"in": "path", "in": "path",
"schema": { "schema": {
"type": "string" "type": "string"
@ -58,8 +58,8 @@
"deprecated": false "deprecated": false
}, },
{ {
"name": "page", "name": "aa",
"in": "path", "in": "query",
"schema": { "schema": {
"type": "number", "type": "number",
"format": "int32" "format": "int32"

View File

@ -0,0 +1,94 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/field_outside_constructor": {
"post": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"requestBody": {
"description": "A cool request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SomethingSimilar"
}
}
},
"required": true
},
"responses": {
"201": {
"description": "Cool response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
}
}
}
}
},
"deprecated": false
},
"parameters": []
}
},
"webhooks": {},
"components": {
"schemas": {
"TestResponse": {
"type": "object",
"properties": {
"c": {
"type": "string"
}
},
"required": [
"c"
]
},
"SomethingSimilar": {
"type": "object",
"properties": {
"a": {
"type": "string"
}
},
"required": [
"a"
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,129 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/": {
"get": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"responses": {
"200": {
"description": "A Successful Endeavor",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
}
}
}
}
},
"deprecated": false,
"security": [
{
"auth-oauth-google": [
"read:pets"
]
}
]
},
"post": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"requestBody": {
"description": "A Successful Endeavor",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "A Successful Endeavor",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
}
}
}
}
},
"deprecated": false,
"security": [
{
"auth-oauth-google": [
"write:pets"
]
}
]
},
"parameters": []
}
},
"webhooks": {},
"components": {
"schemas": {
"TestResponse": {
"type": "object",
"properties": {
"c": {
"type": "string"
}
},
"required": [
"c"
]
}
},
"securitySchemes": {
"auth-oauth-google": {
"flows": {
"implicit": {
"authorizationUrl": "https://accounts.google.com/o/oauth2/auth",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
}
}
},
"type": "oauth2"
}
}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,140 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/": {
"post": {
"tags": [],
"summary": "This is a summary",
"description": "This is a description",
"parameters": [],
"requestBody": {
"description": "This is a request description",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestRequest"
},
"examples": {
"Testerina": {
"value": {
"fieldName": {
"nesty": "asdf"
},
"b": 1.5,
"aaa": []
},
"summary": "summary",
"description": "description"
}
}
}
},
"required": true
},
"responses": {
"200": {
"description": "This is a response description",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
},
"examples": {
"Testerino": {
"value": {
"c": "Heya"
},
"summary": "summary",
"description": "description"
}
}
}
}
}
},
"deprecated": false
},
"parameters": []
}
},
"webhooks": {},
"components": {
"schemas": {
"TestResponse": {
"type": "object",
"properties": {
"c": {
"type": "string"
}
},
"required": [
"c"
]
},
"TestRequest": {
"type": "object",
"properties": {
"aaa": {
"items": {
"type": "number",
"format": "int64"
},
"type": "array"
},
"b": {
"type": "number",
"format": "double"
},
"fieldName": {
"$ref": "#/components/schemas/TestNested"
}
},
"required": [
"aaa",
"b",
"fieldName"
]
},
"TestNested": {
"type": "object",
"properties": {
"nesty": {
"type": "string"
}
},
"required": [
"nesty"
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,93 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/test/{a}": {
"get": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"responses": {
"200": {
"description": "A Successful List-y Endeavor",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/List-TestEnum"
}
}
}
}
},
"deprecated": false
},
"parameters": [
{
"name": "a",
"in": "path",
"schema": {
"type": "string"
},
"required": true,
"deprecated": false
},
{
"name": "aa",
"in": "query",
"schema": {
"type": "number",
"format": "int32"
},
"required": true,
"deprecated": false
}
]
}
},
"webhooks": {},
"components": {
"schemas": {
"TestEnum": {
"enum": [
"YES",
"NO"
]
},
"List-TestEnum": {
"items": {
"$ref": "#/components/schemas/TestEnum"
},
"type": "array"
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,158 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/example": {
"post": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"requestBody": {
"description": "A test request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/List-TestSimpleRequest-blah-blah"
}
}
},
"required": true
},
"responses": {
"201": {
"description": "A Successful Endeavor",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestCreatedResponse"
}
}
}
}
},
"deprecated": false
},
"parameters": [
{
"name": "a",
"in": "path",
"schema": {
"type": "string"
},
"required": true,
"deprecated": false
},
{
"name": "aa",
"in": "query",
"schema": {
"type": "number",
"format": "int32"
},
"required": true,
"deprecated": false
}
]
}
},
"webhooks": {},
"components": {
"schemas": {
"TestCreatedResponse": {
"type": "object",
"properties": {
"c": {
"type": "string"
},
"id": {
"type": "number",
"format": "int32"
}
},
"required": [
"c",
"id"
]
},
"TestSimpleRequest-simple": {
"type": "object",
"properties": {
"a": {
"type": "string",
"description": "A simple description"
},
"b": {
"type": "number",
"format": "int32",
"deprecated": true
},
"c": {
"type": "boolean"
}
},
"required": [
"a",
"b",
"c"
]
},
"TestSimpleRequest-blah-blah": {
"type": "object",
"properties": {
"a": {
"type": "string",
"description": "A simple description"
},
"b": {
"type": "number",
"format": "int32",
"deprecated": true
},
"c": {
"type": "boolean"
}
},
"required": [
"a",
"b",
"c"
]
},
"List-TestSimpleRequest-blah-blah": {
"items": {
"$ref": "#/components/schemas/TestSimpleRequest-blah-blah"
},
"type": "array"
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,111 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/example": {
"get": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"responses": {
"201": {
"description": "A good response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Map-String-TestSimpleRequest-blah"
}
}
}
}
},
"deprecated": false
},
"parameters": []
}
},
"webhooks": {},
"components": {
"schemas": {
"TestSimpleRequest-nested": {
"type": "object",
"properties": {
"a": {
"type": "string",
"description": "A simple description"
},
"b": {
"type": "number",
"format": "int32",
"deprecated": true
},
"c": {
"type": "boolean"
}
},
"required": [
"a",
"b",
"c"
]
},
"TestSimpleRequest-blah": {
"type": "object",
"properties": {
"a": {
"type": "string",
"description": "A simple description"
},
"b": {
"type": "number",
"format": "int32",
"deprecated": true
},
"c": {
"type": "boolean"
}
},
"required": [
"a",
"b",
"c"
]
},
"Map-String-TestSimpleRequest-blah": {
"additionalProperties": {
"$ref": "#/components/schemas/TestSimpleRequest-blah"
},
"type": "object"
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -1,54 +0,0 @@
package io.bkbn.kompendium.core.fixtures
import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonProperty
import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName
import io.bkbn.kompendium.json.schema.SchemaConfigurator
import kotlin.reflect.KClass
import kotlin.reflect.KProperty1
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.javaField
/*
These are test implementation and may well be a good starting point for creating production ones.
Both Gson and Jackson are complex and can achieve this things is more than one way therefore
these will not always work hence why they are in the test package
*/
class GsonSchemaConfigurator: SchemaConfigurator {
override fun serializableMemberProperties(clazz: KClass<*>): Collection<KProperty1<out Any, *>> {
// NOTE: This is test logic Expose is set at a global Gson level so configure to match your Gson set up
val hasAnyExpose = clazz.memberProperties.any { it.hasJavaAnnotation<Expose>() }
return if(hasAnyExpose) {
clazz.memberProperties
.filter { it.hasJavaAnnotation<Expose>() }
} else clazz.memberProperties
}
override fun serializableName(property: KProperty1<out Any, *>): String =
property.getJavaAnnotation<SerializedName>()?.value?: property.name
}
class JacksonSchemaConfigurator: SchemaConfigurator {
override fun serializableMemberProperties(clazz: KClass<*>): Collection<KProperty1<out Any, *>> =
clazz.memberProperties
.filterNot {
it.hasJavaAnnotation<JsonIgnore>()
}
override fun serializableName(property: KProperty1<out Any, *>): String =
property.getJavaAnnotation<JsonProperty>()?.value?: property.name
}
inline fun <reified T: Annotation> KProperty1<*, *>.hasJavaAnnotation(): Boolean {
return javaField?.isAnnotationPresent(T::class.java)?: false
}
inline fun <reified T: Annotation> KProperty1<*, *>.getJavaAnnotation(): T? {
return javaField?.getDeclaredAnnotation(T::class.java)
}

View File

@ -1,7 +0,0 @@
package io.bkbn.kompendium.core.fixtures
enum class SupportedSerializer {
KOTLINX,
GSON,
JACKSON
}

View File

@ -1,7 +1,5 @@
package io.bkbn.kompendium.core.fixtures package io.bkbn.kompendium.core.fixtures
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.SerializationFeature
import io.bkbn.kompendium.core.fixtures.TestSpecs.defaultSpec import io.bkbn.kompendium.core.fixtures.TestSpecs.defaultSpec
import io.bkbn.kompendium.core.plugin.NotarizedApplication import io.bkbn.kompendium.core.plugin.NotarizedApplication
import io.bkbn.kompendium.core.routes.redoc import io.bkbn.kompendium.core.routes.redoc
@ -16,19 +14,18 @@ import io.kotest.matchers.shouldNot
import io.kotest.matchers.string.beBlank import io.kotest.matchers.string.beBlank
import io.ktor.client.request.get import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText import io.ktor.client.statement.bodyAsText
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.serialization.gson.gson
import io.ktor.serialization.jackson.jackson
import io.ktor.serialization.kotlinx.json.json import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.Application import io.ktor.server.application.Application
import io.ktor.server.engine.ApplicationEngineEnvironmentBuilder import io.ktor.server.application.ServerConfigBuilder
import io.ktor.server.engine.ApplicationEnvironmentBuilder
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.routing.Routing import io.ktor.server.plugins.contentnegotiation.ContentNegotiationConfig
import io.ktor.server.routing.Route
import io.ktor.server.testing.ApplicationTestBuilder import io.ktor.server.testing.ApplicationTestBuilder
import io.ktor.server.testing.testApplication import io.ktor.server.testing.testApplication
import java.io.File
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import java.io.File
import kotlin.reflect.KType import kotlin.reflect.KType
object TestHelpers { object TestHelpers {
@ -55,7 +52,7 @@ object TestHelpers {
/** /**
* This will take a provided JSON snapshot file, retrieve it from the resource folder, * This will take a provided JSON snapshot file, retrieve it from the resource folder,
* and build a test ktor server to compare the expected output with the output found in the default * and build a test ktor server to compare the expected output with the output found in the default
* OpenAPI json endpoint. By default, this will run the same test with Gson, Kotlinx, and Jackson serializers * OpenAPI json endpoint.
* @param snapshotName The snapshot file to retrieve from the resources folder * @param snapshotName The snapshot file to retrieve from the resources folder
*/ */
fun openApiTestAllSerializers( fun openApiTestAllSerializers(
@ -63,79 +60,62 @@ object TestHelpers {
customTypes: Map<KType, JsonSchema> = emptyMap(), customTypes: Map<KType, JsonSchema> = emptyMap(),
applicationSetup: Application.() -> Unit = { }, applicationSetup: Application.() -> Unit = { },
specOverrides: OpenApiSpec.() -> OpenApiSpec = { this }, specOverrides: OpenApiSpec.() -> OpenApiSpec = { this },
applicationEnvironmentBuilder: ApplicationEngineEnvironmentBuilder.() -> Unit = {}, applicationEnvironmentBuilder: ApplicationEnvironmentBuilder.() -> Unit = {},
routeUnderTest: Routing.() -> Unit notarizedApplicationConfigOverrides: NotarizedApplication.Config.() -> Unit = {},
contentNegotiation: ContentNegotiationConfig.() -> Unit = {
json(Json {
encodeDefaults = true
explicitNulls = false
serializersModule = KompendiumSerializersModule.module
})
},
serverConfigSetup: ServerConfigBuilder.() -> Unit = { },
routeUnderTest: Route.() -> Unit
) { ) {
openApiTest( openApiTest(
snapshotName, snapshotName,
SupportedSerializer.KOTLINX,
routeUnderTest, routeUnderTest,
applicationSetup, applicationSetup,
specOverrides, specOverrides,
customTypes, customTypes,
applicationEnvironmentBuilder notarizedApplicationConfigOverrides,
) contentNegotiation,
openApiTest( applicationEnvironmentBuilder,
snapshotName, serverConfigSetup
SupportedSerializer.JACKSON,
routeUnderTest,
applicationSetup,
specOverrides,
customTypes,
applicationEnvironmentBuilder
)
openApiTest(
snapshotName,
SupportedSerializer.GSON,
routeUnderTest,
applicationSetup,
specOverrides,
customTypes,
applicationEnvironmentBuilder
) )
} }
private fun openApiTest( private fun openApiTest(
snapshotName: String, snapshotName: String,
serializer: SupportedSerializer, routeUnderTest: Route.() -> Unit,
routeUnderTest: Routing.() -> Unit,
applicationSetup: Application.() -> Unit, applicationSetup: Application.() -> Unit,
specOverrides: OpenApiSpec.() -> OpenApiSpec, specOverrides: OpenApiSpec.() -> OpenApiSpec,
typeOverrides: Map<KType, JsonSchema> = emptyMap(), typeOverrides: Map<KType, JsonSchema> = emptyMap(),
applicationBuilder: ApplicationEngineEnvironmentBuilder.() -> Unit = {} notarizedApplicationConfigOverrides: NotarizedApplication.Config.() -> Unit,
contentNegotiation: ContentNegotiationConfig.() -> Unit,
applicationBuilder: ApplicationEnvironmentBuilder.() -> Unit,
serverConfigSetup: ServerConfigBuilder.() -> Unit
) = testApplication { ) = testApplication {
environment(applicationBuilder) environment(applicationBuilder)
install(NotarizedApplication()) { install(NotarizedApplication()) {
customTypes = typeOverrides customTypes = typeOverrides
spec = defaultSpec().specOverrides() spec = { specOverrides(defaultSpec()) }
schemaConfigurator = when (serializer) { schemaConfigurator = KotlinXSchemaConfigurator()
SupportedSerializer.KOTLINX -> KotlinXSchemaConfigurator() notarizedApplicationConfigOverrides()
SupportedSerializer.GSON -> GsonSchemaConfigurator()
SupportedSerializer.JACKSON -> JacksonSchemaConfigurator()
}
} }
install(ContentNegotiation) { install(ContentNegotiation) {
when (serializer) { contentNegotiation()
SupportedSerializer.KOTLINX -> json(Json {
encodeDefaults = true
explicitNulls = false
serializersModule = KompendiumSerializersModule.module
})
SupportedSerializer.GSON -> gson()
SupportedSerializer.JACKSON -> jackson(ContentType.Application.Json) {
enable(SerializationFeature.INDENT_OUTPUT)
setSerializationInclusion(JsonInclude.Include.NON_NULL)
}
}
} }
application(applicationSetup) application(applicationSetup)
serverConfig(serverConfigSetup)
routing { routing {
swagger() swagger()
redoc() redoc()
routeUnderTest() routeUnderTest()
} }
val root = ApplicationEngineEnvironmentBuilder().apply(applicationBuilder).rootPath
val root = ServerConfigBuilder(ApplicationEnvironmentBuilder().apply(applicationBuilder).build()).apply(serverConfigSetup).rootPath
compareOpenAPISpec(root, snapshotName) compareOpenAPISpec(root, snapshotName)
} }
} }

View File

@ -1,12 +1,10 @@
package io.bkbn.kompendium.core.fixtures package io.bkbn.kompendium.core.fixtures
import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonProperty
import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient import kotlinx.serialization.Transient
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.time.Instant import java.time.Instant
@Serializable @Serializable
@ -25,7 +23,8 @@ data class TestRequest(
@Serializable @Serializable
data class TestSimpleRequest( data class TestSimpleRequest(
val a: String, val a: String,
val b: Int val b: Int,
val c: Boolean
) )
@Serializable @Serializable
@ -91,6 +90,25 @@ data class AnothaJamma(val b: Float) : SlammaJamma
data class InsaneJamma(val c: SlammaJamma) : SlammaJamma data class InsaneJamma(val c: SlammaJamma) : SlammaJamma
sealed interface ChillaxificationMaximization
@Serializable
@SerialName("chillax")
data class Chillax(val a: String) : ChillaxificationMaximization
@Serializable
@SerialName("maximize")
data class ToDaMax(val b: Int) : ChillaxificationMaximization
sealed class Gadget(
open val title: String,
open val description: String
)
class Gizmo(
override val title: String,
) : Gadget(title, "Just a gizmo")
sealed interface Flibbity<T> sealed interface Flibbity<T>
data class Gibbity<T>(val a: T) : Flibbity<T> data class Gibbity<T>(val a: T) : Flibbity<T>
@ -158,9 +176,7 @@ object Nested {
@Serializable @Serializable
data class TransientObject( data class TransientObject(
@field:Expose
val nonTransient: String, val nonTransient: String,
@field:JsonIgnore
@Transient @Transient
val transient: String = "transient" val transient: String = "transient"
) )
@ -174,12 +190,14 @@ data class UnbackedObject(
@Serializable @Serializable
data class SerialNameObject( data class SerialNameObject(
@field:JsonProperty("snake_case_name")
@field:SerializedName("snake_case_name")
@SerialName("snake_case_name") @SerialName("snake_case_name")
val camelCaseName: String val camelCaseName: String
) )
data class GenericObject<T>(
val data: T
)
enum class Color { enum class Color {
RED, RED,
GREEN, GREEN,
@ -190,3 +208,8 @@ enum class Color {
data class ObjectWithEnum( data class ObjectWithEnum(
val color: Color val color: Color
) )
@Serializable
data class SomethingSimilar(val a: String) {
val b = "something else"
}

View File

@ -5,8 +5,8 @@ complexity:
active: true active: true
functionThreshold: 10 functionThreshold: 10
constructorThreshold: 15 constructorThreshold: 15
ComplexMethod: CyclomaticComplexMethod:
threshold: 20 threshold: 15
style: style:
MaxLineLength: MaxLineLength:
excludes: ['**/test/**/*'] excludes: ['**/test/**/*']
@ -22,6 +22,8 @@ formatting:
indentSize: 2 indentSize: 2
ImportOrdering: ImportOrdering:
active: false active: false
EnumEntryNameCase:
active: false
naming: naming:
ConstructorParameterNaming: ConstructorParameterNaming:
active: false active: false

View File

@ -1,13 +1,12 @@
# Summary # Summary
* [Introduction](index.md) * [Introduction](index.md)
* [Helpers](helpers/index.md)
* [Protobuf java converter](helpers/protobuf_java_converter.md)
* [Concepts](concepts/index.md)
* [Enrichment](concepts/enrichment.md)
* [Plugins](plugins/index.md) * [Plugins](plugins/index.md)
* [Notarized Application](plugins/notarized_application.md) * [Notarized Application](plugins/notarized_application.md)
* [Notarized Route](plugins/notarized_route.md) * [Notarized Route](plugins/notarized_route.md)
* [Notarized Locations](plugins/notarized_locations.md)
* [Notarized Resources](plugins/notarized_resources.md) * [Notarized Resources](plugins/notarized_resources.md)
* [Concepts](concepts/index.md)
* [Enrichment](concepts/enrichment.md)
* [Helpers](helpers/index.md)
* [Protobuf java converter](helpers/protobuf_java_converter.md)
* [The Playground](playground.md) * [The Playground](playground.md)

View File

@ -12,7 +12,6 @@ At the moment, the following playground applications are
| Gson | Serialization using Gson instead of the default Kotlinx | | Gson | Serialization using Gson instead of the default Kotlinx |
| Hidden Docs | Place your generated documentation behind authorization | | Hidden Docs | Place your generated documentation behind authorization |
| Jackson | Serialization using Jackson instead of the default KotlinX | | Jackson | Serialization using Jackson instead of the default KotlinX |
| Locations | Using the Ktor Locations API to define routes |
| Resources | Using the Ktor Resources API to define routes | | Resources | Using the Ktor Resources API to define routes |
You can find all of the playground You can find all of the playground

View File

@ -7,5 +7,5 @@ From there, a `NotarizedRoute` plugin is attached to each route you wish to docu
be an iterative process. Each route you notarize will be picked up and injected into the OpenAPI spec that Kompendium be an iterative process. Each route you notarize will be picked up and injected into the OpenAPI spec that Kompendium
generates for you. generates for you.
Finally, there is the `NotarizedLocations` plugin that allows you to leverage and document your usage of the Finally, there is the `NotarizedResources` plugin that allows you to leverage and document your usage of the
Ktor [Locations](https://ktor.io/docs/locations.html) API. Ktor [Resources](https://ktor.io/docs/server-resources.html) API.

View File

@ -1,62 +0,0 @@
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!

View File

@ -3,7 +3,7 @@ plugins {
id("io.bkbn.sourdough.library.jvm") id("io.bkbn.sourdough.library.jvm")
id("io.gitlab.arturbosch.detekt") id("io.gitlab.arturbosch.detekt")
id("com.adarshr.test-logger") id("com.adarshr.test-logger")
id("maven-publish") id("com.vanniktech.maven.publish")
id("java-library") id("java-library")
id("signing") id("signing")
id("org.jetbrains.kotlinx.kover") id("org.jetbrains.kotlinx.kover")

View File

@ -0,0 +1,16 @@
package io.bkbn.kompendium.enrichment
class BooleanEnrichment(override val id: String) : Enrichment {
override var deprecated: Boolean? = null
override var description: String? = null
companion object {
inline operator fun invoke(
id: String,
init: BooleanEnrichment.() -> Unit
): BooleanEnrichment {
val builder = BooleanEnrichment(id)
return builder.apply(init)
}
}
}

View File

@ -0,0 +1,24 @@
package io.bkbn.kompendium.enrichment
class CollectionEnrichment<T>(override val id: String) : TypeEnrichment<T> {
override var deprecated: Boolean? = null
override var description: String? = null
var maxItems: Int? = null
var minItems: Int? = null
var uniqueItems: Boolean? = null
// TODO How to handle contains, minContains, maxContains?
var itemEnrichment: TypeEnrichment<*>? = null
companion object {
inline operator fun <reified T> invoke(
id: String,
init: CollectionEnrichment<T>.() -> Unit
): CollectionEnrichment<T> {
val builder = CollectionEnrichment<T>(id)
return builder.apply(init)
}
}
}

View File

@ -1,3 +1,7 @@
package io.bkbn.kompendium.enrichment package io.bkbn.kompendium.enrichment
sealed interface Enrichment sealed interface Enrichment {
val id: String
var deprecated: Boolean?
var description: String?
}

View File

@ -0,0 +1,23 @@
package io.bkbn.kompendium.enrichment
class MapEnrichment<V>(override val id: String) : TypeEnrichment<V> {
override var deprecated: Boolean? = null
override var description: String? = null
var maxProperties: Int? = null
var minProperties: Int? = null
lateinit var keyEnrichment: StringEnrichment
lateinit var valueEnrichment: TypeEnrichment<*>
companion object {
inline operator fun <reified V> invoke(
id: String,
init: MapEnrichment<V>.() -> Unit
): MapEnrichment<V> {
val builder = MapEnrichment<V>(id)
return builder.apply(init)
}
}
}

View File

@ -0,0 +1,19 @@
package io.bkbn.kompendium.enrichment
class NumberEnrichment(override val id: String) : Enrichment {
override var deprecated: Boolean? = null
override var description: String? = null
var multipleOf: Number? = null
var maximum: Number? = null
var exclusiveMaximum: Number? = null
var minimum: Number? = null
var exclusiveMinimum: Number? = null
companion object {
inline operator fun invoke(id: String, init: NumberEnrichment.() -> Unit): NumberEnrichment {
val builder = NumberEnrichment(id)
return builder.apply(init)
}
}
}

View File

@ -0,0 +1,27 @@
package io.bkbn.kompendium.enrichment
import kotlin.reflect.KProperty1
class ObjectEnrichment<T>(override val id: String) : TypeEnrichment<T> {
override var deprecated: Boolean? = null
override var description: String? = null
private val _propertyEnrichments: MutableMap<KProperty1<*, *>, Enrichment> = mutableMapOf()
val propertyEnrichment: Map<KProperty1<*, *>, Enrichment>
get() = _propertyEnrichments.toMap()
operator fun <R> KProperty1<T, R>.invoke(init: () -> Enrichment) {
require(!_propertyEnrichments.containsKey(this)) { "${this.name} has already been registered" }
val enrichment = init.invoke()
_propertyEnrichments[this] = enrichment
}
companion object {
inline operator fun <reified T> invoke(id: String, init: ObjectEnrichment<T>.() -> Unit): ObjectEnrichment<T> {
val builder = ObjectEnrichment<T>(id)
return builder.apply(init)
}
}
}

View File

@ -1,36 +0,0 @@
package io.bkbn.kompendium.enrichment
/**
* Reference https://json-schema.org/draft/2020-12/json-schema-validation.html#name-multipleof
*/
class PropertyEnrichment : Enrichment {
// Metadata
var deprecated: Boolean? = null
var description: String? = null
var typeEnrichment: TypeEnrichment<*>? = null
// Number and Integer Constraints
var multipleOf: Number? = null
var maximum: Number? = null
var exclusiveMaximum: Number? = null
var minimum: Number? = null
var exclusiveMinimum: Number? = null
// String constraints
var maxLength: Int? = null
var minLength: Int? = null
var pattern: String? = null
var contentEncoding: String? = null
var contentMediaType: String? = null
// TODO how to handle contentSchema?
// Array constraints
var maxItems: Int? = null
var minItems: Int? = null
var uniqueItems: Boolean? = null
// TODO How to handle contains, minContains, maxContains?
// Object constraints
var maxProperties: Int? = null
var minProperties: Int? = null
}

Some files were not shown because too many files have changed in this diff Show More