Can someone please clarify what status codes should I expect from following situations? For instance, I am sending POST request with such body format:
{
"id": 321,
"username": "tombrown",
"email": "tombrown#gmail.com",
"password": "qwerty123",
"activated": true
}
So the questions are:
1) Should the server return 400 if I specify data of wrong type, for instance, "id": “threetwoone” instead of int, "activated": “yes” instead of boolean etc. Or server should rather return 422 here?
2) The “id” value should be int, but actually it is long int, e.g. 9223372036854774700.
3) Some fields are missing in the body, e.g. I try to send:
{
"id": 321,
"username": "tombrown",
"activated": true
}
Should these examples cause 400, 422 or some other options? What reaction should be correct?
If the JSON is syntactically invalid, return 400. If JSON is syntactically valid but its content is invalid, return 422 to indicate that the request entity cannot be processed by the server.
See the following quote from the RFC 4918 (for your situation, just read JSON when it says XML):
11.2. 422 Unprocessable Entity
The 422 (Unprocessable Entity) status code means the server
understands the content type of the request entity (hence a
415 (Unsupported Media Type) status code is inappropriate), and the
syntax of the request entity is correct (thus a 400 (Bad Request)
status code is inappropriate) but was unable to process the contained
instructions. For example, this error condition may occur if an XML
request body contains well-formed (i.e., syntactically correct), but
semantically erroneous, XML instructions.
Related
In the case of a data validation error, I want to return HTTP status code 200 (OK) with my own error code.
Following is my sample error response JSON.
HttpStatusCode : 200
Response JSON
{
"isError": true,
"resultInfo": {
"resultCode": "801",
"resultMessage": "Order(s)-RNSIN000001 is already exists!!"
},
"orderStatus": null
}
Can I go with this pattern or It will be a violation of the API response pattern?
I am trying to run a PACT test on the provider side and I don't know how to manipulate the request body that I get from the Pact file. I need to do this because I have to use an id from State step.
In my case, I need to perform a request in State step and afterwards to use the response of that request in the actual Pact verification test. So, I would like to replace a value from the pact file with the one obtained in the State.
Also, for being even more complicated, my body is an XML. So here it is how my pact request looks like:
"request": {
"method": "POST",
"path": "/path/url",
"headers": {
"Content-Type": "application/xml"
},
"body": "<note> <to>John</to> <from>Jane</from> <subject>Reminder</subject> </note>"
}
As I said, in the Provider State I will have a request and the response of this will be let's say 'Mary'. So my question would be how can I replace 'Jane' with 'Mary' in the Pact request body when executing the verification test? Thanks.
I have managed to solve my problem, modifying the request in TargetRequestFilter.
#TargetRequestFilter
public void updateRequest(HttpPost request) {
HttpEntity entity = request.getEntity();
String body = EntityUtils.toString(entity);
body = replace(body, "Jane", "Mary");
entity = new StringEntity(body);
request.setEntity(entity);
}
This piece of code will modify the request right before making the call and will send the desired value instead the one that we have in the Pact file.
Looking at the code in CacheInterceptor I see that response with the code 204 are not cached. Yet I believe 204 are cacheable as discussed here
We use 204 as a response to GET don't indicate an empty response and just recently noticed those are not cached.
There are a number of reasons why.
Why does the implementation behave like this?
Technically, 204s are skipped because the intercept method will only cache responses if promisesBody returns true:
if (response.promisesBody() && CacheStrategy.isCacheable(response, networkRequest)) {
// Offer this request to the cache.
As you might expect, promisesBody returns false for 204 responses, unless they have a Content-length header, or chunked transfer encoding:
/**
* Returns true if the response headers and status indicate that this response has a (possibly
* 0-length) body. See RFC 7231.
*/
...
val responseCode = code
if ((responseCode < HTTP_CONTINUE || responseCode >= 200) &&
responseCode != HTTP_NO_CONTENT &&
responseCode != HTTP_NOT_MODIFIED) {
return true
}
// If the Content-Length or Transfer-Encoding headers disagree with the response code, the
// response is malformed. For best compatibility, we honor the headers.
if (headersContentLength() != -1L ||
"chunked".equals(header("Transfer-Encoding"), ignoreCase = true)) {
return true
}
return false
Why was this design used?
To justify this decision, it's possible that OkHttp's general use case for a cache is to save re-sending large payloads, rather than keeping round-trips to the absolute minimum. In addition, 204 is valid as a response to a GET, but more often used as a response to a POST; it's possible that the design reflects knowledge of this heuristic.
Why hasn't this changed?
Looking through relevant issues, there is one related to changing the default behaviour for certain status codes: OkHttp cache-by-default status codes out of date:
The spec wants these:
200, 203, 204, 206, 300, 301, 404, 405, 410, 414, and 501
which resulted in a test:
assertCached(true, 204);
However, due to the configuration of the mock server, the response used to test is:
HTTP/1.1 204 OK
...
Content-Length: 0
with exactly the unnecessary Content-Length that its own detection requires, and which a valid response should not include.
tl;dr
It's a bug, which nobody who's run into this case has reported.
A 204 is returned when there is no content - "The server successfully processed the request and is not returning any content."
Therefore there is no data to cache if using the code to spec. If you are returning content/data than a 200 would be more appropriate.
The code i am trying with is:-
response = HTTPotion.post(url, [body: "{channel: \"#bot\", username: \"watson\", text: \"test\"}"])
The response i am getting is:-
%HTTPotion.Response{body: "invalid_payload",......, status_code: 400}
You made a successful request, but the body was wrong. In JSON there should be quotes around the field names:
[body: "{\"channel\": \"#{bot}\", \"username\": \"watson\", \"text\": \"test\"}"]
Also the syntax for string interpolation is #{variable_name} for example:
iex(1)> bot = "mybot"
iex(2)> "#{bot}"
Manually encoding JSON is error prone so you probably want to use Poison.
iex(3)> Poison.encode!(%{bot: bot, username: "watson", text: "test"})
"{\"username\":\"watson\",\"text\":\"test\",\"bot\":\"mybot\"}"
Intuit offers these instructions for uploading attachments (which become Attachable objects that can be associated with one or more transactions).
I believe I'm using python's requests module (via rauth's OAuth1Session module—see below for how I'm creating the session object) to generate these requests. Here's the code leading up to the request:
print request_type
print url
print headers
print request_body
r = session.request(request_type, url, header_auth,
self.company_id, headers = headers,
data = request_body, **req_kwargs)
result = r.json()
print json.dumps(result, indent=4)
and the output of these things:
POST
https://quickbooks.api.intuit.com/v3/company/0123456789/upload
{'Accept': 'application/json'}
Content-Disposition: form-data; name="Invoice 003"; filename="Invoice 003.pdf"
Content-Type: application/pdf
<#INCLUDE */MyDir/Invoice 003.pdf*#>
{
"Fault": {
"type": "SystemFault",
"Error": [
{
"Message": "An application error has occurred while processing your request",
"code": "10000",
"Detail": "System Failure Error: Cannot consume content type"
}
]
},
"time": "[timestamp]"
}
I have confirmed (by uploading an attachment through the QBO web UI and then querying the Attachable object through the API) that application/pdf is included in the list of acceptable file types.
At sigmavirus24's suggestion, I tried removing the Content-Type line from the headers, but I got the same result.
Here's how I'm creating the session object (which, again, is working fine for other QBO v3 API requests of every type you see in Intuit's API Explorer):
from rauth import OAuth1Session
def create_session(self):
if self.consumer_secret and self.consumer_key and self.access_token_secret and self.access_token:
session = OAuth1Session(self.consumer_key,
self.consumer_secret,
self.access_token,
self.access_token_secret,
)
self.session = session
else:
raise Exception("Need four creds for Quickbooks.create_session.")
return self.session
What might I be missing here?
EDIT: current area of exploration is here; I just formed the header you see (that has the "INCLUDE" string there) directly. Perhaps I should be using rauth to attach the file...
Without being able to see what code you're using with requests, I'm going to take a shot in the dark and tell you to remove setting your own Content-Type. You probably don't want that. It looks like you want multipart/form-data and requests will set that on its own if you stop fighting it.
It looks like you're missing the boundaries that QuickBooks is expecting (based on what you linked).
---------------------------acebdf13572468
Content-Disposition: form-data; name="file_content_01"; filename="IMG_0771.jpg"
Content-Type: image/jpeg
<#INCLUDE *Y:\Documents\IMG_0771.jpg*#>
---------------------------acebdf13572468--
The first and last line above seem to be what you're missing.