How to Enable or Disable Specific API Endpoints Programmatically in Stirling-PDF

Stirling-PDF provides the EndpointConfiguration bean to toggle REST endpoints at runtime; autowire this service and call enableEndpoint() or disableEndpoint() to control availability instantly, while the EndpointInterceptor automatically enforces these states with 403 Forbidden responses.

Stirling-PDF exposes dozens of PDF manipulation capabilities through REST APIs, but not every deployment requires every feature. The application provides a robust mechanism to enable or disable specific API endpoints programmatically without restarting the server, managed through the EndpointConfiguration service in the Stirling-Tools/Stirling-PDF repository.

Understanding the Endpoint Control Architecture

The endpoint governance system relies on two core components working together. The EndpointConfiguration bean maintains an internal map of enabled and disabled endpoints, while the EndpointInterceptor enforces these decisions at the request level.

The EndpointConfiguration Service

Located in app/common/src/main/java/stirling/software/SPDF/config/EndpointConfiguration.java, this Spring service reads application YAML, environment variables, and runtime functional groups (such as "OpenCV" or "Python") during startup. It exposes public methods to manipulate endpoint states:

  • enableEndpoint(String endpoint): Forces the specified endpoint to be enabled, overriding any previous disable flag.
  • disableEndpoint(String endpoint): Disables the endpoint with a generic CONFIG reason.
  • disableEndpoint(String endpoint, DisableReason reason): Disables the endpoint with a specific reason (CONFIG, DEPENDENCY, or UNKNOWN) useful for logging and diagnostics.
  • isEndpointEnabled(String endpoint): Returns the current status of the endpoint, used by the interceptor and public controllers.

The DisableReason enum helps identify why an endpoint is unavailable, appearing in logs when the interceptor blocks requests.

Request Interception and Enforcement

The EndpointInterceptor in app/core/src/main/java/stirling/software/SPDF/config/EndpointInterceptor.java intercepts every incoming HTTP request. It extracts the request path, queries endpointConfiguration.isEndpointEnabled(path), and returns 403 Forbidden with the message "Endpoint disabled" if the endpoint is inactive.

Programmatically Toggling Endpoints

Because EndpointConfiguration is a standard Spring bean, any component can inject it to modify endpoint availability at runtime. This enables dynamic feature flags, dependency-based disabling, and automated testing scenarios.

Enabling and Disabling Individual Endpoints

Inject the configuration bean into your service to toggle specific paths:

@Service
public class RuntimeEndpointManager {

    private final EndpointConfiguration endpointConfig;

    public RuntimeEndpointManager(EndpointConfiguration endpointConfig) {
        this.endpointConfig = endpointConfig;
    }

    /** Disable the PDF conversion endpoint because an external library is missing */
    public void disablePdfConversion() {
        endpointConfig.disableEndpoint("/api/v1/convert/pdf",
                EndpointConfiguration.DisableReason.DEPENDENCY);
    }

    /** Re‑enable it after the dependency is restored */
    public void enablePdfConversion() {
        endpointConfig.enableEndpoint("/api/v1/convert/pdf");
    }

    /** Query current status */
    public boolean isPdfConversionActive() {
        return endpointConfig.isEndpointEnabled("/api/v1/convert/pdf");
    }
}

The methods directly manipulate the internal map that the interceptor checks on every request.

Controlling Endpoint Groups

Endpoints belong to functional groups defined in ExternalAppDepConfig (e.g., all OpenCV-dependent operations). You can disable entire groups when dependencies are missing:

@Service
public class GroupToggleService {

    private final EndpointConfiguration cfg;

    public GroupToggleService(EndpointConfiguration cfg) {
        this.cfg = cfg;
    }

    public void disableOpenCvGroup() {
        // All endpoints that belong to the "OpenCV" group are stored in endpointGroups map
        cfg.getEndpointGroups().getOrDefault("OpenCV", Set.of())
           .forEach(ep -> cfg.disableEndpoint(ep, EndpointConfiguration.DisableReason.DEPENDENCY));
    }

    public void enableOpenCvGroup() {
        cfg.getEndpointGroups().getOrDefault("OpenCV", Set.of())
           .forEach(cfg::enableEndpoint);
    }
}

The getEndpointGroups() method is exposed via Lombok @Getter, returning a map of group names to endpoint sets.

Querying Status via REST

If you prefer HTTP-based inspection over direct bean injection, the ConfigController exposes a public endpoint:

GET /api/v1/config/endpoint-enabled?endpoint=/api/v1/convert/pdf

This delegates to endpointConfiguration.isEndpointEnabled(...) and returns a JSON boolean indicating availability.

Automated Testing with Disabled Endpoints

Use the configuration bean in tests to verify behavior when features are unavailable:

@SpringBootTest
@AutoConfigureMockMvc
class ConvertPdfEndpointTest {

    @Autowired MockMvc mvc;
    @Autowired EndpointConfiguration endpointConfig;

    @BeforeEach void blockEndpoint() {
        endpointConfig.disableEndpoint("/api/v1/convert/pdf");
    }

    @Test void conversionShouldBeForbiddenWhenDisabled() throws Exception {
        mvc.perform(post("/api/v1/convert/pdf")
                .contentType(MediaType.MULTIPART_FORM_DATA)
                .param("file", "dummy"))
           .andExpect(status().isForbidden());
    }
}

This demonstrates runtime control by disabling the endpoint before asserting that the interceptor returns 403 Forbidden.

Key Implementation Files

Summary

  • Autowire EndpointConfiguration to programmatically enable or disable any REST endpoint at runtime without restarting Stirling-PDF.
  • Use disableEndpoint(path, reason) to provide context for logs when blocking access due to missing dependencies or configuration.
  • Leverage endpoint groups to toggle related functionality collectively by iterating over group mappings.
  • Rely on EndpointInterceptor to automatically enforce states, returning 403 Forbidden for disabled endpoints.
  • Query status either through the bean's isEndpointEnabled() method or the public /api/v1/config/endpoint-enabled REST endpoint.

Frequently Asked Questions

How does Stirling-PDF determine if an endpoint should be disabled at startup?

During initialization, the EndpointConfiguration bean executes init() and processEnvironmentConfigs() to load settings from ApplicationProperties and detect missing external dependencies via ExternalAppDepConfig. It populates endpointStatuses with explicit flags and disabledGroups for functional categories, checking these maps in isEndpointEnabled() when requests arrive.

Can I disable an endpoint temporarily and re-enable it without restarting the server?

Yes. The EndpointConfiguration bean is a singleton Spring service that maintains state in memory. Calling disableEndpoint() immediately updates the internal map, and subsequent requests receive 403 Forbidden responses. Calling enableEndpoint() restores access instantly for all new requests.

What happens when I try to call a disabled endpoint?

The EndpointInterceptor intercepts the request before it reaches the controller, checks endpointConfiguration.isEndpointEnabled(path), and if false, aborts the request with HTTP status 403 Forbidden and the body "Endpoint disabled". The reason (CONFIG, DEPENDENCY, or UNKNOWN) is logged server-side for diagnostics.

Is there a way to disable entire categories of endpoints based on missing system dependencies?

Yes. The codebase uses functional groups like "OpenCV" and "Python" defined in ExternalAppDepConfig. When the system detects missing binaries, it can call disableGroup() (or manually iterate getEndpointGroups().get("GroupName")) to disable all related endpoints simultaneously, ensuring users receive consistent 403 responses for unavailable functionality.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →