I was introduced to web development using React and Django. As a tutorial, I was creating a to-do application. When I sent an API request from React, it was marked as Not Allowed. However, when I send the same request from curl, it is allowed. It seems that the API side is not set up properly.
The code in question is shown below.
import React, { useState } from "react";
import {CustomModal} from "./components/Modal";
import axios from "axios";
function App() {
const [isComplete, setComplete] = useState(true);
const [modal, setModal] = useState(false);
const [todoItems, setToDoItems] = useState([]);
const handleSubmit = (item) => {
setModal(!modal);
if (item.id) {
axios
.put(`http://localhost:8000/api/todos/${item.id}/`, item)
.then(res => refreshList);
} else {
axios
.put(`http://localhost:8000/api/todos/`, item)
.then(res => refreshList);
}
};
const handleDelete = (item) => {
axios
.post(`http://localhost:8000/api/todos/${item.id}`, item)
.then(res => refreshList);
};
const [Item, setItem] = useState({title: "", description: "", completed: false });
const createItem = () => {
const item = { title: "", description: "", completed: false };
setItem(item);
setModal(!modal);
};
const editItem = ( item ) => {
setItem(item);
setModal(!modal);
};
const refreshList = () => {
axios
.get("http://localhost:8000/api/todos/")
.then(res => setToDoItems(res.data))
.catch(err => console.log(err));
};
const displayCompleted = (status) => {
if (status) {
setComplete(true);
}
setComplete(false);
};
const renderTabList = () => {
return (
<div className="my-5 tab-list">
<span
onClick={() => displayCompleted(true)}
className={isComplete ? "active" : ""}
>
complete
</span>
<span onClick={() => displayCompleted(false)}
className={isComplete ? "" : "active"}
>
Incomplete
</span>
</div>
);
};
const renderItems = () => {
const items = todoItems.filter(item => item.completed === isComplete);
return items.map(item => (
<li key={ item.id } className="list-group-item d-flex justify-content-between align-items-center">
<span
className={`todo-title mr-2 ${
isComplete ? "completed-todo" : ""
}`}
title={item.description}
>
{item.title}
</span>
<span>
<button onClick={() => editItem(item)} className="btn btn-secondary mr-2"> Edit </button>
<button onClick={() => handleDelete(item)} className="btn btn-danger"> Delete </button>
</span>
</li>
));
};
return (
<main>
<h1 className="text-white text-uppercase text-center my-4">To Do App</h1>
<div className="row ">
<div className="col-md-6 col-sm-10 mx-auto p-0">
<div className="card p-3">
<div className="">
<button onClick={createItem} className="btn btn-primary">Add task</button>
</div>
{ renderTabList() }
<ul className="list-group list-group-flush">
{renderItems()}
</ul>
</div>
</div>
</div>
{modal ? (
<CustomModal
activeItem={Item}
toggle={setModal}
onSave={handleSubmit}
/>
) : null}
</main>
);
}
export default App;
Also, the backend/setting.py file
# ...omission
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'corsheaders',
'rest_framework',
'todo',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# ...omission
# we whitelist localhost:3000 because that's where frontend will be served
CORS_ORIGIN_WHITELIST = [
'http://localhost:3000',
]
CORS_ORIGIN_ALLOW = True
The error in the Developer Tools is as follows
PUT http://localhost:8000/api/todos/ 405 (Method Not Allowed)
dispatchXhrRequest @ xhr.js:177
xhrAdapter @ xhr.js:13
dispatchRequest @ dispatchRequest.js:52
Promise.then (async)
request @ Axios.js:61
Axios.<computed> @ Axios.js:87
wrap @ bind.js:9
handleSubmit @ App.js:18
onClick @ Modal.js:68
onClick @ Button.js:50
callCallback @ react-dom.development.js:3945
invokeGuardedCallbackDev @ react-dom.development.js:3994
invokeGuardedCallback @ react-dom.development.js:4056
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4070
executeDispatch @ react-dom.development.js:8243
processDispatchQueueItemsInOrder @ react-dom.development.js:8275
processDispatchQueue @ react-dom.development.js:8288
dispatchEventsForPlugins @ react-dom.development.js:8299
(anonymous) @ react-dom.development.js:8508
batchedEventUpdates$1 @ react-dom.development.js:22396
batchedEventUpdates @ react-dom.development.js:3745
dispatchEventForPluginEventSystem @ react-dom.development.js:8507
attemptToDispatchEvent @ react-dom.development.js:6005
dispatchEvent @ react-dom.development.js:5924
unstable_runWithPriority @ scheduler.development.js:646
runWithPriority$1 @ react-dom.development.js:11276
discreteUpdates$1 @ react-dom.development.js:22413
discreteUpdates @ react-dom.development.js:3756
dispatchDiscreteEvent @ react-dom.development.js:5889
Uncaught (in promise) Error: Request failed with status code 405
at createError (createError.js:16)
at settle (settle.js:17)
at XMLHttpRequest.handleLoad (xhr.js:62)