Reputation: 302
I am working on a Quiz Application using DjangoRestFramework and ReactJS. My App is comprised of two apps, api
and frontend
. In my api
app, I have multiple API views for many different things. One of my API Views is called JoinQuiz
. When I call it on my frontend
, I get this error in the console:
Forbidden: /api/join-quiz
[16/Dec/2020] "POST /api/join-quiz HTTP/1.1" 403 58
I don't think my problem is due to a CSRF
error because my other API views are working perfectly fine. I may be wrong on this point.
[16/Dec/2020] "GET /api/get-question?id=3 HTTP/1.1" 200 10009
[17/Dec/2020 01:15:47] "POST /api/create-quiz HTTP/1.1" 201 11959
I suspect that my request.session
may be the issue because when I go directly to /api/join-quiz
and make a POST
request with my code
, nothing goes wrong and I have a successful post.
Views.py
class QuizView(generics.ListAPIView):
queryset = Quiz.objects.all()
serializer_class = QuizSerializer
class GetQuiz(APIView):
""" Searches for a quiz given its code and returns the Quiz with is_host info"""
serializer_class = QuizSerializer
lookup_url_kwarg = 'code'
def get(self, request, format=None): # This is an HTTP GET request
code = request.GET.get(self.lookup_url_kwarg)
if code != None: # Check if code is not equal to None
quiz = Quiz.objects.filter(code=code)
if len(quiz) > 0: # If there is a quiz...
data = QuizSerializer(quiz[0]).data
data['is_host'] = self.request.session.session_key == quiz[0].host
return Response(data, status=status.HTTP_200_OK)
return Response({'Quiz not found': 'Invalid Code'}, status=status.HTTP_404_NOT_FOUND)
return Response({'Bad Request': 'Code Parameter not found in request'}, status=status.HTTP_400_BAD_REQUEST)
class CreateQuizView(APIView):
"""Creates A new Quiz given nested question and answer data"""
serializer_class = QuizSerializer
def post(self, request, format=None):
""" Create the User's Account first"""
if not self.request.session.exists(self.request.session.session_key):
self.request.session.create()
data = request.data
data['host'] = self.request.session.session_key
serializer = self.serializer_class(data=data)
if serializer.is_valid():
quiz = serializer.create(validated_data=data)
self.request.session['quiz_code'] = quiz.code
return Response(
self.serializer_class(quiz).data,
status=status.HTTP_201_CREATED
)
return Response({'Bad Request': 'Invalid Data'}, status=status.HTTP_400_BAD_REQUEST)
class JoinQuiz(APIView):
"""Join a quiz based on the quiz code"""
lookup_url_kwarg = 'code'
def post(self, request, format=None):
if not self.request.session.exists(self.request.session.session_key):
self.request.session.create()
print(self.request.session.session_key)
code = request.data.get(self.lookup_url_kwarg)
if code != None:
quiz_result = Quiz.objects.filter(code=code)
if len(quiz_result) > 0:
self.request.session['quiz_code'] = code
return Response({'message': 'Quiz Joined!'}, status=status.HTTP_200_OK)
return Response({'Quiz Not Found': 'Invalid Quiz Code'}, status=status.HTTP_404_NOT_FOUND)
return Response({'Bad Request': 'Invalid Post Data'}, status=status.HTTP_400_BAD_REQUEST)
serializers.py
class QuizSerializer(serializers.ModelSerializer):
questions = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Quiz
fields = ['id', 'code', 'questions', 'name']
def create(self, validated_data):
questions_data = validated_data.pop('questions')
quiz = Quiz.objects.create(**validated_data)
for question_data in questions_data:
answers_data = question_data.pop('answers')
question = Question.objects.create(quiz=quiz, **question_data)
for answer_data in answers_data:
Answer.objects.create(question=question, **answer_data)
return quiz
const quizButtonPressed = () => {
const requestOptions = {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
code: quizCode
})
};
fetch('/api/join-quiz', requestOptions)
.then((response) => {
if (response.ok) {
props.history.push(`/play/${quizCode}`);
} else {
setError("Quiz not found")
}
})
.catch((error) => console.log(error));
}
I followed the solution from @Blusky and it worked!
Following the Django docs link from @Blusky solved the problem: https://docs.djangoproject.com/en/3.1/ref/csrf/#ajax
Upvotes: 2
Views: 664
Reputation: 3784
Even though you checked it, it might be a CSRF problem. You should check the body of the 403 Error, it might contains further information.
Only when authenticated, POST request on Django requires a CSRF token (it might be why your first POST is working)
If it's the case, you can check this snippet: https://docs.djangoproject.com/en/3.1/ref/csrf/#ajax
Upvotes: 1