-
Notifications
You must be signed in to change notification settings - Fork 263
Open
Description
System details
Output of sessioninfo::session_info()()
:
R version 4.4.1 (2024-06-14)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 24.04.2 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 LC_PAPER=en_US.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
time zone: America/Toronto
tzcode source: system (glibc)
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] RSQLite_2.3.9 DBI_1.2.3 jsonlite_1.9.1 plumber_1.3.0.9000
loaded via a namespace (and not attached):
[1] later_1.4.1 R6_2.6.1 fastmap_1.2.0 httpuv_1.6.15 bit_4.5.0 swagger_5.17.14.1
[7] magrittr_2.0.3 webutils_1.2.2 cachem_1.1.0 blob_1.2.4 pkgconfig_2.0.3 memoise_2.0.1
[13] bit64_4.5.2 lifecycle_1.0.4 promises_1.3.2 cli_3.6.4 vctrs_0.6.5 compiler_4.4.1
[19] tools_4.4.1 Rcpp_1.0.14 rlang_1.1.5 crayon_1.5.3 stringi_1.8.4
Example application or steps to reproduce the problem
library(plumber)
library(jsonlite)
library(DBI)
library(RSQLite)
# Initialize database connection
conn <- dbConnect(RSQLite::SQLite(), "items.db")
# Create table if not exists
dbExecute(
conn,
"CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, name TEXT)"
)
# Define CORS headers
cors_handler <- function(req, res) {
res$setHeader("Access-Control-Allow-Origin", "*")
res$setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS"
)
res$setHeader("Access-Control-Allow-Headers", "Content-Type")
if (req$REQUEST_METHOD == "OPTIONS") {
res$status <- 200
return("")
}
forward()
}
# Define API
pr() %>%
pr_hook("preroute", cors_handler) %>% # Apply CORS middleware
# GET all items
pr_get("/items", function(req, res) {
items <- dbGetQuery(conn, "SELECT * FROM items")
res$body <- toJSON(items, auto_unbox = TRUE)
res
}) %>%
# POST a new item
pr_post("/items", function(req, res) {
body <- fromJSON(req$postBody)
dbExecute(conn, "INSERT INTO items (name) VALUES (?)", list(body$name))
id <- dbGetQuery(conn, "SELECT last_insert_rowid() AS id")$id
res$body <- toJSON(list(id = id, name = body$name), auto_unbox = TRUE)
res
}) %>%
# PUT (update) an item
pr_put("/items/<id>", function(req, res, id) {
body <- fromJSON(req$postBody)
dbExecute(
conn,
"UPDATE items SET name = ? WHERE id = ?",
list(body$name, id)
)
res$body <- toJSON(list(id = id, name = body$name), auto_unbox = TRUE)
res
}) %>%
# DELETE an item
pr_delete("/items/<id>", function(req, res, id) {
dbExecute(conn, "DELETE FROM items WHERE id = ?", list(id))
res$body <- toJSON(list(message = "Item deleted"), auto_unbox = TRUE)
res
}) %>%
pr_run(port = 8000)
import React, { useEffect, useState } from "react";
import axios from "axios";
const API_URL = "http://127.0.0.1:8000/items";
function App() {
const [items, setItems] = useState([]);
const [newItem, setNewItem] = useState("");
useEffect(() => {
fetchItems();
}, []);
const fetchItems = async () => {
const response = await axios.get(API_URL);
setItems(response.data);
};
const addItem = async () => {
if (!newItem.trim()) return;
const response = await axios.post(API_URL, { name: newItem });
setItems([...items, response.data]);
setNewItem("");
};
const updateItem = async (id, newName) => {
await axios.put(`${API_URL}/${id}`, { name: newName });
setItems(items.map(item => (item.id === id ? { id, name: newName } : item)));
};
const deleteItem = async (id) => {
await axios.delete(`${API_URL}/${id}`);
setItems(items.filter(item => item.id !== id));
};
return (
<div className="container">
<h1>CRUD with React & Plumber</h1>
<input
type="text"
value={newItem}
onChange={(e) => setNewItem(e.target.value)}
placeholder="Add new item"
/>
<button onClick={addItem}>Add</button>
<ul>
{items.map(item => (
<li key={item.id}>
<input
type="text"
value={item.name}
onChange={(e) => updateItem(item.id, e.target.value)}
/>
<button onClick={() => deleteItem(item.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}
export default App;
Describe the problem in detail
The problem is that while I can retrieve data from the API, any other method I try results in CORS errors. I even found a similar issue reported on Stack Overflow.
https://stackoverflow.com/questions/78165697/react-post-plumber-api-resulting-in-cors-error
Metadata
Metadata
Assignees
Labels
No labels