skip to Main Content

I’ve been trying unsuccesfully to make a POST request to my API end point, and I always get an error. My setup is a django server with a rest API, and I’m trying to add a reservation to the Booking Model, using fetch.

This is the code inside my "onSubmit" js function (when the submit button is clicked):

                csrf = document.getElementsByName("csrfmiddlewaretoken")[0].value;
                const formdata = new FormData(form);
                fetch('/api/booking/', {
                    method: 'POST',
                    headers: {
                        "X-CSRF-Token":csrf,
                        "Content-Type": "application/json"
                    },
                    credentials: "same-origin",
                    body: formdata
                })
                .then(res => res.json())
                .then(data => console.log(data));

models.py

class Booking(models.Model):
    client = models.ForeignKey(User,  on_delete=models.CASCADE, null=True)
    date = models.DateField(null=True)
    hour = models.SmallIntegerField(
        null=False,
        default=12,
        validators=[ #from 8am to 10pm
            MaxValueValidator(22),
            MinValueValidator(8)
        ],
    )
    
    class Meta:
        unique_together = ('date', 'hour')

forms.py

class BookingForm(ModelForm):
    class Meta:
        model = Booking
        fields = ['date', 'hour', 'client']

views.py (of the api endpoint /api/booking/

class BookingView(generics.ListCreateAPIView):
    queryset = Booking.objects.all()
    serializer_class = BookingSerializer

So this is the error I get in the Chrome JS console:

book:159     POST http://127.0.0.1:8000/api/booking/ 400 (Bad Request)
onSubmit @ book:159
book:169 {detail: 'JSON parse error - Expecting value: line 1 column 1 (char 0)'}detail: "JSON parse error - Expecting value: line 1 column 1 (char 0)"[[Prototype]]: Object

Any idea what is the problem?

2

Answers


  1. Your content type for the body is JSON but you are trying to send FormData. Convert the FormData to JSON first before putting it in the request body.

    var object = {};
    formdata.forEach(function(value,key){
    object[key] = value});
    
    fetch('/api/booking/', {
       method: 'POST',
       headers: {
          "X-CSRF-Token":csrf,
          "Content-Type": "application/json"
           },
       credentials: "same-origin",
       body: JSON.stringify(object)
       })
    
    Login or Signup to reply.
  2. csrf is not required in REST APIs services. Thus, you do not need to set any headers in your request. Although, you have an authentication system in place and your view just does not know how to handle it:

    class BookingListCreateAPIView(ListCreateAPIView):
        queryset = Booking.objects.all()
        serializer_class = BookingSerializer
        authentication_classes = [BasicAuthentication]
    

    Aside from that it is always good practice to use the latest features such as arrow functions and async/await, introduced with ES6. That being said, your template should be similar to this:

    <body>
        <form>
            {{form}}
            <input type="button" value="Submit" onclick="sendForm()">
        </form>
    
        <script>
            const sendForm = async (event) => {
                const url = 'http://localhost:8000/api/bookings/';
    
                const formElement = document.querySelector("form");
                const formData = new FormData(formElement);
                
                const res = await fetch(url, { 
                    method: "POST", 
                    body: formData 
                });
    
                if (res.status === 201) {
                    console.log('Booking successfully created!');
                }
            }
        </script>
    </body>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search