Skip to content

Missing Request Body for Write Operation Actuator Endpoints #1565

Closed

Description

@mathieu-amblard

Describe the bug
After adding springdoc.show-actuator=true, I can see all the actuator endpoints 👍 but I cannot see the Request Body field for the @WriteOperation endpoints (for example https://github.com/spring-projects/spring-boot/blob/47516b50c39bd6ea924a1f6720ce6d4a71088651/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/logging/LoggersEndpoint.java#L99).
In the following class it seems that only parameters are managed :

public class ActuatorOpenApiCustomizer implements OpenApiCustomiser {

To Reproduce
Steps to reproduce the behavior:

  • What version of spring-boot you are using? Tried with 2.5.10 and 2.6.4
  • What modules and versions of springdoc-openapi are you using? Tried with 1.6.2 and 1.6.6
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-webmvc-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-ui</artifactId>
        </dependency>
  • What is the actual and the expected result using OpenAPI Description (yml or json)?
"post": {
    "tags": ["Actuator"],
    "summary": "Actuator web endpoint 'loggers-name'",
    "operationId": "loggers-name_7",
    "parameters": [{
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
                "type": "string"
            }
        }
    ],
    "responses": {...},
}

Expected behavior

  • A clear and concise description of what you expected to happen.
    We expect to have the Request Body field in case of @WriteOperation if it is possible as there is not @RequestBody annotation.
  • What is the expected result using OpenAPI Description (yml or json)?
    Something like this for the LoggersEndpoint :
"post": {
    "tags": ["Actuator"],
    "summary": "Actuator web endpoint 'loggers-name'",
    "operationId": "loggers-name_7",
    "parameters": [{
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
                "type": "string"
            }
        }
    ],
    "requestBody": {
        "content": {
            "application/json": {
                "schema": {
                    "type": "object",
                    "properties": {
                        "configuredLevel": {
                            "type": "string",
                            "required": true
                        }
                    }
                }
            }
        },
        "required": true
    },
    "responses": {...},
}

Activity

  1. bnasslahsen commented on Mar 21, 2022

    @bnasslahsen
    Collaborator

    @mathieu-amblard,

    I have added a fix, to handle this case out of the box.
    Feel free to test with the latest SNAPSHOT and provide your feedback.

  2. added a commit that references this issue on Mar 21, 2022
    495e88f
  3. mathieu-amblard commented on Mar 23, 2022

    @mathieu-amblard
    ContributorAuthor

    I works well, thank you for the fix and for your reactivity 👍

  4. added a commit that references this issue on Mar 12, 2024
    6ce3b5a
  5. added a commit that references this issue on May 17, 2025
    d061b3a
  6. ajs139 commented on Oct 22, 2025

    @ajs139

    The fix generates:

           "requestBody": {
              "content": {
                "application/json": {
                  "schema": {
                    "type": "string",
                    "enum": [
                      "TRACE",
                      "DEBUG",
                      "INFO",
                      "WARN",
                      "ERROR",
                      "FATAL",
                      "OFF"
                    ]
                  }
                }
              }
            },

    However, the request body should be an object type with a configuredLevel property.

  7. jorgerod commented on Nov 26, 2025

    @jorgerod

    Hi @bnasslahsen @ajs139

    I'm experiencing the same issue described here, even though the issue was marked as closed.

    Context

    I'm using a custom actuator endpoint from the Resilience4j library (version 2.3.0), specifically the CircuitBreakerEndpoint class. This is a third-party library endpoint that we cannot modify - it comes from the io.github.resilience4j:resilience4j-spring-boot3 dependency.

    The Problem

    When using @Endpoint with @WriteOperation annotations (Spring Boot Actuator's standard approach), the enum parameter UpdateState is not rendered correctly in Swagger UI. The parameter appears but doesn't show the available enum values properly.

    Problematic code (from resilience4j library - we cannot modify this):

    /*
     * Copyright 2017 Robert Winkler
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *        http://www.apache.org/licenses/LICENSE-2.0
     */
    package io.github.resilience4j.circuitbreaker.monitoring.endpoint;
    
    import io.github.resilience4j.circuitbreaker.CircuitBreaker;
    import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
    import io.github.resilience4j.common.circuitbreaker.monitoring.endpoint.CircuitBreakerUpdateStateResponse;
    import io.github.resilience4j.common.circuitbreaker.monitoring.endpoint.UpdateState;
    import io.swagger.v3.oas.annotations.Parameter;
    import io.swagger.v3.oas.annotations.enums.ParameterIn;
    import io.swagger.v3.oas.annotations.media.Schema;
    import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
    import org.springframework.boot.actuate.endpoint.annotation.Selector;
    import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
    
    import java.util.Arrays;
    
    @Endpoint(id = "circuitbreakers")
    public class CircuitBreakerEndpoint {
    
        private final CircuitBreakerRegistry circuitBreakerRegistry;
    
        public CircuitBreakerEndpoint(CircuitBreakerRegistry circuitBreakerRegistry) {
            this.circuitBreakerRegistry = circuitBreakerRegistry;
        }
    
        @WriteOperation
        public CircuitBreakerUpdateStateResponse updateCircuitBreakerState(
                @Selector String name,  UpdateState updateState) {
            final CircuitBreaker circuitBreaker = this.circuitBreakerRegistry.circuitBreaker(name);
            final String message = "%s state has been changed successfully";
            switch (updateState) {
                case CLOSE:
                    circuitBreaker.transitionToClosedState();
                    return this.createCircuitBreakerUpdateStateResponse(name, 
                        circuitBreaker.getState().toString(), String.format(message, name));
                case FORCE_OPEN:
                    circuitBreaker.transitionToForcedOpenState();
                    return this.createCircuitBreakerUpdateStateResponse(name, 
                        circuitBreaker.getState().toString(), String.format(message, name));
                case DISABLE:
                    circuitBreaker.transitionToDisabledState();
                    return this.createCircuitBreakerUpdateStateResponse(name, 
                        circuitBreaker.getState().toString(), String.format(message, name));
                default:
                    return this.createCircuitBreakerUpdateStateResponse(name, 
                        circuitBreaker.getState().toString(),
                        "State change value is not supported please use only " + 
                        Arrays.toString(UpdateState.values()));
            }
        }
    
        private CircuitBreakerUpdateStateResponse createCircuitBreakerUpdateStateResponse(
                String circuitBreakerName, String newState, String message) {
            final CircuitBreakerUpdateStateResponse response = new CircuitBreakerUpdateStateResponse();
            response.setCircuitBreakerName(circuitBreakerName);
            response.setCurrentState(newState);
            response.setMessage(message);
            return response;
        }
    }

    The UpdateState enum parameter doesn't display correctly in Swagger UI despite the @Parameter annotation with @Schema configuration.

    Why @RestControllerEndpoint is NOT a solution for us

    I've seen suggestions to use @RestControllerEndpoint instead of @Endpoint, and I can confirm that approach works. However, this is not a viable solution in our case because:

    1. We cannot modify the resilience4j library code - this endpoint comes from an external dependency
    2. We would need to create custom wrapper classes for every actuator endpoint from third-party libraries that has enum parameters
    3. This defeats the purpose of using the library's built-in endpoints and creates maintenance overhead

    For reference, here's what a @RestControllerEndpoint implementation looks like (which DOES work, but we cannot use it because we can't modify the library):

    @RestControllerEndpoint(id = "circuitbreakers")
    public class CircuitBreakerEndpoint {
        // ...
        @PostMapping("/updateState")
        public CircuitBreakerUpdateStateResponse updateCircuitBreakerState(
                @Selector String name, 
                UpdateState updateState) {
            // ... implementation
        }
    }

    Environment Details

    • Spring Boot: 3.5.8
    • springdoc-openapi-starter-webmvc-ui: 2.8.14
    • resilience4j-spring-boot3: 2.3.0
    • Java: 21

    Question

    Is there a way to make @Endpoint + @WriteOperation work correctly with enum parameters in Swagger UI without having to wrap or recreate third-party library endpoints?

    The current situation forces us to either:

    1. Accept broken Swagger UI documentation for these endpoints, or
    2. Create and maintain custom wrappers for all third-party actuator endpoints with enum parameters

    Neither option is ideal. Is there a configuration or workaround that would allow springdoc-openapi to properly introspect enum parameters in @Endpoint + @WriteOperation methods from third-party libraries?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions