django-ninja icon indicating copy to clipboard operation
django-ninja copied to clipboard

Bad request

Open chrisbodon opened this issue 2 years ago • 2 comments

When I send a post of only text values, it works. The same when I send only a image file. But I´m getting this error when I send a mix of both: POST http://127.0.0.1:8000/api/towns 400 (Bad Request)

o {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
code: "ERR_BAD_REQUEST"
config:
adapter: Æ’ (e)
data: FormData {}
env: {FormData: null}
headers: {Accept: 'application/json, text/plain, */*'}
maxBodyLength: -1
maxContentLength: -1
method: "post"
timeout: 0
transformRequest: [Æ’]
transformResponse: [Æ’]
transitional: {silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false}
url: "http://127.0.0.1:8000/api/towns"
validateStatus: Æ’ (e)
xsrfCookieName: "XSRF-TOKEN"
xsrfHeaderName: "X-XSRF-TOKEN"
[[Prototype]]: Object
message: "Request failed with status code 400"
name: "AxiosError"
request: XMLHttpRequest {onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}
response:
config:
adapter: Æ’ (e)
data: FormData {}
env: {FormData: null}
headers: {Accept: 'application/json, text/plain, */*'}
maxBodyLength: -1
maxContentLength: -1
method: "post"
timeout: 0
transformRequest: [Æ’]
transformResponse: [Æ’]
transitional: {silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false}
url: "http://127.0.0.1:8000/api/towns"
validateStatus: Æ’ (e)
xsrfCookieName: "XSRF-TOKEN"
xsrfHeaderName: "X-XSRF-TOKEN"
[[Prototype]]: Object
data: {detail: "Cannot parse request body ('utf-8' codec can't decode byte 0xff in position 285: invalid start byte)"}
headers: {content-length: '114', content-type: 'application/json; charset=utf-8', cross-origin-opener-policy: 'same-origin', date: 'Tue, 16 Aug 2022 07:50:01 GMT', referrer-policy: 'same-origin', …}
request: XMLHttpRequest {onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}
status: 400
statusText: "Bad Request"
[[Prototype]]: Object
[[Prototype]]: Error
constructor: Æ’ o(e,t,n,r,o)
toJSON: Æ’ ()
isAxiosError: true
[[Prototype]]: Object

Maybe it´s because of how I build the FormData? This is my code. HTML & JS:

 townForm.addEventListener("submit", (event) => {
        event.preventDefault();
        let values = document.querySelectorAll('#town-form .data');
        postImages(values, "towns");
    });

    function postImages(values, url) {
        console.log(`inputFile-> `, inputFile.files[0]);
        const image = inputFile.files[0];

        let object = {};

        let valuesArray = Array.prototype.map.call(values, function (element) {
            return element;
        });

        for (element in valuesArray) {
            if (valuesArray[element].value === "true") {
                object[valuesArray[element].id] = true;

            } else if (valuesArray[element].value === "false") {
                object[valuesArray[element].id] = false;

            } else if (valuesArray[element].id === "youtube_video_code") {
                object[valuesArray[element].id] = youtube_parser(valuesArray[element].value);

            } else {
                object[valuesArray[element].id] = valuesArray[element].value;
            }

        }
        console.log(`object-> `, object);
        const data = JSON.stringify(object);

        console.log(`data-> `, data);
        formData.append("data", data);
        formData.append("image", image);
        console.log(`formData-> `, formData);
        let requestURL = 'http://127.0.0.1:8000/api/' + url;

        axios.post(requestURL, formData)
            .then(function (response) {
                console.log(response);
                $('#success-toast').toast('show');
            })
            .catch(function (error) {
                console.log(error);
                $('#error-toast').toast('show');
            });
    }

MODEL:

class Town(models.Model):
	name = models.CharField(max_length=255)
	slug = models.CharField(max_length=255)
	description = models.TextField()
	image = models.ImageField(upload_to=GenericImageUploadTo('image'), null=True)
	thumbnail = models.ImageField(upload_to=GenericImageUploadTo('thumbnail'), null=True)
	youtube_video_code = models.CharField(max_length=255)
	web = models.CharField(max_length=255)
	map_link = models.CharField(max_length=255)
	lat = models.IntegerField(null=True)
	long = models.IntegerField(null=True)
	map_pct_x = models.IntegerField(null=True)
	map_pct_y = models.IntegerField(null=True)
	activated = models.BooleanField(default=False)
	
	def __str__(self):
		return self.name

API URLS:

@api.post("/towns")
def create_town(request, payload: TownSchema):
	obj = Town.objects.create(**payload.dict())
	return {"id": obj.id}

chrisbodon avatar Aug 16 '22 08:08 chrisbodon

from what I see the response from the serve is

"Cannot parse request body ('utf-8' codec can't decode byte 0xff in position 285: invalid start byte)

which probably means that request body is not good... so yeah something with building your formData (BTW it's not even clear where you initialize the formData variable in your code)

vitalik avatar Aug 16 '22 08:08 vitalik

I'm going to take a good look at the FormData building. I initialized it beforehand like this: const formData = new FormData();

Thank you very much for answering so quickly

chrisbodon avatar Aug 16 '22 09:08 chrisbodon