Generate a response without stripping off default values in protobuf - clojure

We have a API where we send the response by parsing it with protobuf contracts and we send the result to the consumers. It strips of some of the fields which has default values(0 for integer, false for boolean etc.) but we don't want to allow that behaviour.
Is there a way that we can either stop protobuf from stripping the default values in response or maybe construct a response with all the default values and merge it with our regular response so that we can send back those fields with default values?
For example, if we have
{"foo": 0.0, "bar": false, "baz": "abc"}
in the response we only get
{"baz": "abc"}
because protobuf strips off the values. But, we also want to get full response with zero values.
We are using below clojure snippet to generate the JSON:
(-> (JsonFormat/printer)
(.print proto)
(json/parse-string true))

(-> (JsonFormat/printer)
(.includingDefaultValueFields)
(.print proto)
(json/parse-string true))
calling (.includingDefaultValueFields) does the trick.

Related

Why Is My Django Post Request Sending Incorrectly Parsed My List of Dictionaries?

Here is my Django view:
def sendMail(request):
url = 'https://example.com/example'
dictwithlist = request.FILES['dictwithlist']
parsed = json.load(dictwithlist)
// the log file shows that the lists are intact after json.loads
logip(request, json.loads(parsed))
x = requests.post(url, json.loads(clockoutJSON))
return HttpResponse(status=204)
If I just send parsed data my express server receives an empty dict, {}. When I log the json.loads(parsed) I find good data, with the lists intact. When the data gets to the other side though, the dictionaries inside the nested list are all removed, replaced by only strings of their keys.
I tried using headers as described here: Sending list of dicts as value of dict with requests.post going wrong but I just get 500 errors. I don't know if I'm formatting the headers wrong or not. (because the code has line spacing and I'm copying it)
Can anyone help me understand why this is failing? I need that list to get through with its dictionaries intact.
I believe you may need to use dumps rather than loads when sending the request:
x = requests.post(url, json.dumps(parsed))
Alternatively if you're using the python requests library you can send json as a dict as below:
response = requests.post(url=url, json=parsed)

QueryDict getlist returns empty list

I'm sending from frontend object with one property which equal to array.
In backend I need to get data from that array.
when i write request.POST i see:
<QueryDict: {u'response[0][doc_id]': [u'14'], u'response[1][uuid]': [u'157fa2ae-802f-f851-94ba-353f746c9e0a'], u'response[1][doc_id]': [u'23'], u'response[1][data][read][user_ids][]': [u'9'], u'response[0][uuid]': [u'8a0b8806-4d51-2344-d236-bc50fb923f27'], u'response[0][data][read][user_ids][]': [u'9']}>
But when i write request.POST.getlist('response') or request.POST.getlist('response[]') i get
[]
request.POST.get('response') doesn't work as well (returns None).
What is wrong?
Because you don't have either response[] or response as keys, you have the literal strings response[0][doc_id] and response[1][uuid] etc.
If you want to use a structure like this, you should send JSON rather than form-encoded data and access json.loads(request.body).

Pass multiple query parameter values with clj-http

I need to make a web request to an external service (Twilio), with multiple values specified for the same parameter, e.g.
GET /some-url?status=1&status=2&status=3
How do I tell clj-http to encode the request like this?
You can put multiple values for your :query-param value inside of sequential:
(client/get
"http://yoursite.com/some-url"
{:query-params {"status" [1 2 3]}
:debug true})

Testing multiple JSON lines response

I am trying to make a test in Postman to verify some content in a JSON response. If I just try to verify a single line from the JSON response everything is fine. My problem starts when I need to test multiple lines of the JSON response. Is always failing. Any suggestion?
tests["Body matches string"] = responseBody.has("\"name\": null,
\"nameType\": \"NON_REFUNDABLE\"");
If I understand your question correctly I'd like to suggest that you approach this in a different way.
Instead of looking at the entire response body and seeing if the strings match you could alternatively test the individual Json properties that make up the response body. For example you could do the following:
var data = JSON.parse(responseBody);
tests["name is null"] = data.name === null;
tests["nameType is non-refundable"] = data.nameType === "NON_REFUNDABLE";
There are other alternatives as well but this is the first that comes to mind. For some more ideas about testing using postman check out their documentation and examples.

Determine the requested content type?

I'd like to write a Django view which serves out variant content based on what's requested. For example, for "text/xml", serve XML, for "text/json", serve JSON, etc. Is there a way to determine this from a request object? Something like this would be awesome:
def process(request):
if request.type == "text/xml":
pass
elif request.type == "text/json":
pass
else:
pass
Is there a property on HttpRequest for this?
'Content-Type' header indicates media type send in the HTTP request. This is used for requests that have a content (POST, PUT).
'Content-Type' should not be used to indicate preferred response format, 'Accept' header serves this purpose. To access it in Django use: HttpRequest.META.get('HTTP_ACCEPT')
See more detailed description of these headers
HttpRequest.META, more specifically HttpRequest.META.get('HTTP_ACCEPT') — and not HttpRequest.META.get('CONTENT_TYPE') as mentioned earlier
As said in other answers, this information is located in the Accept request header. Available in the request as HttpRequest.META['HTTP_ACCEPT'].
However there is no only one requested content type, and this header often is a list of accepted/preferred content types. This list might be a bit annoying to exploit properly. Here is a function that does the job:
import re
def get_accepted_content_types(request):
def qualify(x):
parts = x.split(';', 1)
if len(parts) == 2:
match = re.match(r'(^|;)q=(0(\.\d{,3})?|1(\.0{,3})?)(;|$)',
parts[1])
if match:
return parts[0], float(match.group(2))
return parts[0], 1
raw_content_types = request.META.get('HTTP_ACCEPT', '*/*').split(',')
qualified_content_types = map(qualify, raw_content_types)
return (x[0] for x in sorted(qualified_content_types,
key=lambda x: x[1], reverse=True))
For instance, if request.META['HTTP_ACCEPT'] is equal to "text/html;q=0.9,application/xhtml+xml,application/xml;q=0.8,*/*;q=0.7". This will return: ['application/xhtml+xml', 'text/html', 'application/xml', '*/*'] (not actually, since it returns a generator).
Then you can iterate over the resulting list to select the first content type you know how to respond properly.
Note that this function should work for most cases but do not handle cases such as q=0 which means "Not acceptable".
Sources: HTTP Accept header specification and Quality Values specification
in django 1.10, you can now use, request.content_type, as mentioned here in their doc