After writing tests for my REST API (built using Spring Boot), I realised that, even when the request body is not used (see below), calling the endpoint with a request body succeeds–effectively, Spring ignores the body.
This is not a huge issue, but I was wondering what philosophy I should approach this with:
Should I fail when passed an unexpected body (when do not expect any)?
If so, is this configurable in Spring so that there is strict checking of body/parameters?
Finally, beyond personal preference and/or experience, is there a good way of deciding this, or should I simply use 'if it isn't broken, don't fix it' as my mantra?
#PatchMapping(value = "/products/{pid}/sell")
public TxDTO sell(#NotBlank #PathVariable("pid") String pid,
#NotNull #RequestParam Float price)
I think you shouldn't think too much into this. Technically, ignoring the unexpected body doesn't violate any software development principles. Even though this might be something that makes you feel uncomfortable personally in the context of your project, you might want to consider other scenarios where there's a filter or servlet sitting in front of your #RestController doing some additional stuff you're not aware of.
The point is this is not a feature you should turn off globally nor it is worth spending time implementing custom code to turn it off locally for a single endpoint :).
Related
I often see three different response return types: Flux<T>, ResponseEntity<Flux<T>>, and Flux<ResponseEntity<T>> in MVC style controllers using Spring WebFlux. The documentation explains the difference between ResponseEntity<Flux<T>> and Flux<ResponseEntity<T>>. Does Spring automatically wrap Flux<T> as either ResponseEntity<Flux<T>> or Flux<ResponseEntity<T>>? if yes, which one?
Moreover, how to decide which one to return, ResponseEntity<Flux<T>> or Flux<ResponseEntity<T>>? What situation or use case would call for using one over the other?
And, from a webclient's point of view, are there any significant differences when consuming the two types of response?
Does Spring automatically wrap Flux as either
ResponseEntity<Flux> or Flux<ResponseEntity>? if yes, which one?
Spring will automatically wrap that Flux as a ResponseEntity<Flux>. For example if you have a web endpoint as follows
#GetMapping("/something")
public Flux handle() {
doSomething()
}
And if you are consuming from a WebClient, you can retrieve your response as either ResponseEntity<Flux<T>> or Flux<T>. There is no default, but I would think it's good practice to retrieve only Flux unless you explicitly need something from the ResponseEntity. The Spring doc has good examples of this.
You actually can consume it as a Flux<ResponseEntity<T>>, but this would only be applicable for more complex use cases.
Moreover, how to decide which one to return, ResponseEntity<Flux>
or Flux<ResponseEntity>? What situation or use case would call for
using one over the other?
It really depends on your use case.
Returning ResponseEntity<Flux<T>> is saying something like,
I am returning a Response of a Collection of type T objects.
Where Flux<ResponseEntity<T>> is saying something more like
I am returning a Collection of Responses, where the responses have an entity of type T.
Again, I think in most use cases returning just Flux<T> makes sense (This is equivalent to returning ResponseEntity<Flux<T>>)
And finally
And, from a webclient's point of view, are there any significant
differences when consuming the two types of response?
I think what you're trying to ask is whether you should be using ResponseEntity<Flux<T>> or Mono<ResponseEntity<T>> when consuming from the WebClient. And the spring doc answers this question quite elegantly
ResponseEntity<Flux> make the response status and headers known
immediately while the body is provided asynchronously at a later
point.
Mono<ResponseEntity> provides all three — response status, headers,
and body, asynchronously at a later point. This allows the response
status and headers to vary depending on the outcome of asynchronous
request handling.
As a newcomer to spring I would like to know the actual difference between:-
#PostMapping
#PutMapping
#PatchMapping
My understanding is PUT is for update but then we have to get the element by its id and then save() it. Similarly the save() method is again used by Post which automatically replaces by its identifier(PRIMARY). In my application I am able to use three of these methods interchangeably.
What is the point of having PATCH, POST, PUT types when we use repository save methods for all?
HTTP method tokens are used to define request semantics in such a way that general purpose components (browsers, reverse proxies, etc) can exploit the information to do intelligent things.
The easiest of these is that PUT has idempotent semantics; if an http response is lost, a general purpose component knows that it may autonomously retry sending the request. This in turn gives you a bit of extra reliability over an unreliable network, "for free".
The fact that your origin server uses the same persistence mechanism for each is an implementation detail, something deliberately hidden behind the "uniform interface".
The difference between PATCH and POST is subtle; PATCH gives you an unambiguous way to designate that the enclosed entity is a patch document, and offers a mechanism for discovering which patch document formats are understood by the origin server, neither of which you get from POST alone.
What's less clear, at least to me, is whether PATCH semantics allow an intermediate component to do something intelligent with a request - in other words, do the additional constraints (relative to POST) allow intermediaries to do anything interesting?
As best I can tell, the semantics of a PATCH request are more specific, but not actionably more specific -- certainly not as obviously as we have in the case of safe or idempotent request semantics.
POST is for creating a brand new object.
PUT will replace all of an objects properties in one go.
Leaving a property empty will empty the value in the datastore.
PATCH does a partial update of an object.
You can send it just the properties which should be updated.
A PATCH request with all object properties included will have the same effect as a POST request. But they are not the same.
The HTTP method is a convention not specific to Spring but is a main pillar of the REST API specification.
They make sure the intent of a request is clear and both the provider and consumer are in agreement of the end result.
Kind of like the pedals or gear shift in our cars. It's a lot easier when they all work the same.
Switching them up could lead to a lot of accidents.
For us as developers, it means we can expect most REST APIs to behave in a similar way, assuming an API is implemented according to or reasonably close to the specification.
POST/PUT/PATCH may look alike but there are subtle differences.
As you mention the PUT and PATCH methods require some kind of ID of the object to be updated.
In an example of a combined POST/PUT/PATCH endpoint, sending a request with an object, omitting some of its properties. How does the API react?
Update only the received properties.
Update the entire object, emptying the omitted properties.
Attempt to create a new object.
How is the consumer of the endpoint to know which of the three actions the server took?
This is where the HTTP method and specification/convention help determine the appropriate course of action.
Spring may facilitate the save method which can handle both creation, updates and partial updates. But this is not necessarily the case for other frameworks in Java or other languages.
Also, your application may be simple enough to handle POST/PUT/PATCH in the same controller method right now.
But over time as your application grows more complex, the separation of concerns makes your code a lot cleaner, more readable and maintainable.
I'm writing some tests for a Spring WebFlux application and I'm trying to mock a scenario where a request doesn't have a body. I reached for the built-in MockServerRequest, figuring I'd use the built-in mock over making my own. It does allow constructing an instance without a body, but my tests are failing as all of its methods for extracting the body contain an assertion that the body is not null. This doesn't seem to line up with how an actual request would behave. It's totally possible to make a request with no body. I'd also say it's reasonable to have code that checks to see if there's a body, as backed up by the existence of methods like awaitBodyOrNull (I'm using Kotlin).
Am I missing/misunderstanding something here? I'm constructing my mock by just doing MockServerRequest.builder().build() (the methods under test don't care about anything other than the body). Is this class perhaps not actually meant to be used on its own? I'm not finding anyone else asking about this so I feel like I must be overlooking something.
For now I'll work around this by just making my own mock.
MockServerRequest.Builder expects you to give it a body already wrapped in a Mono. It doesn't do any wrapping for you. So mocking an empty request is done with MockServerRequest.builder().body(Mono.empty<TestDto>()).
Is there a way to change the default response format for GET requests like /ws/v1/cluster/info to be XML?
I know that I can specify the Accept: application/xmlheader with my request. However I want to change the default value so that I can omit the header.
From my reading of the Yarn source code, the distinction between JSON and XML is completely delegated to the underlying JAX-RS infrastructure, with annotations like
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
all over the code. This mechanism (called "Static Content Negotiation") specifies that the first in the list is the default, which is consistent with behavior. One could use the javax.ws.rs.core.Variant class (and a technique called "Runtime Content Negotiation") to override this, but I can't find any use of it in the codebase.
If you're willing to make a small modification to the source and rebuild it, you could simply find all of these #Produces declarations and swap the order. If you decide to do this, you'll want to be mindful of the apparent bug described here. If it turns out to still be relevant (and it was recent), you may find you have to tackle all the complexity of runtime content negotiation anyway.
It should be simple enough to try it out, but if you don't have any other reason to build from sources it's probably overkill.
It's a code design question :)
I have a DelegatingHandler which takes the http request header and validates the API-key. Pretty common task I guess. In my controller I call my business logic and pass along all business-relevant information. However now I'm challenged with the task to change behavior inside my business logic (separate assemblies) depending on certain api-keys.
Various possible solutions come to my mind...
Change business logic method signatures to ask for an api-key, too.
public void SomeUseCase(Entity1 e1, Entity2 e2, string apiKey);
Use HttpContext.Current to access the current request context. However I read somewhere that using HttpContext restrict my hosting options to IIS. Is there any better suited option for that?
var request = HttpContext.Current.Request; // next extract header information
Use Sessions (don't really want to go that road...)
What's your opinion on that topic?
I'd go for #1 although I don't like the idea of mixing in enivonmental stuff in business logic methods. But depending on your point of view you might argue the api-key is in fact logic-relevant.
Update #1:
I'm using a delegatingHandler to validate the apiKey and once it is validated I add it to the Request's Properties Collection.
The part in question is how the "api-key" or RegisteredIdentifier is passed along to the business logic layer. Right now I am passing the object (e.g. IRegisteredIdentifier) as a parameter to the business logic classes' constructors. I understand there is no more elegant way to solve this(?). I thought about changing the method signatures but I'm not sure whether it's interface pollution or not. Some methods need to work with the api-key, most don't. Experience tells me that the number will more likely grow than drop :) So keeping a reference to it in my bl classes seems to be a good choice.
Thank you for your answers - I think all of them are part of my solution. I'm new to StackOverflow.. but as far as I can see - I cannot rate answers yet. Rest assured I'm still thankful :)
I would suggest two different options.
Promote the value into a custom HTTP header (e.g. something like mycompany-api-key: XXXX ). This makes your delegating handler work more like a standard HTTP intermediary. This would be handy if you ever hand off your request to some secondary internal server.
Put the api-key into the request.Properties dictionary. The idea of the the Properties dictionary is to provide a place to put custom meta information about the request.
HTTP works hard to make sure authentication/authorization is a orthogonal concern to the actual request, which is why I would try and keep it out of the action signature.
I would go for option 1.
But you could introduce the entity RegisteredIdentifier (Enterprise Patterns and MDA by Jim Arlow and Ila Neustadt) in your business logic.
The api-key can be converted to a RegisteredIdentifier.
RegisteredIdentifier id = new RegisteredIdentitief(api-key);
public void SomeUseCase(Entity1 e1, Entity2 e2, RegisteredIdentifier id);
The business logic layer has a dependency on the API key. So I would suggest:
interface IApiKeyProvider
{
string ApiGet { get; }
}
..then have your BLL require that an object implementing that interface is supplied to it (in constructor, setup, or even each method that requires it).
Since in the future it might not be one API key. The key point is that this identifies the BLL is dependent on something, and defining a contract for the something.
Real-world example:
Then, in your DI container (Ninject etc), bind your own ConfigFileApiKeyProvider (or whatever) implementation to that interface, in the "place" (layer) that DOES have the API key. So the app that calls the BLL specifies/configures how the API key is specified.
Edit: I misunderstood the part about this being a "how-to-do-it-over-HTTP" question and not a code architecture/code design question. So:
HTTP header is the way to go in terms of transport