spring-projects / spring-framework

Spring Framework
https://spring.io/projects/spring-framework
Apache License 2.0
56.61k stars 38.13k forks source link

Support limited subset of RFC 6570 syntax including operators "", "?", "/", "#" [SPR-14134] #18706

Open spring-projects-issues opened 8 years ago

spring-projects-issues commented 8 years ago

Stefan Kühnel opened SPR-14134 and commented

org.springframework.web.util.UriTemplate and org.springframework.web.util.DefaultUriTemplateHandler (and RestTemplate as consequence) don't support the complete syntax of RfC 6570, but Spring HATEOAS has a version that does org.springframework.hateoas.UriTemplate. So the features should be merged into the "standard" template functionality.


Affects: 4.2.5

Issue Links:

1 votes, 2 watchers

spring-projects-issues commented 8 years ago

Rossen Stoyanchev commented

We've already looked into supporting RFC 6570. It's very extensive and arguably well beyond most needs. Even the spec recognizes that and defines itself in terms of 4 levels (section 1.2). Moreover there are significant differences in the way Spring's URI template support works and we've made a conscious decision not to change the mechanisms in place but rather evolve them as needed, i.e. not seeking compliance with the spec. You can see more comments on that.

Note that the RestTemplate does have a UriTemplateHandler extension point which allows you to completely replace the URI template handling for example swapping out our URI template support with another from an external library that supports RFC 6570.

That said we can consider specific features and enhancements around Spring's URI template handling. That would mean a separate ticket with a more specific request for enhancement.

spring-projects-issues commented 8 years ago

Stefan Kühnel commented

Hello @Rossen Stoyanchev,

thanks for the update and the links.

In the REST scenario we have we had a ressource like Customer. The URI design looks like the following (using RFC 6570 syntax), which follows common best practices from all I can tell:

https://{host}:{port}/v42/customers{/id}{?size,page,name}}

This is very similar to what Spring Data Rest does (e.g. https://spring.io/guides/gs/accessing-data-rest/), but we want some more control.

For a client side wrapper of the ressource, it could look something like the following:

public class Customers
{
    private String ID_PARAM = "id";
    private String SIZE_PARAM = "size";
    private String PAGE_PARAM = "page";
    private String NAME_PARAM = "name";

    // One can easily see and understand the whole structure and design of the resouce URIs with this one line.
    private String URI_TEMPLATE = "https://api.example.com/v42/customers{/id}{?size,page,name}}";

    private RestTemplate template = new RestTemplate();

    public List<Customer> getCustomers(int page, int size)
    {
        Map<String,Object> urlVariables = new HashMap<>();
        urlVariables.add(PAGE_PARAM, page);
        urlVariables.add(SIZE_PARAM, size);

    Customer[] customers = template.getForObject(URI_TEMPLATE, Customer[].class, urlVariables);

        return Arrays.asList(customers);
    }

    public Customer getCustomer(long id)
    {
        Map<String,Object> urlVariables = new HashMap<>();
        urlVariables.add(ID_PARAM, id);

    Customer customer = template.getForObject(URI_TEMPLATE, Customer.class, urlVariables);

        return customer;
    }

    public List<Customer> searchCustomer(String name)
    {
        Map<String,Object> urlVariables = new HashMap<>();
        urlVariables.add(NAME_PARAM, name);

    Customer[] customers = template.getForObject(URI_TEMPLATE, Customer[].class, urlVariables);

        return Arrays.asList(customers);
    }
}

This looks very simple to me: Always the same URI template. The correct URI would be created "automagically" depending on the given urlVariables.

For this to work the types as used in UriTemplate of Spring HATEOAS ("", "?", "/", "#") are sufficient IMHO.

spring-projects-issues commented 8 years ago

Rossen Stoyanchev commented

We can consider an alternative UriTemplateHandler that supports a limited subset of the RFC based on the given list of operators. Probably taking a similar approach as in the Spring HATEOAS UriTemplate, resolving what variables should be added from expressions and then building the URI with UriComponentsBuilder. The main difference is that it would be packaged as a UriTemplateHandler and available to plug into the RestTemplate.

spring-projects-issues commented 8 years ago

Stefan Kühnel commented

Thanks, Rossen, this sounds very good to me. :-)