Skip to content

Url template #407

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

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open

Url template #407

wants to merge 10 commits into from

Conversation

amotov
Copy link
Contributor

@amotov amotov commented May 27, 2025

The url-template property defines how the url field in the filter configuration is interpreted:

REGEX (default): The url value is treated as a standard regular expression pattern. The filter matches requests based on this regex.
CUSTOM: The url value is interpreted as a custom URL template pattern (e.g., Ant-style path pattern like /**). Internally, this template will be converted to a regex for matching.
This addition enables more flexible and readable URL pattern definitions in filter configurations, allowing users to choose between precise regex patterns or simplified template syntax.

@amotov
Copy link
Contributor Author

amotov commented May 27, 2025

Hi @macguffin!

I've added support for a new url-template property in the filter configuration. This allows users to define URL patterns in a more readable format (CUSTOM), alongside the traditional REGEX mode. This improves flexibility for those using Ant-style patterns like /**.

Let me know if you'd like any changes or refinements. I'd really appreciate it if you could take a look and consider merging.

@amotov
Copy link
Contributor Author

amotov commented May 27, 2025

Additionally, as a possible future improvement, the CUSTOM mode could support a configurable SpEL expression to define how the URL template should be resolved into a regex — without needing a dedicated mapper bean.

This would allow even greater flexibility and reduce the need to wire Java components for simple pattern mapping.

Let me know what you think.

@MarcGiffing
Copy link
Owner

Hey, thanks für the PR. I'm not sure if there is maybe an alternative way to solve the problem. I don't see a reason why a new property is needed. The result is a regex. The UrlTemplateMapper converts the URL into an REGEX. One solution is maybe to provide a default Bean which only return the configured string.

@Bean
@ConditionalOnMissingBean(UrlMapper.class)
public UrlMapper defaultUrlMapper() {
  return url -> url;
}

The user can override the UrlMapper with a custom implementation:

@Bean
public UrlMapper antPathMatcherUrlMapper() {
  return url -> // your custom logic.;
}

This was you don't have to configure any additional properties.

I would only see a benefit if you already insert the support for a AntPathMatcher

@MarcGiffing MarcGiffing added this to the 0.12.10 milestone May 30, 2025
CacheManager<String, Bucket4JConfiguration> configCacheManager,
List<MetricHandler> metricHandlers,
Map<String, ExecutePredicate<R>> executePredicates,
@Autowired(required = false) UrlMapper urlMapper) {
Copy link
Owner

@MarcGiffing MarcGiffing Jun 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove the constructor? The default UrlMapper implementation is provided within the Bucket4jUrlConfiguration. (re add the @requiredargsconstructor)

@MarcGiffing
Copy link
Owner

Sorry, If I expressed myself badly. You provide now a default implementation for the PathPattern implementation, thank you! But the users can't switch between this implementations. Know it makes sense to provide such an enum. They have to define a bean on there own. Maybe we introduce the enum again. Or you have a better idea. There is currently also no hint that you can use the PathPattern from Spring.

@Bean
    @ConditionalOnMissingBean(UrlMapper.class)
    public UrlMapper urlMapper(Bucket4JBootProperties properties) {
        return switch(properties.getUrlMapperType()) {
            case REGEX -> new RegexUrlMapper();
            case PATH_PATTERN -> new PatternUrlMapper();
        };
    }

@Override
public UrlMatcher getMatcher(String pattern) {
var pathPatternParser =
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really needed? The parse implementation creates a new InternalPathPatternParser because the PathPatternParser is not Thread save. It seems that the InternalPathPatternParser only uses the configuration from the PathPatternParser. So a new instance is created because the PathPatternParser is not Thread-Save but because of that we don't need a new instance every time. Maybe I'm wrong...

import jakarta.validation.ConstraintValidatorContext;
import org.springframework.beans.factory.annotation.Autowired;

public class UrlValidator
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional - what do you think?: Maybe something like UrlPatternMatcherValidator to give a hint, that not an URL is validated. Afterwards I should have name the property maybe url.pattern=.*

@amotov
Copy link
Contributor Author

amotov commented Jun 2, 2025

  • Maintained backward compatibility with the existing deprecated url property by introducing a new url-pattern property, accessible via a combined getter that falls back to url if url-pattern is not set.
  • Added the url-pattern-parser property as a string type, which controls the initialization of corresponding beans for values regex and path-pattern.
  • Implemented support for extracting variables from URL patterns and passing them into the SpEL context.
  • Added support for query strings. I use a custom parser that handles requests with query parameters, e.g. /api/*/models/**?param1=value&param2=*. I plan to refine this further and release it as an extension to your library later if there's interest.

@amotov
Copy link
Contributor Author

amotov commented Jun 2, 2025

Open Questions

  • It’s not entirely clear how to avoid injecting UrlPatternParser.
  • It might be necessary to add a pattern type setting for each filter.
  • Remove support for extracting groups in regex patterns.
  • Make variable extraction from the URL optional.
  • Add tests: Cover cases where filters do not execute. Test different matcher implementations separately.

@MarcGiffing MarcGiffing modified the milestones: 0.12.10, 0.12.11 Jun 5, 2025
@@ -252,7 +253,7 @@ bucket4j.filters[0].http-status-code=TOO_MANY_REQUESTS # Enum value of org.sprin
bucket4j.filters[0].http-response-body={ "message": "Too many requests" } # the json response which should be added to the body
bucket4j.filters[0].http-response-headers.<MY_CUSTOM_HEADER>=MY_CUSTOM_HEADER_VALUE # You can add any numbers of custom headers
bucket4j.filters[0].hide-http-response-headers=true # Hides response headers like x-rate-limit-remaining or x-rate-limit-retry-after-seconds on rate limiting
bucket4j.filters[0].url=.* # a regular expression
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert the renaming. The users may used to be using the '.url' property. I don't want to change it. My comment was maybe unclear, sorry.


public interface UrlPatternMatcher {

boolean matches(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

your line length is too short. can you check that please.

* <p>Default is <b>regex</b>.</p>
* <p>This setting controls how URL patterns in Bucket4j filters will be interpreted.</p>
*/
private String urlPatternParser = "regex";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use an enum again. If someone misspells it, the application will only fail at startup due to the missing UrlPatternParser bean, and the user won't know how to resolve the issue.

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

Successfully merging this pull request may close these issues.

2 participants