django-rest-framework accept JSON data? - python

I have created RESTFul APIs using django-rest-framework. The user endpoint is: /api/v1/users
I want to create a new user, so I send the user data in JSON format:
{
"username": "Test1",
"email": "test1#gmail.com",
"first_name": "Test1",
"last_name": "Test2",
"password":"12121212"
}
I am using Google Chrome extension Postman to test the API. But, after sending the request, the user data is not saving. The response contains this error:
{
"detail": "Unsupported media type \"text/plain;charset=UTF-8\" in request."
}
This is what the request details look like in Postman:

You have missed adding the Content-Type header in the headers section. Just set the Content-Type header to application/json and it should work.
See the below image:
Also, you might also need to include a CSRF token in the header in case you get an error {"detail": "CSRF Failed: CSRF token missing or incorrect."} while making a POST request using Postman. In that case, add an X-CSRFToken header also with value as the CSRF token value.

I'm posting this answer in case someone is facing a problem like mine.
I'm working on a Front-End app using Angular 2 with an API made with Django Rest Framework and I used to send requests with the following headers:
'Content-Type': 'application/json'
And it was working fine until I tried it on Fire Fox and I couldn't load the needed data and I solved it with adding the following headers
'Content-Type': 'application/json',
'Accept': 'application/json'
Here's an explanation, Content-Type tells the server what is the content type of data is while Accept tells it what content type the client side will accpet.
Here's a nice clear answer about this issue:
https://webmasters.stackexchange.com/questions/31212/difference-between-the-accept-and-content-type-http-headers

You need to do two step to done this issue:
Add Content-Type header with application/json value
Add Authorization header with Token {YOUR_CUSTOM_TOKEN} value to pass CSRFToken
Note: if you want to authenticate with session, you don't need to do second step, but if you want use this API for mobile, you have to pass Authorization header to server
I hope it helps

You need to define content type by setting the appropriate headers. In case of Postman you need to set the following values under url field:
Header: "Content-Type"
Value: application/json

I had to add the following to get this to work (I'm using node-fetch btw from the client side to do a POST):
supportHeaderParams: true,
headers: { "Content-Type": "application/json; charset=UTF-8" },

Couple of things to do if you want to accept JSON Data using Django Rest Framework.
Make sure application/json headers are sent:
'Content-Type: application/json'
JSON Parser is selected in settings.py
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
],
}

Related

How to return a bearer JWT token FROM Flask?

How to form a response from Flask python server which would contain the bearer token in the response. More precisely, I am looking to somehow securely propagate the JWT token from Flask python server back to the client (angular page). I can just return it in form of the querystring in GET redirect. What are other possibilities in terms of returning the JWT access token back to the client? I tried setting the response form python, and to set the jwt token in Authorization field, but nothing worked. This is what I tried:
1.
r = Response(headers={
"Authorization": "bearer jwtcntent",
"Access-Control-Allow-Origin": "*",
},
is_redirect=True,
url="https://localhost:5000/callback",
)
return r
r = redirect("http://localhost:5000/callback")
r.headers = {"authorization": "bearer jwtcntent"}
return r
r = Response(headers={
"Authorization": "Bearer jwtcntent",
"Access-Control-Allow-Origin": "*",
},
allow_redirects=True,
url="https://localhost:5000/callback",
)
return r
Any recommendations?
You can store it in an httponly cookie, but you need to make sure to handle CSRF attacks if you do so. Flask-JWT-Extended has built in support for this which you might find useful, either as a solution or as a reference for whatever you end up doing:
https://flask-jwt-extended.readthedocs.io/en/stable/token_locations/#cookies
You can also just send the token back as part of the JSON body and then storing it in local/session storage, which is probably the most common pattern.
Are you able to implement a regular OAuth flow in your Authorization Server? OAuth flows are standardized and use secure ways of returning an access token to the client.
I don't recommend using the Authorization header for returning responses. This header is a request header, it has no meaning in a response. If you really need to do it through the header you can add Access-Control-Expose-Headers header to let your client read the Authorization header from a response.

Access JWT access_token_cookie with javascript

I have set up a JWT authentication system for my web application, however I have run into issues whilst trying to implement CSRF protection.
I am POST(ing) the data with the X-CSRF-TOKEN.
let request = $.ajax({
type: "POST",
data: $form.serialize(),
headers: {
"X-CSRF-TOKEN": json_form["csrf_token"],
"Authorization": authHeader
}
})
(json_form: form data converted to json obj)
However I dont know how to access the access_token_cookie.
The HTTP request contains this cookie, however document.cookie does not, I assume this is because the JWT is not sent as part of the response?
My question then is this: how does one access the JWT?
I assumed it would be a matter of accessing this cookie straight from the browser with JS.
Otherwise maybe I could send the JWT as a header with each response, but I have a sneaking suspicion that is superfluous().
My gratitude in advance.

How to fix 'Unsupported media type" error on python POST request to Twilio

I have been following Twilio's Quickstart page for their Functions API.
I am stuck at the part where I am supposed to manually upload the Function JS file.
Their POST examples use cURL and node.js but I am using Python 3.6:
# Manually upload the subscription function file
upload_url = f'https://serverless-upload.twilio.com/v1/Services/{sub_service_sid}/Functions/{sub_function_sid}/Versions'
function_request = requests.post(
upload_url,
files = {'subscription_function_file': open('subscriptionFunction.js', 'rb')},
auth = (account_sid, auth_token),
headers = {
'content-type': 'application/javascript',
'path': '/subscription-function',
'visibility': 'public'
}
)
In both examples, they declare the content type as application/javascript. However, I get this error when I do the same:
{"status":415,"message":"Unsupported media type","detail":"The server does not support the media type transmitted in the request.","code":20415,"moreInfo":"https://www/twilio.com/docs/errors/20415"}
That URL throws a 404 so I went digging in Twilio's Error Dictionary but that code is not listed. Furthermore, application/javascript is absent from their supported media types page.
Am I uploading the file incorrectly? Or is their tutorial wrong?
Twilio developer evangelist here.
I think you may have translated some of the curl request to the wrong parts of a request made with requests and I think this is causing the issue. You don't want to set the request type to be application/javascript that wants to be the type of the file you are uploading. You can set this as part of the files tuple.
You don't want to send the other bits of data, Path and Visibility as headers either, they should be part of the data so they become part of the request body.
Try something like this instead:
upload_url = f'https://serverless-upload.twilio.com/v1/Services/{sub_service_sid}/Functions/{sub_function_sid}/Versions'
files = { 'Content': ('subscriptionFunction.js', open('subscriptionFunction.js', 'rb'), 'application/javascript') }
function_request = requests.post(
upload_url,
files = files,
auth = (account_sid, auth_token),
data = {
'Path': '/subscription-function',
'Visibility': 'public'
}
)
Let me know if that helps.

Python Connexion: Automatically validate Accept header

I'm using the Connexion framework for my Python Flask project. In the API spec (using the yaml file format) I defined "consumes" and "produces" field like this:
produces:
- application/json
consumes:
- application/json
The Connexion documentanation says that Connexion automatically validates the request based on the API specification, so I thought that it would automatically verify that incoming "Accept" (or "Content-Type") headers would match "application/json" using the above data as example.
However, this doesn't seem to be the case. If I omit the Accept header and Content-Type header, or add them with random values, there are no warnings or errors or anything.
Have other Connexion users gotten Connexion to validate media types data? Or do you handle this explicitly in your code?
EDIT: Seems like this bug report addresses this issue.
I'm using the versions:
connexion == 1.5.3 swagger
spec-validator == 2.4.0
When I execute an operation in this scenario where I wait for "application/json" and send a different Content I get a 415 with the body:
{
"detail": "Invalid Content-type (application/javascript), expected JSON data",
"status": 415,
"title": "Unsupported Media Type",
"type": "about:blank"
}
In this case i sent a request with the Content "application/javascript"

How to return multiple cookies with AWS APIGateway and Lambda?

I am trying to return two cookies from Lambda to client(Postman) via APIGateway.
I referred to the aws blog, and could return 1 cookie to client.
https://aws.amazon.com/jp/blogs/compute/simply-serverless-using-aws-lambda-to-expose-custom-cookies-with-api-gateway/
But I have no idea to return 2 kind of cookies.
I tried like this, but not working.
return {
'cookie': 'aaa=bbb; secure' -> Okay, but just one cookie
# 'cookie': 'aaa=bbb; ccc=ddd; secure' -> ×
# 'cookie': ['aaa=bbb','ccc=ddd'] -> ×
}
Could anyone give me an advise?
As far as I can tell, you can't set multiple cookies in the same Set-Cookie header. There's literature on the internet saying that you can, but my attempts to replicate this in API Gateway were fruitless.
Additionally, at the time of writing, API Gateway doesn't allow you to set multiple Set-Cookie headers. This has been a long-requested and still not implemented feature.
If you can, I'd suggest packing all your information into a single object and sending the JSON in one cookie.
If you really need to though, here is a disgusting workaround...
API Gateway's response headers are case-sensitive, so you can define multiple instances of the set-cookie header by varying the case, like this:
Set-Cookie
SET-COOKIE
SeT-CoOkIe
Setup mapping with Response header Set-Cookie and mapping value “integration.response.multivalueheader.Set-Cookie”
source "https://medium.com/nirman-tech-blog/aws-gateway-api-endpoints-multi-value-cookie-mapping-a36586cebd5e"
With the Lambda function response for format 2.0, as stated in the official documentation, to customize the response, your Lambda function should return a response with the following format.
{
"cookies" : ["cookie1", "cookie2"],
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headername": "headervalue", ... },
"body": "Hello from Lambda!"
}

Categories

Resources