How defensive to be when interacting with another internal microservice? - microservices

In this scenario there are two HTTP microservices:
The public service that provides the client with data
The internal microservice that authenticates calls to the public service
Service 1 makes a call to Service 2 to ask it to authenticate the token provided to it by the client.
The agreement ("contract") is that Service 2 should reply with 200 OK and JSON content about the authenticated user.
In Service 1, if it receives the response 200 OK, is it worth going any further to validate the response further?
For example, the JSON body of the response is parsed into an object. Is there value in checking if that object was correctly instantiated instead of being set to null? Or alternatively should that be left to integration tests?

Strictly, a 200 only means that the request was successfully processed. This is regardless of the actual outcome of the call from a business perspective.
You are in effect relying on a convention of "we will throw an exception or otherwise fail the call if the user is not authenticated", to authenticate users.
Depending on the convention, you could conceivably have a scenario where a user was unauthenticated but the call was still successfully processed.
From this perspective, it may be worth having the service2 return a response which could then be interrogated to close this circle.
Alternatively, you could have the client call the authentication service directly, retrieve a token, and then present this token with any other request. This would mean that service1 is no longer responsible for having to know that a caller is authenticated.
The question is whether or not to then test in Service 1 each time the
response is received
Sorry, I would appear to have misunderstood the spirit of the question somewhat.
I am slightly confused - are you asking that, if the system under test is service1 then should any response from service2 also be part of that test?
I would say you would have to have some test which could prove that the sercvice2 response interrogation logic is correct, but this could be done at the unit test level. I don't think you'd need to do this for tests running against a deployed instance of the service, which is by nature more about the service behaviour at the boundary rather than internally.

Well your approach is not that bad!
Some of the HTTP status codes are reserved for cases of malformed requests etc. but in your case, you ask Service2 to return information for a token! If that token exists, you specified correctly, that Service2 has to return 200 OK. Now you just need to specify what happens if the token is not valid anymore or if it does not exists (or treat both cases the same...). If you specify, that Service2 has to return 404 Not found if it does not know the token or that the token expired, there (in most cases) is no need for Service1 to go any further! Parsing the status code is cheap in almost any language/environment, but forcing the deserialization of the content in both success and error cases is in comparison very expensive. Authentication needs to be fast - so I'd go for the status code here!
The key is, that this behavior has to be specified somewhere! (We went for swagger definitions!)

Related

HTTP Status to return if resources are partially created in Spring boot - rest api?

I've a scenario where a post request from first microservice creates new user and creates a wallet for newly created user from different microservice.
I'm returning HTTP status 201 when both user and wallet created. I'm bit confused what status should I return if user is created but wallet isn't.
I came across some articles and found two relevant to my confusion but are contradictory on returning HTTP status 207 due to its limitation related to WebDAV.
Is Http response 207 MULTI-STATUS appropriate for multi task operations?
REST API response in partial success
refer my code -
#PostMapping("/register")
public ResponseEntity<User> saveUser(#RequestBody User user) {
user.setUserId(sequenceGeneratorService.generateSequence(User.SEQUENCE_NAME));
user.getRoles().forEach(role -> role.setRoleId(sequenceGeneratorService.generateSequence(Role.SEQUENCE_NAME)));
User savedUser = userService.saveUser(user);
ResponseEntity<Wallet> createdWallet = createUserWallet(savedUser);
if (createdWallet.getStatusCode().is2xxSuccessful()) {
savedUser.setWallet(createdWallet.getBody());
return new ResponseEntity<User>(savedUser, HttpStatus.CREATED);
} else {// here is the confusion
return new ResponseEntity<User>(savedUser, HttpStatus.MULTI_STATUS);
}
}
private ResponseEntity<Wallet> createUserWallet(User savedUser) {
Wallet userWallet = Wallet.builder()
.walletId(sequenceGeneratorService.generateSequence(Wallet.SEQUENCE_NAME))
.userId(savedUser.getUserId())
.balance(BigDecimal.ZERO).build();
return walletServiceProxy.createWallet(userWallet);
}
May I know which status should I return here?
I'm returning HTTP status 201 when both user and wallet created. I'm bit confused what status should I return if user is created but wallet isn't.
HTTP status codes are metadata of the transfer-of-documents-over-a-network domain (see Webber 2011); they are there so that general purpose HTTP components can correctly interpret the response, and do intelligent things (like invalidating previously cached responses, when appropriate).
Your HTTP API is a facade: a costume that your implementation wears that makes it look like an HTTP aware document store. (The fact that your implementation doesn't have "documents" is an implementation detail, hidden behind this facade.)
The responses you send should be understood in this same way - you are telling the HTTP client (and also any intermediary components who can read the response metadata) how your (imaginary) web page reacted to the request that was sent.
Was the message processed successfully? Did it create a new (imaginary) web page with its own identifier, that clients can send messages to? Then you should normally be sending back a 201 Created, even if the implementation didn't achieve that outcome via the "happy path".
On the other hand, if you want general purpose components to understand that request processing failed, you send a 4XX Client Error or a 5XX Server Error, as appropriate.
(You probably shouldn't be using 207 MultiStatus unless you are deliberately doing WebDav things and are expecting requests from WebDav aware components; it doesn't achieve anything useful unless the client implementation knows how to handle multistatus XML documents).
Reminder: the part of an HTTP response where you describe in detail what happened and how the end consumer can respond to it is the body of the HTTP response.
201 Created
Location: /users/12345
Content-Type: text/plain
Hey, we created the new user you asked us to. Isn't that great?
You can review the details of the user at: /users/12345
But, we weren't able to create a wallet for the user. If that's
kind of important to you, could you fill in this form and send it
to us: /lost-wallets#form ?
Thanks, and have a great day

405 Method is not Allowed exception: "Request Method 'T' not supported" for GET call and "Request Method 'ST' not supported" for POST

I am facing a very strange issue in my project. It is related to rest API call using spring reactive webclient bulider. It is working fine on local and prod as well but abnormally giving below error after 3 or 4 request to same endpoint.
"org.springframework.web.server.MethodNotAllowedException: 405 METHOD_NOT_ALLOWED "Request method 'T' not supported"
This is valid exception as method going to "T" for Get method and "ST" for Post method .I am not able to understand why two starting charcter truncating from method name
Please help me resolve this error.
OP and I must have been the only ones to have ever experienced this and honestly I don't know the root cause but this was my situation and the fix.
For me, I was running 2 services in a docker. One service would make requests to the other. The 1st request always succeeds but the subsequent one always fails. After some time, a new request succeeds again.
I speculated that it must have to do with a persistent connection. I am using OkHttpClient library (3.14.9) to make the request. The service receiving the request was running spring webflux but I don't think the service was the issue. I could make repeated successful requests to it using curl from inside the 1st service's container.
OkHttpClient uses keep-alive connections by default. You can specify for a single request that you don't want to keep connection alive by setting the Connection header to close. Once I did that, all requests were working again.
For whatever reason, the re-use of the keep-alive connections was not sending over over and entire request. It was always truncating the first 2 characters of the method that is why Request method 'T' not supported. Perhaps the 1st request didn't end correctly and eats up the 2nd request's first 2 characters. I don't know the root cause. Probably a bug with OkHttpClient

What's the appropriate HTTP status code to return if a user tries logging in with an incorrect username / password, but correct format?

A similar question is posted here: What's an appropriate HTTP status code to return by a REST API service for a validation failure?
The answer in the thread above states that "For instance if the URI is supposed to have an ISO-8601 date and you find that it's in the wrong format or refers to February 31st, then you would return an HTTP 400. Ditto if you expect well-formed XML in an entity body and it fails to parse."
However, what happens if the user submitted correctly formatted data? By this I mean, the user submitted a plain alphabetical string / text for the username and password (which is perfectly valid for my application). The only issue is that the password did not match with the username. In this case, 400 will be incorrect because it is perfectly valid syntax and well-formed.
A 401 would be incorrect (as suggested here: Which HTTP status code to say username or password were incorrect?) because the user is not trying to access any page, he is simply trying to login and entered data which does not match.
If you look back at the first post I linked to, the second answer states that 422 is the correct response (and it looks correct to me), however, I am using Django Rest Framework and 422 is not part of the status codes (a list of the status codes which are part of DRF can be found here: http://www.django-rest-framework.org/api-guide/status-codes/#client-error-4xx)
404 also doesn't look right because the data is successfully accepted and not refused.
With that said, what is the real correct response which should be used?
If you are strictly using the HTTP authentication framework provided by RFC 7235 for your REST API, the correct HTTP code would actually be 401. From the RFC:
The 401 (Unauthorized) status code indicates that the request has not been applied because it lacks valid authentication credentials for the target resource. The server generating a 401 response MUST send a WWW-Authenticate header field (Section 4.1) containing at least one challenge applicable to the target resource.
If the request included authentication credentials, then the 401 response indicates that authorization has been refused for those credentials. The user agent MAY repeat the request with a new or replaced Authorization header field (Section 4.2).
Your REST API should employ an authentication scheme of some sort in order to return a valid 401 response to your client.
Another pertinent section from RFC 7235, page 4:
Upon receipt of a request for a protected resource that omits
credentials, contains invalid credentials (e.g., a bad password) or
partial credentials (e.g., when the authentication scheme requires
more than one round trip), an origin server SHOULD send a 401
(Unauthorized) response that contains a WWW-Authenticate header field
with at least one (possibly new) challenge applicable to the
requested resource.
A higher-level response, such as a rendered login page for a visual user (redirected from a protected resource via 302), would be better served with the 200 status code (per #KernelDeimos' answer, for example). Since login pages are typically their own resource (e.g. /login?redirect=original-resource), the unauthenticated user is still authorized to see this page, even if they provide an incorrect username/password. Then, you redirect the authenticated user back to the resource, at which point would show 200 if allowed, or 403 if the user is forbidden to view the resource.
The area where 401 could come into play with a visual login page is a front-end library that leverages the REST API using XHR requests, then relay the 401 response from the REST API back into a meaningful format on the login page.
If login is handled at a higher-level (ex: sending a POST to the server with a username and password), use the appropriate status code in 2xx for a successfully handled login request with the wrong password. If using the HTTP authentication framework provided by RFC 7235, send 401 (see answer by #sjagr for further detail).
Below the line is the rest of my original answer, which explains my train of thought. Also note the thread on sjagr's answer which includes a debate which improved both our answers and a comment from Julian Reschke (one of the RFC's authors).
Before asking "what is the correct HTTP status code", it's important to consider this question: "Should success or failure of login be reflected in the HTTP status code of the response?"
In #sjagr's answer the first part of this section is highlighted. I'm going to highlight the second part and explain why:
If the request included authentication credentials, then the 401 response indicates that authorization has been refused for those credentials. The user agent MAY repeat the request with a new or replaced Authorization header field (Section 4.2).
This refers to an Authorization header, rather than a request body containing login credentials. The phrasing of the first part, unfortunately, could be misinterpreted to refer to a request body containing login information. This ambiguity can be resolved by considering separation of concerns; (https://en.wikipedia.org/wiki/Separation_of_concerns) the server's response header should not depend on the differences of two valid request bodies, with the exception of when it causes an internal server error, otherwise the concerns of data transfer and appliction login begin to creep into each other.
I would use HTTP response 2xx for a valid login request, where the client has permission to attempt a login, that is handled successfully with a response indicating success or failure.
I also like the way #spectras expressed this in the comments:
Attempting to express an application-level error in a transport-level status code is a design mistake.
401 - Unauthorized
403 - Forbidden
http://www.buggybread.com/2012/11/http-error-codes-401-access-denied-403.html
If you try to log into a Google account with the wrong password, it will return a 200 response containing data that indicates the password was incorrect. For that reason, I just use a 200.
At the end of the day, which status code you use is purely a semantic issue and isn't going to change the functionality of your application. What really matters is that your application displays the correct information to the user.
I think what causes all the confusion is that there are two entities that need to be authenticated. One is the client (front-end app) needs to authenticate itself, that its authorized to make a login request for the user, and then the user needs to authenticate itself with his username/password.
The status code should only be related to the client making the request, not the user.
From https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
HTTP response status codes indicate whether a specific HTTP request has been successfully completed.
200 is correct:
Given that you have a front-end application that talks to the backend, the appropriate respond code should be 200 and the response body should contain the information if password matches or not, but that result has no impact on the status code, because the request itself was authorized and successfully parsed.
401 is wrong:
Assume your front-end authenticates with a token for example, then the response code 401 would mean the front-end token is invalid, not the password of the user inside that request.
403 is wrong: Assume your front-end authenticates with a token for example, then the response code 403 would mean the token is vaild, but that token does not have the access right to ask if password/username match.

How to handle status codes with .NET web API?

I'm new to the .NET web api. But I can't figure out what the best practice should be when returning status codes. I've followed the tutorial on creating a web api that supports crud operations to get a good idea on how it all works.
I have a spec where the response to every request returns a status code along with other data, I can change the spec if need be but I can't work out if it's good to return a status code and also return all the data requested or to just return the data on it's own.
For example if I made a request to GetAllCarManufacturers without being authenticated I'd return a custom statusCode of 1 (Indicating not authenticated), and message "User is not authenticated.". But if I was authenticated I'd like to send back a statusCode of 0 (indicating success) and all the car manufacturers. This seems to go against the way the tutorial is organised as only the car manufacturers are sent back without any additional data. Which leads me to believe passing around a statusCode isn't the correct thing to do.
I've seen in the example crud demo that HttpResponseExceptions are thrown which sets the HttpStatusCode to a certain value (see code below). Should I be using that instead of returning my own status code? But then my concern is it doesn't have enough different status codes that will match my custom scenarios.
// Setting the HTTPStatusCode example.
throw new HttpResponseException(HttpStatusCode.NotFound);
.NET Web API sets up a convention for HTTP calls to a server that supports a REST interface. So, if you follow the convention, you should return HTTP Status Codes as a way of indicating what happened to the request when the server processed it.
HTTP Status Codes are part of the HTTP spec and can be found here.
There are many benefits to using HTTP Status Codes. One is that the HTTP Status Code is a header, so the client doesn't have to look into the content of the response in order to find out what happened.
So, returning a custom status code (of say 0 or 1) is not very useful to HTTP clients if they expect a RESTful experience from your interface.

Http status code for bad params in post request

I have a server in which the client can register itself as a device (like a mobile device). For the registration, the device must be associated with another resource (say an user) which is already registered on the server. To do that, the client sends a Http Post request to the server, with two params, its own ID and the associated resource ID.
I need to choose an Http Status code to return when the client ask the server to do some procedure and one of the resources indicated in the parameters are not found.
I suggested 404, but my professor said that 404 is used the resource associated to the URI is not found, not when you submit a well-formed request with bad parameters.
What is the most suitable http status and why would you choose?
In my opinion, it fits to:
400 - Bad Request
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.
OR
403 - Forbidden
The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. If the server does not wish to make this information available to the client, the status code 404 (Not Found) can be used instead.
Ref: fc2616
I would use 403 'Forbidden' - meaning, you are forbidden from accessing the page with the request you have sent

Resources