From d271a2db3d5280208fbe9768388b25904cf991ec Mon Sep 17 00:00:00 2001 From: Era Dorta Date: Mon, 2 Mar 2026 00:26:18 +0100 Subject: [PATCH] Add OpenAPIDocs --- README.md | 13 +++++ build.gradle.kts | 9 ++++ gradle/libs.versions.toml | 4 ++ .../signal/json/JsonOpenApiController.java | 21 ++++++++ .../asamk/signal/json/JsonSchemaCatalog.java | 53 +++++++++++++++++++ .../OpenApiDocumentationApplication.java | 26 +++++++++ 6 files changed, 126 insertions(+) create mode 100644 src/main/java/org/asamk/signal/json/JsonOpenApiController.java create mode 100644 src/main/java/org/asamk/signal/json/JsonSchemaCatalog.java create mode 100644 src/main/java/org/asamk/signal/openapi/OpenApiDocumentationApplication.java diff --git a/README.md b/README.md index 1d192bb3..43387d1d 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,19 @@ version installed, you can replace `./gradlew` with `gradle` in the following st ./gradlew run --args="--help" ``` +### Documentation + +1. Run OpenAPI documentation server for JSON models (`src/main/java/org/asamk/signal/json`): + + ```sh + ./gradlew openApiDocs + ``` + +2. Open: + + - `http://localhost:8080/swagger-ui/index.html` (Swagger UI) + - `http://localhost:8080/v3/api-docs/json-models` (OpenAPI JSON) + ### Building a native binary with GraalVM (EXPERIMENTAL) It is possible to build a native binary with [GraalVM](https://www.graalvm.org). This is still experimental and will not diff --git a/build.gradle.kts b/build.gradle.kts index d8e36ea4..09d6f597 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -90,6 +90,8 @@ dependencies { implementation(libs.slf4j.jul) implementation(libs.logback) implementation(libs.zxing) + implementation(libs.spring.boot.starter.web) + implementation(libs.springdoc.openapi.starter.webmvc.ui) implementation(project(":libsignal-cli")) } @@ -138,3 +140,10 @@ tasks.register("fatJar", type = Jar::class) { } with(tasks.jar.get()) } + +tasks.register("openApiDocs") { + group = "application" + description = "Run OpenAPI documentation server for JSON models" + classpath = sourceSets["main"].runtimeClasspath + mainClass.set("org.asamk.signal.openapi.OpenApiDocumentationApplication") +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3df9835e..cb99bbc8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,8 @@ [versions] slf4j = "2.0.17" junit = "6.0.2" +spring-boot = "3.5.0" +springdoc = "2.8.13" [libraries] bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.83" @@ -8,6 +10,8 @@ jackson-databind = "com.fasterxml.jackson.core:jackson-databind:2.20.2" argparse4j = "net.sourceforge.argparse4j:argparse4j:0.9.0" dbusjava = "com.github.hypfvieh:dbus-java-transport-native-unixsocket:5.0.0" zxing = "com.google.zxing:core:3.5.4" +spring-boot-starter-web = { module = "org.springframework.boot:spring-boot-starter-web", version.ref = "spring-boot" } +springdoc-openapi-starter-webmvc-ui = { module = "org.springdoc:springdoc-openapi-starter-webmvc-ui", version.ref = "springdoc" } slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } slf4j-jul = { module = "org.slf4j:jul-to-slf4j", version.ref = "slf4j" } logback = "ch.qos.logback:logback-classic:1.5.32" diff --git a/src/main/java/org/asamk/signal/json/JsonOpenApiController.java b/src/main/java/org/asamk/signal/json/JsonOpenApiController.java new file mode 100644 index 00000000..9b8a6565 --- /dev/null +++ b/src/main/java/org/asamk/signal/json/JsonOpenApiController.java @@ -0,0 +1,21 @@ +package org.asamk.signal.json; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/openapi/json") +class JsonOpenApiController { + + @GetMapping("/models") + @Operation(summary = "Signal JSON model schema catalog") + @ApiResponse(responseCode = "200", description = "Catalog of Signal JSON model schemas", content = @Content(mediaType = "application/json", schema = @Schema(implementation = JsonSchemaCatalog.class))) + JsonSchemaCatalog getModels() { + return new JsonSchemaCatalog(); + } +} diff --git a/src/main/java/org/asamk/signal/json/JsonSchemaCatalog.java b/src/main/java/org/asamk/signal/json/JsonSchemaCatalog.java new file mode 100644 index 00000000..1ff4d141 --- /dev/null +++ b/src/main/java/org/asamk/signal/json/JsonSchemaCatalog.java @@ -0,0 +1,53 @@ +package org.asamk.signal.json; + +import java.util.List; + +public class JsonSchemaCatalog { + + public JsonAdminDelete adminDelete; + public JsonAttachment attachment; + public JsonAttachmentData attachmentData; + public JsonCallMessage callMessage; + public JsonContact contact; + public JsonContactAddress contactAddress; + public JsonContactAvatar contactAvatar; + public JsonContactEmail contactEmail; + public JsonContactName contactName; + public JsonContactPhone contactPhone; + public JsonDataMessage dataMessage; + public JsonEditMessage editMessage; + public JsonError error; + public JsonGroupInfo groupInfo; + public JsonMention mention; + public JsonMessageEnvelope messageEnvelope; + public JsonPayment payment; + public JsonPinMessage pinMessage; + public JsonPollCreate pollCreate; + public JsonPollTerminate pollTerminate; + public JsonPollVote pollVote; + public JsonPreview preview; + public JsonQuote quote; + public JsonQuotedAttachment quotedAttachment; + public JsonReaction reaction; + public JsonReceiptMessage receiptMessage; + public JsonRecipientAddress recipientAddress; + public JsonRemoteDelete remoteDelete; + public JsonSendMessageResult sendMessageResult; + public JsonSharedContact sharedContact; + public JsonSticker sticker; + public JsonStoryContext storyContext; + public JsonStoryMessage storyMessage; + public JsonSyncDataMessage syncDataMessage; + public JsonSyncMessage syncMessage; + public JsonSyncReadMessage syncReadMessage; + public JsonSyncStoryMessage syncStoryMessage; + public JsonTextStyle textStyle; + public JsonTypingMessage typingMessage; + public JsonUnpinMessage unpinMessage; + + public List attachments; + public List mentions; + public List previews; + public List contacts; + public List textStyles; +} diff --git a/src/main/java/org/asamk/signal/openapi/OpenApiDocumentationApplication.java b/src/main/java/org/asamk/signal/openapi/OpenApiDocumentationApplication.java new file mode 100644 index 00000000..74dfb164 --- /dev/null +++ b/src/main/java/org/asamk/signal/openapi/OpenApiDocumentationApplication.java @@ -0,0 +1,26 @@ +package org.asamk.signal.openapi; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Info; +import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication(scanBasePackages = "org.asamk.signal") +@OpenAPIDefinition(info = @Info(title = "signal-cli JSON Models", version = "v1")) +public class OpenApiDocumentationApplication { + + public static void main(String[] args) { + SpringApplication.run(OpenApiDocumentationApplication.class, args); + } + + @Bean + GroupedOpenApi jsonModelsOpenApi() { + return GroupedOpenApi.builder() + .group("json-models") + .packagesToScan("org.asamk.signal.json") + .pathsToMatch("/openapi/json/models") + .build(); + } +}