From c134980d34cd1677bb93b88d985f75a085b354f6 Mon Sep 17 00:00:00 2001 From: slinkydeveloper Date: Tue, 14 Nov 2023 11:19:30 +0100 Subject: [PATCH] Generate admin client --- admin-client/build.gradle.kts | 70 +++++++++++++++++++++++++ admin-client/src/main/openapi/meta.json | 1 + settings.gradle.kts | 5 +- 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 admin-client/build.gradle.kts create mode 100644 admin-client/src/main/openapi/meta.json diff --git a/admin-client/build.gradle.kts b/admin-client/build.gradle.kts new file mode 100644 index 00000000..1d048c77 --- /dev/null +++ b/admin-client/build.gradle.kts @@ -0,0 +1,70 @@ +import net.ltgt.gradle.errorprone.errorprone +import org.openapitools.generator.gradle.plugin.tasks.GenerateTask + +plugins { + `java-library` + `maven-publish` + id("org.openapi.generator") version "6.6.0" +} + +dependencies { + implementation(platform(jacksonLibs.jackson.bom)) + implementation(jacksonLibs.jackson.core) + implementation(jacksonLibs.jackson.databind) + implementation(jacksonLibs.jackson.jsr310) + implementation("org.openapitools:jackson-databind-nullable:0.2.6") + + // Required for the annotations + compileOnly(coreLibs.javax.annotation.api) + compileOnly("com.google.code.findbugs:jsr305:3.0.2") +} + +// Add generated output to source sets +sourceSets { main { java.srcDir("$buildDir/generate-resources/main/src/main/java") } } + +// Configure openapi generator +tasks.withType { + inputSpec.set("$projectDir/src/main/openapi/meta.json") + + // Java 9+ HTTP Client using Jackson + generatorName.set("java") + library.set("native") + + // Package names + invokerPackage.set("dev.restate.admin.client") + apiPackage.set("dev.restate.admin.api") + modelPackage.set("dev.restate.admin.model") + + // We don't need these + generateApiTests.set(false) + generateApiDocumentation.set(false) + generateModelTests.set(false) + generateModelDocumentation.set(false) + + finalizedBy("spotlessJava") +} + +tasks.withType().configureEach { + dependsOn("openApiGenerate") + + targetCompatibility = "11" + sourceCompatibility = "11" + + // Disable errorprone for this module + options.errorprone.disableAllChecks.set(true) +} + +configure { + java { targetExclude(fileTree("$buildDir/generate-resources") { include("**/*.java") }) } +} + +publishing { + publications { + register("maven") { + groupId = "dev.restate.sdk" + artifactId = "admin-client" + + from(components["java"]) + } + } +} diff --git a/admin-client/src/main/openapi/meta.json b/admin-client/src/main/openapi/meta.json new file mode 100644 index 00000000..3c1cbaeb --- /dev/null +++ b/admin-client/src/main/openapi/meta.json @@ -0,0 +1 @@ +{"openapi":"3.0.0","info":{"title":"Admin API","version":"0.2.2"},"paths":{"/subscriptions":{"post":{"tags":["subscription"],"summary":"Create subscription","description":"Create subscription.","operationId":"create_subscription","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSubscriptionRequest"}}},"required":true},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"}}}},"400":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"403":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"404":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"409":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"500":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"503":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}}}}},"/health":{"get":{"tags":["health"],"summary":"Health check","description":"Check REST API Health.","operationId":"health","responses":{"200":{"description":"OK"}}}},"/services/{service}/methods/{method}":{"get":{"tags":["service_method"],"summary":"Get service method","description":"Get the method of a service","operationId":"get_service_method","parameters":[{"name":"service","in":"path","description":"Fully qualified service name.","required":true,"schema":{"type":"string"}},{"name":"method","in":"path","description":"Method name.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetServiceMethodResponse"}}}},"400":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"403":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"404":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"409":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"500":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"503":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}}}}},"/services/{service}":{"patch":{"tags":["service"],"summary":"Modify a service","description":"Modify a registered service.","operationId":"modify_service","parameters":[{"name":"service","in":"path","description":"Fully qualified service name.","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModifyServiceRequest"}}},"required":true},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServiceMetadata"}}}},"400":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"403":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"404":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"409":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"500":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"503":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}}}}},"/subscriptions/{subscription}":{"delete":{"tags":["subscription"],"summary":"Delete subscription","description":"Delete subscription.","operationId":"delete_subscription","parameters":[{"name":"subscription","in":"path","description":"Subscription identifier","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Accepted"},"400":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"403":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"404":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"409":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"500":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"503":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}}}}},"/openapi":{"get":{"tags":["openapi"],"summary":"OpenAPI specification","externalDocs":{"url":"https://swagger.io/specification/"},"operationId":"openapi_spec","responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/endpoints":{"post":{"tags":["service_endpoint"],"summary":"Create service endpoint","description":"Create service endpoint. Restate will invoke the endpoint to gather additional information required for registration, such as the services exposed by the service endpoint and their Protobuf descriptor. If the service endpoint is already registered, this method will fail unless `force` is set to `true`.","operationId":"create_service_endpoint","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterServiceEndpointRequest"}}},"required":true},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterServiceEndpointResponse"}}}},"400":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"403":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"404":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"409":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"500":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"503":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}}}}},"/services":{"get":{"tags":["service"],"summary":"List services","description":"List all registered services.","operationId":"list_services","responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListServicesResponse"}}}},"400":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"403":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"404":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"409":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"500":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"503":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}}}}},"/services/{service}/methods":{"get":{"tags":["service_method"],"summary":"List service methods","description":"List all the methods of the given service.","operationId":"list_service_methods","parameters":[{"name":"service","in":"path","description":"Fully qualified service name.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListServiceMethodsResponse"}}}},"400":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"403":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"404":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"409":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"500":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"503":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}}}}},"/endpoints/{endpoint}":{"delete":{"tags":["service_endpoint"],"summary":"Delete service endpoint","description":"Delete service endpoint. Currently it's supported to remove a service endpoint only using the force flag","operationId":"delete_service_endpoint","parameters":[{"name":"endpoint","in":"path","description":"Endpoint identifier","required":true,"schema":{"type":"string"}},{"name":"force","in":"query","description":"If true, the service endpoint will be forcefully deleted. This might break in-flight invocations, use with caution.","style":"simple","schema":{"type":"boolean"}}],"responses":{"202":{"description":"Accepted"},"501":{"description":"Not implemented. Only using the force flag is supported at the moment."},"400":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"403":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"404":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"409":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"500":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"503":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}}}}},"/invocations/{invocation_id}":{"delete":{"tags":["invocation"],"summary":"Kill an invocation","description":"Kill the given invocation. When killing, consistency is not guaranteed for service instance state, in-flight invocation to other services, etc. Future releases will support graceful invocation cancellation.","operationId":"cancel_invocation","parameters":[{"name":"invocation_id","in":"path","description":"Invocation identifier.","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":""},"400":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"403":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"404":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"409":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"500":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}},"503":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorDescriptionResponse"}}}}}}}},"components":{"schemas":{"CreateSubscriptionRequest":{"type":"object","required":["sink","source"],"properties":{"id":{"title":"Identifier","description":"Identifier of the subscription. If not specified, one will be auto-generated.","type":"string","nullable":true},"source":{"title":"Source","description":"Source uri. Accepted forms:\n\n* `kafka:///`, e.g. `service://my-cluster/my-topic`","type":"string"},"sink":{"title":"Sink","description":"Sink uri. Accepted forms:\n\n* `service:///`, e.g. `service://com.example.MySvc/MyMethod`","type":"string"},"options":{"title":"Options","description":"Additional options to apply to the subscription.","type":"object","additionalProperties":{"type":"string"},"nullable":true}}},"SubscriptionResponse":{"type":"object","required":["id","options","sink","source"],"properties":{"id":{"type":"string"},"source":{"type":"string"},"sink":{"type":"string"},"options":{"type":"object","additionalProperties":{"type":"string"}}}},"ErrorDescriptionResponse":{"title":"Error description response","description":"Error details of the response","type":"object","required":["message"],"properties":{"message":{"type":"string"},"restate_code":{"title":"Restate code","description":"Restate error code describing this error","type":"string","nullable":true}}},"GetServiceMethodResponse":{"type":"object","required":["method_name","service_name"],"properties":{"service_name":{"type":"string"},"method_name":{"type":"string"}}},"ModifyServiceRequest":{"type":"object","required":["public"],"properties":{"public":{"title":"Public","description":"If true, the service can be invoked through the ingress. If false, the service can be invoked only from another Restate service.","type":"boolean"}}},"ServiceMetadata":{"type":"object","required":["endpoint_id","instance_type","methods","name","public","revision"],"properties":{"name":{"type":"string"},"methods":{"type":"array","items":{"type":"string"}},"instance_type":{"$ref":"#/components/schemas/InstanceType"},"endpoint_id":{"title":"Endpoint Id","description":"Endpoint exposing the latest revision of the service.","type":"string"},"revision":{"title":"Revision","description":"Latest revision of the service.","type":"integer","format":"uint32","minimum":0.0},"public":{"title":"Public","description":"If true, the service can be invoked through the ingress. If false, the service can be invoked only from another Restate service.","type":"boolean"}}},"InstanceType":{"type":"string","enum":["Keyed","Unkeyed","Singleton"]},"RegisterServiceEndpointRequest":{"type":"object","required":["uri"],"properties":{"uri":{"title":"Uri","description":"Uri to use to discover/invoke the service endpoint.","type":"string"},"additional_headers":{"title":"Additional headers","description":"Additional headers added to the discover/invoke requests to the service endpoint.","type":"object","additionalProperties":{"type":"string"},"nullable":true},"force":{"title":"Force","description":"If `true`, it will override, if existing, any endpoint using the same `uri`. Beware that this can lead in-flight invocations to an unrecoverable error state.\n\nBy default, this is `true` but it might change in future to `false`.\n\nSee the [versioning documentation](https://docs.restate.dev/services/upgrades-removal) for more information.","default":true,"type":"boolean"}}},"RegisterServiceEndpointResponse":{"type":"object","required":["id","services"],"properties":{"id":{"type":"string"},"services":{"type":"array","items":{"$ref":"#/components/schemas/RegisterServiceResponse"}}}},"RegisterServiceResponse":{"type":"object","required":["name","revision"],"properties":{"name":{"type":"string"},"revision":{"type":"integer","format":"uint32","minimum":0.0}}},"ListServicesResponse":{"type":"object","required":["services"],"properties":{"services":{"type":"array","items":{"$ref":"#/components/schemas/ServiceMetadata"}}}},"ListServiceMethodsResponse":{"type":"object","required":["methods"],"properties":{"methods":{"type":"array","items":{"type":"string"}}}}}}} diff --git a/settings.gradle.kts b/settings.gradle.kts index a6497dc1..191abb7e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,7 +18,8 @@ include( "protoc-gen-restate-java-blocking", "sdk-lambda", "sdk-kotlin", - "examples") + "examples", + "admin-client") dependencyResolutionManagement { repositories { mavenCentral() } @@ -72,6 +73,8 @@ dependencyResolutionManagement { library("jackson-core", "com.fasterxml.jackson.core", "jackson-core").withoutVersion() library("jackson-databind", "com.fasterxml.jackson.core", "jackson-databind") .versionRef("jackson") + library("jackson-jsr310", "com.fasterxml.jackson.datatype", "jackson-datatype-jsr310") + .withoutVersion() } create("kotlinLibs") { library("kotlinx-coroutines", "org.jetbrains.kotlinx", "kotlinx-coroutines-core")