001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.util;
018
019import java.net.URI;
020import java.util.Collection;
021import java.util.Map;
022
023import org.springframework.lang.Nullable;
024import org.springframework.util.MultiValueMap;
025
026/**
027 * Builder-style methods to prepare and expand a URI template with variables.
028 *
029 * <p>Effectively a generalization of {@link UriComponentsBuilder} but with
030 * shortcuts to expand directly into {@link URI} rather than
031 * {@link UriComponents} and also leaving common concerns such as encoding
032 * preferences, a base URI, and others as implementation concerns.
033 *
034 * <p>Typically obtained via {@link UriBuilderFactory} which serves as a central
035 * component configured once and used to create many URLs.
036 *
037 * @author Rossen Stoyanchev
038 * @since 5.0
039 * @see UriBuilderFactory
040 * @see UriComponentsBuilder
041 */
042public interface UriBuilder {
043
044        /**
045         * Set the URI scheme which may contain URI template variables,
046         * and may also be {@code null} to clear the scheme of this builder.
047         * @param scheme the URI scheme
048         */
049        UriBuilder scheme(@Nullable String scheme);
050
051        /**
052         * Set the URI user info which may contain URI template variables, and
053         * may also be {@code null} to clear the user info of this builder.
054         * @param userInfo the URI user info
055         */
056        UriBuilder userInfo(@Nullable String userInfo);
057
058        /**
059         * Set the URI host which may contain URI template variables, and may also
060         * be {@code null} to clear the host of this builder.
061         * @param host the URI host
062         */
063        UriBuilder host(@Nullable String host);
064
065        /**
066         * Set the URI port. Passing {@code -1} will clear the port of this builder.
067         * @param port the URI port
068         */
069        UriBuilder port(int port);
070
071        /**
072         * Set the URI port . Use this method only when the port needs to be
073         * parameterized with a URI variable. Otherwise use {@link #port(int)}.
074         * Passing {@code null} will clear the port of this builder.
075         * @param port the URI port
076         */
077        UriBuilder port(@Nullable String port);
078
079        /**
080         * Append to the path of this builder.
081         * <p>The given value is appended as-is without any checks for slashes other
082         * than to clean up duplicates. For example:
083         * <pre class="code">
084         *
085         * builder.path("/first-").path("value/").path("/{id}").build("123")
086         *
087         * // Results is "/first-value/123"
088         * </pre>
089         * <p>By contrast {@link #pathSegment(String...)} builds the path from
090         * individual path segments and in that case slashes are inserted transparently.
091         * In some cases you may use a combination of both {@code pathSegment} and
092         * {@code path}. For example:
093         * <pre class="code">
094         *
095         * builder.pathSegment("first-value", "second-value").path("/")
096         *
097         * // Results is "/first-value/second-value/"
098         *
099         * </pre>
100         * <p>If a URI variable value contains slashes, whether those are encoded or
101         * not depends on the configured encoding mode. See
102         * {@link UriComponentsBuilder#encode()}, or if using
103         * {@code UriComponentsBuilder} via {@link DefaultUriBuilderFactory}
104         * (e.g. {@code WebClient} or {@code RestTemplate}) see its
105         * {@link DefaultUriBuilderFactory#setEncodingMode encodingMode} property.
106         * Also see the <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#web-uri-encoding">
107         * URI Encoding</a> section of the reference docs.
108         * @param path the URI path
109         */
110        UriBuilder path(String path);
111
112        /**
113         * Override the existing path.
114         * @param path the URI path, or {@code null} for an empty path
115         */
116        UriBuilder replacePath(@Nullable String path);
117
118        /**
119         * Append to the path using path segments. For example:
120         * <pre class="code">
121         *
122         * builder.pathSegment("first-value", "second-value", "{id}").build("123")
123         *
124         * // Results is "/first-value/second-value/123"
125         *
126         * </pre>
127         * <p>If slashes are present in a path segment, they are encoded:
128         * <pre class="code">
129         *
130         * builder.pathSegment("ba/z", "{id}").build("a/b")
131         *
132         * // Results is "/ba%2Fz/a%2Fb"
133         *
134         * </pre>
135         * To insert a trailing slash, use the {@link #path} builder method:
136         * <pre class="code">
137         *
138         * builder.pathSegment("first-value", "second-value").path("/")
139         *
140         * // Results is "/first-value/second-value/"
141         *
142         * </pre>
143         * @param pathSegments the URI path segments
144         */
145        UriBuilder pathSegment(String... pathSegments) throws IllegalArgumentException;
146
147        /**
148         * Parse the given query string into query parameters where parameters are
149         * separated with {@code '&'} and their values, if any, with {@code '='}.
150         * The query may contain URI template variables.
151         * <p><strong>Note: </strong> please, review the Javadoc of
152         * {@link #queryParam(String, Object...)} for further notes on the treatment
153         * and encoding of individual query parameters.
154         * @param query the query string
155         */
156        UriBuilder query(String query);
157
158        /**
159         * Clear existing query parameters and then delegate to {@link #query(String)}.
160         * <p><strong>Note: </strong> please, review the Javadoc of
161         * {@link #queryParam(String, Object...)} for further notes on the treatment
162         * and encoding of individual query parameters.
163         * @param query the query string; a {@code null} value removes all query parameters.
164         */
165        UriBuilder replaceQuery(@Nullable String query);
166
167        /**
168         * Append the given query parameter. Both the parameter name and values may
169         * contain URI template variables to be expanded later from values. If no
170         * values are given, the resulting URI will contain the query parameter name
171         * only, e.g. {@code "?foo"} instead of {@code "?foo=bar"}.
172         * <p><strong>Note:</strong> encoding, if applied, will only encode characters
173         * that are illegal in a query parameter name or value such as {@code "="}
174         * or {@code "&"}. All others that are legal as per syntax rules in
175         * <a href="https://tools.ietf.org/html/rfc3986">RFC 3986</a> are not
176         * encoded. This includes {@code "+"} which sometimes needs to be encoded
177         * to avoid its interpretation as an encoded space. Stricter encoding may
178         * be applied by using a URI template variable along with stricter encoding
179         * on variable values. For more details please read the
180         * <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#web-uri-encoding">"URI Encoding"</a>
181         * section of the Spring Framework reference.
182         * @param name the query parameter name
183         * @param values the query parameter values
184         * @see #queryParam(String, Collection)
185         */
186        UriBuilder queryParam(String name, Object... values);
187
188        /**
189         * Variant of {@link #queryParam(String, Object...)} with a Collection.
190         * <p><strong>Note: </strong> please, review the Javadoc of
191         * {@link #queryParam(String, Object...)} for further notes on the treatment
192         * and encoding of individual query parameters.
193         * @param name the query parameter name
194         * @param values the query parameter values
195         * @since 5.2
196         * @see #queryParam(String, Object...)
197         */
198        UriBuilder queryParam(String name, @Nullable Collection<?> values);
199
200        /**
201         * Add multiple query parameters and values.
202         * <p><strong>Note: </strong> please, review the Javadoc of
203         * {@link #queryParam(String, Object...)} for further notes on the treatment
204         * and encoding of individual query parameters.
205         * @param params the params
206         */
207        UriBuilder queryParams(MultiValueMap<String, String> params);
208
209        /**
210         * Set the query parameter values replacing existing values, or if no
211         * values are given, the query parameter is removed.
212         * <p><strong>Note: </strong> please, review the Javadoc of
213         * {@link #queryParam(String, Object...)} for further notes on the treatment
214         * and encoding of individual query parameters.
215         * @param name the query parameter name
216         * @param values the query parameter values
217         * @see #replaceQueryParam(String, Collection)
218         */
219        UriBuilder replaceQueryParam(String name, Object... values);
220
221        /**
222         * Variant of {@link #replaceQueryParam(String, Object...)} with a Collection.
223         * <p><strong>Note: </strong> please, review the Javadoc of
224         * {@link #queryParam(String, Object...)} for further notes on the treatment
225         * and encoding of individual query parameters.
226         * @param name the query parameter name
227         * @param values the query parameter values
228         * @since 5.2
229         * @see #replaceQueryParam(String, Object...)
230         */
231        UriBuilder replaceQueryParam(String name, @Nullable Collection<?> values);
232
233        /**
234         * Set the query parameter values after removing all existing ones.
235         * <p><strong>Note: </strong> please, review the Javadoc of
236         * {@link #queryParam(String, Object...)} for further notes on the treatment
237         * and encoding of individual query parameters.
238         * @param params the query parameter name
239         */
240        UriBuilder replaceQueryParams(MultiValueMap<String, String> params);
241
242        /**
243         * Set the URI fragment. The given fragment may contain URI template variables,
244         * and may also be {@code null} to clear the fragment of this builder.
245         * @param fragment the URI fragment
246         */
247        UriBuilder fragment(@Nullable String fragment);
248
249        /**
250         * Build a {@link URI} instance and replaces URI template variables
251         * with the values from an array.
252         * @param uriVariables the map of URI variables
253         * @return the URI
254         */
255        URI build(Object... uriVariables);
256
257        /**
258         * Build a {@link URI} instance and replaces URI template variables
259         * with the values from a map.
260         * @param uriVariables the map of URI variables
261         * @return the URI
262         */
263        URI build(Map<String, ?> uriVariables);
264
265}