001/*
002 * Copyright 2002-2019 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.reactive.function.server;
018
019import java.net.URI;
020import java.time.Instant;
021import java.time.ZonedDateTime;
022import java.util.Collection;
023import java.util.List;
024import java.util.Map;
025import java.util.Set;
026import java.util.function.BiFunction;
027import java.util.function.Consumer;
028
029import org.reactivestreams.Publisher;
030import reactor.core.publisher.Mono;
031
032import org.springframework.core.ParameterizedTypeReference;
033import org.springframework.core.ReactiveAdapterRegistry;
034import org.springframework.http.CacheControl;
035import org.springframework.http.HttpHeaders;
036import org.springframework.http.HttpMethod;
037import org.springframework.http.HttpStatus;
038import org.springframework.http.MediaType;
039import org.springframework.http.ResponseCookie;
040import org.springframework.http.codec.HttpMessageWriter;
041import org.springframework.http.codec.json.Jackson2CodecSupport;
042import org.springframework.http.server.reactive.ServerHttpResponse;
043import org.springframework.util.MultiValueMap;
044import org.springframework.web.reactive.function.BodyInserter;
045import org.springframework.web.reactive.function.BodyInserters;
046import org.springframework.web.reactive.result.view.ViewResolver;
047import org.springframework.web.server.ServerWebExchange;
048
049/**
050 * Represents a typed server-side HTTP response, as returned
051 * by a {@linkplain HandlerFunction handler function} or
052 * {@linkplain HandlerFilterFunction filter function}.
053 *
054 * @author Arjen Poutsma
055 * @author Juergen Hoeller
056 * @author Sebastien Deleuze
057 * @since 5.0
058 */
059public interface ServerResponse {
060
061        /**
062         * Return the status code of this response.
063         * @return the status as an HttpStatus enum value
064         * @throws IllegalArgumentException in case of an unknown HTTP status code
065         * @see HttpStatus#valueOf(int)
066         */
067        HttpStatus statusCode();
068
069        /**
070         * Return the (potentially non-standard) status code of this response.
071         * @return the status as an integer
072         * @since 5.2
073         * @see #statusCode()
074         * @see HttpStatus#resolve(int)
075         */
076        int rawStatusCode();
077
078        /**
079         * Return the headers of this response.
080         */
081        HttpHeaders headers();
082
083        /**
084         * Return the cookies of this response.
085         */
086        MultiValueMap<String, ResponseCookie> cookies();
087
088        /**
089         * Write this response to the given web exchange.
090         * @param exchange the web exchange to write to
091         * @param context the context to use when writing
092         * @return {@code Mono<Void>} to indicate when writing is complete
093         */
094        Mono<Void> writeTo(ServerWebExchange exchange, Context context);
095
096
097        // Static methods
098
099        /**
100         * Create a builder with the status code and headers of the given response.
101         * @param other the response to copy the status and headers from
102         * @return the created builder
103         */
104        static BodyBuilder from(ServerResponse other) {
105                return new DefaultServerResponseBuilder(other);
106        }
107
108        /**
109         * Create a builder with the given HTTP status.
110         * @param status the response status
111         * @return the created builder
112         */
113        static BodyBuilder status(HttpStatus status) {
114                return new DefaultServerResponseBuilder(status);
115        }
116
117        /**
118         * Create a builder with the given HTTP status.
119         * @param status the response status
120         * @return the created builder
121         * @since 5.0.3
122         */
123        static BodyBuilder status(int status) {
124                return new DefaultServerResponseBuilder(status);
125        }
126
127        /**
128         * Create a builder with the status set to {@linkplain HttpStatus#OK 200 OK}.
129         * @return the created builder
130         */
131        static BodyBuilder ok() {
132                return status(HttpStatus.OK);
133        }
134
135        /**
136         * Create a new builder with a {@linkplain HttpStatus#CREATED 201 Created} status
137         * and a location header set to the given URI.
138         * @param location the location URI
139         * @return the created builder
140         */
141        static BodyBuilder created(URI location) {
142                BodyBuilder builder = status(HttpStatus.CREATED);
143                return builder.location(location);
144        }
145
146        /**
147         * Create a builder with an {@linkplain HttpStatus#ACCEPTED 202 Accepted} status.
148         * @return the created builder
149         */
150        static BodyBuilder accepted() {
151                return status(HttpStatus.ACCEPTED);
152        }
153
154        /**
155         * Create a builder with a {@linkplain HttpStatus#NO_CONTENT 204 No Content} status.
156         * @return the created builder
157         */
158        static HeadersBuilder<?> noContent() {
159                return status(HttpStatus.NO_CONTENT);
160        }
161
162        /**
163         * Create a builder with a {@linkplain HttpStatus#SEE_OTHER 303 See Other}
164         * status and a location header set to the given URI.
165         * @param location the location URI
166         * @return the created builder
167         */
168        static BodyBuilder seeOther(URI location) {
169                BodyBuilder builder = status(HttpStatus.SEE_OTHER);
170                return builder.location(location);
171        }
172
173        /**
174         * Create a builder with a {@linkplain HttpStatus#TEMPORARY_REDIRECT 307 Temporary Redirect}
175         * status and a location header set to the given URI.
176         * @param location the location URI
177         * @return the created builder
178         */
179        static BodyBuilder temporaryRedirect(URI location) {
180                BodyBuilder builder = status(HttpStatus.TEMPORARY_REDIRECT);
181                return builder.location(location);
182        }
183
184        /**
185         * Create a builder with a {@linkplain HttpStatus#PERMANENT_REDIRECT 308 Permanent Redirect}
186         * status and a location header set to the given URI.
187         * @param location the location URI
188         * @return the created builder
189         */
190        static BodyBuilder permanentRedirect(URI location) {
191                BodyBuilder builder = status(HttpStatus.PERMANENT_REDIRECT);
192                return builder.location(location);
193        }
194
195        /**
196         * Create a builder with a {@linkplain HttpStatus#BAD_REQUEST 400 Bad Request} status.
197         * @return the created builder
198         */
199        static BodyBuilder badRequest() {
200                return status(HttpStatus.BAD_REQUEST);
201        }
202
203        /**
204         * Create a builder with a {@linkplain HttpStatus#NOT_FOUND 404 Not Found} status.
205         * @return the created builder
206         */
207        static HeadersBuilder<?> notFound() {
208                return status(HttpStatus.NOT_FOUND);
209        }
210
211        /**
212         * Create a builder with an
213         * {@linkplain HttpStatus#UNPROCESSABLE_ENTITY 422 Unprocessable Entity} status.
214         * @return the created builder
215         */
216        static BodyBuilder unprocessableEntity() {
217                return status(HttpStatus.UNPROCESSABLE_ENTITY);
218        }
219
220
221        /**
222         * Defines a builder that adds headers to the response.
223         * @param <B> the builder subclass
224         */
225        interface HeadersBuilder<B extends HeadersBuilder<B>> {
226
227                /**
228                 * Add the given header value(s) under the given name.
229                 * @param headerName   the header name
230                 * @param headerValues the header value(s)
231                 * @return this builder
232                 * @see HttpHeaders#add(String, String)
233                 */
234                B header(String headerName, String... headerValues);
235
236                /**
237                 * Manipulate this response's headers with the given consumer. The
238                 * headers provided to the consumer are "live", so that the consumer can be used to
239                 * {@linkplain HttpHeaders#set(String, String) overwrite} existing header values,
240                 * {@linkplain HttpHeaders#remove(Object) remove} values, or use any of the other
241                 * {@link HttpHeaders} methods.
242                 * @param headersConsumer a function that consumes the {@code HttpHeaders}
243                 * @return this builder
244                 */
245                B headers(Consumer<HttpHeaders> headersConsumer);
246
247                /**
248                 * Add the given cookie to the response.
249                 * @param cookie the cookie to add
250                 * @return this builder
251                 */
252                B cookie(ResponseCookie cookie);
253
254                /**
255                 * Manipulate this response's cookies with the given consumer. The
256                 * cookies provided to the consumer are "live", so that the consumer can be used to
257                 * {@linkplain MultiValueMap#set(Object, Object) overwrite} existing cookies,
258                 * {@linkplain MultiValueMap#remove(Object) remove} cookies, or use any of the other
259                 * {@link MultiValueMap} methods.
260                 * @param cookiesConsumer a function that consumes the cookies
261                 * @return this builder
262                 */
263                B cookies(Consumer<MultiValueMap<String, ResponseCookie>> cookiesConsumer);
264
265                /**
266                 * Set the set of allowed {@link HttpMethod HTTP methods}, as specified
267                 * by the {@code Allow} header.
268                 *
269                 * @param allowedMethods the allowed methods
270                 * @return this builder
271                 * @see HttpHeaders#setAllow(Set)
272                 */
273                B allow(HttpMethod... allowedMethods);
274
275                /**
276                 * Set the set of allowed {@link HttpMethod HTTP methods}, as specified
277                 * by the {@code Allow} header.
278                 * @param allowedMethods the allowed methods
279                 * @return this builder
280                 * @see HttpHeaders#setAllow(Set)
281                 */
282                B allow(Set<HttpMethod> allowedMethods);
283
284                /**
285                 * Set the entity tag of the body, as specified by the {@code ETag} header.
286                 * @param eTag the new entity tag
287                 * @return this builder
288                 * @see HttpHeaders#setETag(String)
289                 */
290                B eTag(String eTag);
291
292                /**
293                 * Set the time the resource was last changed, as specified by the
294                 * {@code Last-Modified} header.
295                 * @param lastModified the last modified date
296                 * @return this builder
297                 * @see HttpHeaders#setLastModified(long)
298                 */
299                B lastModified(ZonedDateTime lastModified);
300
301                /**
302                 * Set the time the resource was last changed, as specified by the
303                 * {@code Last-Modified} header.
304                 * @param lastModified the last modified date
305                 * @return this builder
306                 * @since 5.1.4
307                 * @see HttpHeaders#setLastModified(long)
308                 */
309                B lastModified(Instant lastModified);
310
311                /**
312                 * Set the location of a resource, as specified by the {@code Location} header.
313                 * @param location the location
314                 * @return this builder
315                 * @see HttpHeaders#setLocation(URI)
316                 */
317                B location(URI location);
318
319                /**
320                 * Set the caching directives for the resource, as specified by the HTTP 1.1
321                 * {@code Cache-Control} header.
322                 * <p>A {@code CacheControl} instance can be built like
323                 * {@code CacheControl.maxAge(3600).cachePublic().noTransform()}.
324                 * @param cacheControl a builder for cache-related HTTP response headers
325                 * @return this builder
326                 * @see <a href="https://tools.ietf.org/html/rfc7234#section-5.2">RFC-7234 Section 5.2</a>
327                 */
328                B cacheControl(CacheControl cacheControl);
329
330                /**
331                 * Configure one or more request header names (e.g. "Accept-Language") to
332                 * add to the "Vary" response header to inform clients that the response is
333                 * subject to content negotiation and variances based on the value of the
334                 * given request headers. The configured request header names are added only
335                 * if not already present in the response "Vary" header.
336                 * @param requestHeaders request header names
337                 * @return this builder
338                 */
339                B varyBy(String... requestHeaders);
340
341                /**
342                 * Build the response entity with no body.
343                 */
344                Mono<ServerResponse> build();
345
346                /**
347                 * Build the response entity with no body.
348                 * <p>The response will be committed when the given {@code voidPublisher} completes.
349                 * @param voidPublisher the publisher to indicate when the response should be committed
350                 */
351                Mono<ServerResponse> build(Publisher<Void> voidPublisher);
352
353                /**
354                 * Build the response entity with a custom writer function.
355                 * @param writeFunction the function used to write to the {@link ServerWebExchange}
356                 */
357                Mono<ServerResponse> build(BiFunction<ServerWebExchange, Context, Mono<Void>> writeFunction);
358        }
359
360
361        /**
362         * Defines a builder that adds a body to the response.
363         */
364        interface BodyBuilder extends HeadersBuilder<BodyBuilder> {
365
366                /**
367                 * Set the length of the body in bytes, as specified by the
368                 * {@code Content-Length} header.
369                 * @param contentLength the content length
370                 * @return this builder
371                 * @see HttpHeaders#setContentLength(long)
372                 */
373                BodyBuilder contentLength(long contentLength);
374
375                /**
376                 * Set the {@linkplain MediaType media type} of the body, as specified by the
377                 * {@code Content-Type} header.
378                 * @param contentType the content type
379                 * @return this builder
380                 * @see HttpHeaders#setContentType(MediaType)
381                 */
382                BodyBuilder contentType(MediaType contentType);
383
384                /**
385                 * Add a serialization hint like {@link Jackson2CodecSupport#JSON_VIEW_HINT}
386                 * to customize how the body will be serialized.
387                 * @param key the hint key
388                 * @param value the hint value
389                 */
390                BodyBuilder hint(String key, Object value);
391
392                /**
393                 * Customize the serialization hints with the given consumer.
394                 * @param hintsConsumer a function that consumes the hints
395                 * @return this builder
396                 * @since 5.1.6
397                 */
398                BodyBuilder hints(Consumer<Map<String, Object>> hintsConsumer);
399
400                /**
401                 * Set the body of the response to the given {@code Object} and return it.
402                 * This is a shortcut for using a {@link #body(BodyInserter)} with a
403                 * {@linkplain BodyInserters#fromValue value inserter}.
404                 * @param body the body of the response
405                 * @return the built response
406                 * @throws IllegalArgumentException if {@code body} is a
407                 * {@link Publisher} or producer known to {@link ReactiveAdapterRegistry}
408                 * @since 5.2
409                 */
410                Mono<ServerResponse> bodyValue(Object body);
411
412                /**
413                 * Set the body from the given {@code Publisher}. Shortcut for
414                 * {@link #body(BodyInserter)} with a
415                 * {@linkplain BodyInserters#fromPublisher Publisher inserter}.
416                 * @param publisher the {@code Publisher} to write to the response
417                 * @param elementClass the type of elements published
418                 * @param <T> the type of the elements contained in the publisher
419                 * @param <P> the type of the {@code Publisher}
420                 * @return the built response
421                 */
422                <T, P extends Publisher<T>> Mono<ServerResponse> body(P publisher, Class<T> elementClass);
423
424                /**
425                 * Variant of {@link #body(Publisher, Class)} that allows using any
426                 * producer that can be resolved to {@link Publisher} via
427                 * {@link ReactiveAdapterRegistry}.
428                 * @param publisher the {@code Publisher} to use to write the response
429                 * @param elementTypeRef the type of elements produced
430                 * @param <T> the type of the elements contained in the publisher
431                 * @param <P> the type of the {@code Publisher}
432                 * @return the built response
433                 */
434                <T, P extends Publisher<T>> Mono<ServerResponse> body(P publisher,
435                                ParameterizedTypeReference<T> elementTypeRef);
436
437                /**
438                 * Variant of {@link #body(Publisher, Class)} that allows using any
439                 * producer that can be resolved to {@link Publisher} via
440                 * {@link ReactiveAdapterRegistry}.
441                 * @param producer the producer to write to the request
442                 * @param elementClass the type of elements produced
443                 * @return the built response
444                 * @since 5.2
445                 */
446                Mono<ServerResponse> body(Object producer, Class<?> elementClass);
447
448                /**
449                 * Variant of {@link #body(Publisher, ParameterizedTypeReference)} that
450                 * allows using any producer that can be resolved to {@link Publisher}
451                 * via {@link ReactiveAdapterRegistry}.
452                 * @param producer the producer to write to the response
453                 * @param elementTypeRef the type of elements produced
454                 * @return the built response
455                 * @since 5.2
456                 */
457                Mono<ServerResponse> body(Object producer, ParameterizedTypeReference<?> elementTypeRef);
458
459                /**
460                 * Set the body of the response to the given {@code BodyInserter} and return it.
461                 * @param inserter the {@code BodyInserter} that writes to the response
462                 * @return the built response
463                 */
464                Mono<ServerResponse> body(BodyInserter<?, ? super ServerHttpResponse> inserter);
465
466                /**
467                 * Set the response body to the given {@code Object} and return it.
468                 * As of 5.2 this method delegates to {@link #bodyValue(Object)}.
469                 * @deprecated as of Spring Framework 5.2 in favor of {@link #bodyValue(Object)}
470                 */
471                @Deprecated
472                Mono<ServerResponse> syncBody(Object body);
473
474                /**
475                 * Render the template with the given {@code name} using the given {@code modelAttributes}.
476                 * The model attributes are mapped under a
477                 * {@linkplain org.springframework.core.Conventions#getVariableName generated name}.
478                 * <p><em>Note: Empty {@link Collection Collections} are not added to
479                 * the model when using this method because we cannot correctly determine
480                 * the true convention name.</em>
481                 * @param name the name of the template to be rendered
482                 * @param modelAttributes the modelAttributes used to render the template
483                 * @return the built response
484                 */
485                Mono<ServerResponse> render(String name, Object... modelAttributes);
486
487                /**
488                 * Render the template with the given {@code name} using the given {@code model}.
489                 * @param name the name of the template to be rendered
490                 * @param model the model used to render the template
491                 * @return the built response
492                 */
493                Mono<ServerResponse> render(String name, Map<String, ?> model);
494        }
495
496
497        /**
498         * Defines the context used during the {@link #writeTo(ServerWebExchange, Context)}.
499         */
500        interface Context {
501
502                /**
503                 * Return the {@link HttpMessageWriter HttpMessageWriters} to be used for response body conversion.
504                 * @return the list of message writers
505                 */
506                List<HttpMessageWriter<?>> messageWriters();
507
508                /**
509                 * Return the  {@link ViewResolver ViewResolvers} to be used for view name resolution.
510                 * @return the list of view resolvers
511                 */
512                List<ViewResolver> viewResolvers();
513        }
514
515}