I'm trying to create an admin panel (CRUD operations) for a website. I first create the API endpoint and then host it on my subdomain. I'm now getting data from that endpoint. Showing all contacts (GET), individual contacts (GET) and adding new contacts (POST) works great, but I'm stuck for days on updating contacts (PUT).
Pre-filled forms work fine. When I submit the data, I get the following error:
Access to XMLHttpRequest at 'https://api.itisgoodtohave.me/contacts/update.php' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status. PUT https://api.itisgoodtohave.me/contacts/update.php net::ERR_FAILED Uncaught (in promise) AxiosError {message: 'Network Error', name: 'AxiosError', code: 'ERR_NETWORK', config: {…}, request: XMLHttpRequest, …}
update.php
:
<?php header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Headers: *"); header("Access-Control-Allow-Methods: *"); include 'DbConnection.php'; $objDb = new DbConnection; $conn = $objDb->connect(); $method = $_SERVER['REQUEST_METHOD']; if ($method = "POST") { $contact = json_decode(file_get_contents('php://input')); $sql = "UPDATE contacts SET name=:name, email=:email, phone=:phone WHERE id=:id"; $stmt = $conn->prepare($sql); $stmt->bindParam(':id', $contact->id); $stmt->bindParam(':name', $contact->name); $stmt->bindParam(':email', $contact->email); $stmt->bindParam(':phone', $contact->phone); if ($stmt->execute()) { $response = ['status' => 1, 'message' => "Contact updated sucessfully."]; } else { $response = ['status' => 0, 'message' => "Could not update contact."]; } echo json_encode($response); } else { echo "some error occured"; }
EditContact.js
import React from 'react'; import axios from 'axios'; import { useState, useEffect } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; export default function EditContact() { const [inputs, setInputs] = useState([]) const navigate = useNavigate(); const { id } = useParams(); useEffect(() => { showContact(); }, []) function showContact() { axios.get(`https://api.mywebsite.com/contacts/single_read.php/?id=${id}`) .then(function(response) { setInputs(response.data); }) } const handleChange = (event) => { const name = event.target.name; const value = event.target.value; setInputs(values=> ({...values, [name]: value})); console.log(inputs) } const handleSubmit = (event) => { event.preventDefault(); axios.put('https://api.mywebsite.com/contacts/update.php', inputs) .then(function(response){ console.log(response) navigate('/admin/contacts') }) } return ( <div> <h3>Edit Contact</h3> <form onSubmit={handleSubmit}> <label>Name</label> <input defaultValue={inputs.name} type="text" name="name" onChange={handleChange} /> <br /> <label>Email</label> <input defaultValue={inputs.email} type="text" name="email" onChange={handleChange} /> <br /> <label>Phone</label> <input defaultValue={inputs.phone} type="text" name="phone" onChange={handleChange} /> <br /> <button type="submit">Save</button> </form> </div> ) }
I have tried every endpoint in postman. All of them (GET, POST, PUT, DELETE) are working. These entries have been updated in my database.
After hours of googling about CORS, rewriting my code again, etc., I just can't figure it out. I'm pretty new to coding, but it seems illogical to me that POST works but PUT doesn't (or I'm missing some basic logic here).
I would be happy if anyone can suggest new ideas. I'm eager to learn :)
Postman is an HTTP client, not a browser. CORS works in browsers, so HTTP clients will ignore these headers. So it makes perfect sense that you won't have any issues calling the API using Postman.
The important part of the error message is that
the response to the preflight request failed the access control check: it did not have HTTP OK status
. Preflight request is an HTTP request with the OPTIONS method. You can think of this as a recon request to check whether further requests are allowed (See MDN documentation). This error indicates that the response to this OPTIONS request was not an HTTP 200. The solution here is to ensure that the OPTIONS request will result in an HTTP 200 with all CORS headers set.