Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for OAS v3.1 webhooks #2657

Closed
skborissov opened this issue Jul 25, 2024 · 2 comments
Closed

Add support for OAS v3.1 webhooks #2657

skborissov opened this issue Jul 25, 2024 · 2 comments

Comments

@skborissov
Copy link

Is your feature request related to a problem? Please describe.

OAS v3.1 introduced webhooks. I would like for Springdoc to support their generation. This was previously asked about in #2555, but that issue was closed for some reason.

@mzealey
Copy link

mzealey commented Sep 18, 2024

Yes really useful for us also. Or at least the ability to add whatever custom openapi information we would like via the annotation interface.

@mzealey
Copy link

mzealey commented Sep 20, 2024

So we have managed to make webhooks in 1.8.0:

import io.swagger.v3.oas.annotations.Webhook;
import io.swagger.v3.oas.annotations.Webhooks;

@Webhooks({
    @Webhook(
        name="Message Received",
        operation = @Operation(
            summary = "Message Received",
            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
                content = @Content(
                    schema = @Schema(implementation = MessageEvent.class)
                )
            ),
            method = "POST",
            responses = {
                @ApiResponse(
                    responseCode = "200",
                    description = "Event received"
                )
            },
            description=...

Set

springdoc.api-docs.version=OPENAPI_3_1

and then the magic by @Taetse to make this automatically discovered and added:

import io.swagger.v3.oas.annotations.Webhook;
import io.swagger.v3.oas.annotations.Webhooks;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;

/*
 * A custom configuration/openapi required in order to add in webhooks to the
 * documentation - for some reason the springdoc ui 1.8.0 does not find these
 * automatically even though the underlying openapi-core does support the
 * annotations correctly.
 */
@Configuration
public class SpringDocConfig {

    private final ApplicationContext applicationContext;

    public SpringDocConfig(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Bean
    public OpenAPI customOpenAPI() {
        OpenAPI openAPI = new OpenAPI();

        var restControllers = applicationContext.getBeansWithAnnotation(Webhooks.class);

        restControllers.values().forEach(controller -> {
            var webhooksAttr = controller.getClass().getAnnotationsByType(Webhooks.class);
            var webhooks = Arrays.stream(webhooksAttr).map(Webhooks::value).flatMap(Arrays::stream).toArray(Webhook[]::new);

            Arrays.stream(webhooks).forEach(webhook -> {
                var apiResponses = new ApiResponses();
                for (var response : webhook.operation().responses()) {
                    apiResponses.addApiResponse(response.responseCode(), new ApiResponse().description(response.description()));
                }

                Operation operation = new Operation()
                        .summary(webhook.operation().summary())
                        .description(webhook.operation().description())
                        .requestBody(new RequestBody().content(convertContent(webhook.operation().requestBody().content())))
                        .responses(apiResponses);

                PathItem pathItem = new PathItem().post(operation);
                openAPI.addWebhooks(webhook.name(), pathItem);
            });
        });

        return openAPI;
    }

    private Content convertContent(io.swagger.v3.oas.annotations.media.Content[] annotationContent) {
        Content content = new Content();
        for (var annotation : annotationContent) {
            MediaType mediaType = new MediaType();
            mediaType.setSchema(new Schema<>().$ref(annotation.schema().implementation().getName()));
            content.addMediaType(annotation.mediaType(), mediaType);
        }
        return content;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants