API URL with Node Server and react-admin - node.js

I'm trying to connect
react-admin: https://github.com/marmelab/react-admin
and a Node server: https://github.com/hagopj13/node-express-mongoose-boilerplate
I have users in database and i can sing-in with the react-admin.
But when i want to show the list of users, i get this error:
fetch.js:39 GET http://localhost:4000/v1/users?filter=%7B%7D&range=%5B0%2C24%5D&sort=%5B%22createdAt%22%2C%22DESC%22%5D 401 (Unauthorized)
I don't know what to modify on the server to accept the request .
I'm a litte lost, i need help to start, do you have example that work with react-admin?
What files i need to modify?
Update:
My dataprovider in react-admin
import { fetchUtils } from "react-admin";
import { stringify } from "query-string";
const apiUrl = "http://localhost:4000/v1";
const httpClient = fetchUtils.fetchJson;
export default {
getList: (resource, params) => {
console.log(params.pagination);
console.log(params.sort);
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
filter: JSON.stringify(params.filter)
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
return httpClient(url).then(({ headers, json }) => ({
data: json,
total: parseInt(
headers
.get("content-range")
.split("/")
.pop(),
10
)
}));
},
getOne: (resource, params) =>
httpClient(`${apiUrl}/${resource}/${params.id}`).then(({ json }) => ({
data: json
})),
getMany: (resource, params) => {
const query = {
filter: JSON.stringify({ id: params.ids })
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
return httpClient(url).then(({ json }) => ({ data: json }));
},
getManyReference: (resource, params) => {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
filter: JSON.stringify({
...params.filter,
[params.target]: params.id
})
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
return httpClient(url).then(({ headers, json }) => ({
data: json,
total: parseInt(
headers
.get("content-range")
.split("/")
.pop(),
10
)
}));
},
update: (resource, params) =>
httpClient(`${apiUrl}/${resource}/${params.id}`, {
method: "PUT",
body: JSON.stringify(params.data)
}).then(({ json }) => ({ data: json })),
updateMany: (resource, params) => {
const query = {
filter: JSON.stringify({ id: params.ids })
};
return httpClient(`${apiUrl}/${resource}?${stringify(query)}`, {
method: "PUT",
body: JSON.stringify(params.data)
}).then(({ json }) => ({ data: json }));
},
create: (resource, params) =>
httpClient(`${apiUrl}/${resource}`, {
method: "POST",
body: JSON.stringify(params.data)
}).then(({ json }) => ({
data: { ...params.data, id: json.id }
})),
delete: (resource, params) =>
httpClient(`${apiUrl}/${resource}/${params.id}`, {
method: "DELETE"
}).then(({ json }) => ({ data: json })),
deleteMany: (resource, params) => {
const query = {
filter: JSON.stringify({ id: params.ids })
};
return httpClient(`${apiUrl}/${resource}?${stringify(query)}`, {
method: "DELETE",
body: JSON.stringify(params.data)
}).then(({ json }) => ({ data: json }));
}
};
Thanks & Regards

you are missing the JWT token from the header of the request ,thats why you get 401 code , the route /v1/users protected with auth middleware .get(auth('getUsers'), validate(userValidation.getUser), userController.getUser) in routes/v1/user.route.js
in middlewares/auth.js passport.authenticate('jwt', { session: false }, verifyCallback(req, resolve, reject, requiredRights))(req, res, next);

Related

FaunaDB returns empty array (FaunaDB + Netlify + VueJS)

My code is based on the repository - https://github.com/ttntm/recept0r-ts
Code from "\functions\read-all.js":
const faunadb = require('faunadb');
const fnHeaders = require('./_shared/headers.js');
exports.handler = (event, context) => {
const client = new faunadb.Client({
secret: process.env.FAUNA_SECRET,
domain: 'db.fauna.com',
scheme: 'https',
port: '443'
});
const q = faunadb.query;
const headers = { ...fnHeaders };
const origin = event.headers.Origin || event.headers.origin;
headers['Access-Control-Allow-Origin'] = origin ? origin : '*';
return client.query(q.Paginate(q.Match(q.Index('all_users'), false), { size: 500 }))
.then((response) => {
const listRefs = response.data;
const getListDataQuery = listRefs.map(ref => q.Get(ref)); // create new query out of list refs, then query the refs
return client.query(getListDataQuery).then((records) => {
return { statusCode: 200, headers: headers, body: JSON.stringify(records) }
})
})
.catch((error) => {
return { statusCode: 400, headers: headers, body: JSON.stringify(error) }
});
}
Code from "\src\store\modules\data.js":
async readAll({ commit, dispatch, rootGetters })
{
const fn = rootGetters['app/functions'];
const request = await fetch(fn.readAll, { method: 'GET' });
const response = await request.json();
if (response.length > 0) {
commit('SET_ALL_RECIPES', response);
commit('SET_LAST_UPDATED', new Date); }
else {
dispatch('app/sendToastMessage', { text: 'Error loading recipes. Please try again later.', type: 'error' }, { root: true });
return 'error';
}
}
Everything seems to be set. For example, this code works:
client.query(q.CreateCollection({ name: 'someCollection' }))
But can't read any data.
If launch application by "netlify dev" (localhost) - "read-all" returns empty array ("[]").
If launch application by "network" - "read-all" returns default "index.html".
I have no idea what's wrong. Maybe someone give advice...
I found a similar question - Local Netlify function server gives strange response instead of FaunaDB data
Some answer:
"In my experience, one of the most common reasons for this error is a routing problem, which is triggering a 404 response route serving HTML instead of your expected function handler."
This code works:
return client.query(q.Paginate(q.Documents(q.Collection('customers')), { size: 500 }))
.then((response) => {
const listRefs = response.data;
const getListDataQuery = listRefs.map(ref => q.Get(ref)); // create new query out of list refs, then query the refs
return client.query(getListDataQuery).then((records) => {
return { statusCode: 200, headers: headers, body: JSON.stringify(records) }
});
})
.catch((error) => {
return { statusCode: 400, headers: headers, body: JSON.stringify(error) }
});

POST http://localhost:8080/todo net::ERR_ABORTED 400 (Bad Request), how do I fix this?

I'm creating a to-do list that uses authentication and the todo has to connect to the MongoDB server. The bad request is because of syntax, probably the to-do list sending back from client-side to server-side. How do I fix this error?
This is the page the error is on: TodoPage.js
import React, { useState, useEffect } from 'react';
//components
import ToDoList from '../Components/ToDoList';
import ToDoForm from '../Components/ToDoForm';
function ToDoPage() {
const [toDoList, setToDoList] = useState([]);
const url = 'http://localhost:8080/todo';
useEffect(function effectFunction() {
fetch(url, {
method: 'POST',
mode: 'no-cors',
})
.then((response) => response.json())
.then(({ data: toDoList }) => {
setToDoList(toDoList);
});
}, []);
const handleToggle = (id) => {
let mapped = toDoList.map((task) => {
return task.id === Number(id)
? { ...task, complete: !task.complete }
: { ...task };
});
setToDoList(mapped);
};
const handleFilter = () => {
let filtered = toDoList.filter((task) => {
return !task.complete;
});
setToDoList(filtered);
};
const addTask = (userInput) => {
let copy = [...toDoList];
copy = [
...copy,
{ id: toDoList.length + 1, task: userInput, complete: false },
];
setToDoList(copy);
};
return (
<div className='App'>
<ToDoList
toDoList={toDoList}
handleToggle={handleToggle}
handleFilter={handleFilter}
/>
<ToDoForm addTask={addTask} />
</div>
);
}
export default ToDoPage;
The console says it is this block of code that is giving trouble.
useEffect(function effectFunction() {
fetch(url, {
method: 'POST',
mode: 'no-cors',
})
.then((response) => response.json())
.then(({ data: toDoList }) => {
setToDoList(toDoList);
});
}, []);

decrease number server making with express put method

I am trying to decrease the quantity, which I have to change on mongodb database, also I need to show it in body. I set a button called delivered which will decrease the quantity value by 1 . but when I click on the delivered button suddenly nodemon index.js cmd crashed. it says"MongoInvalidArgumentError: Update document requires atomic operators"
//Client side:
const handleQuantity = (quantity) => {
const newQuantity = Number(quantity) - 1;
// console.log(newQuantity);
fetch(`http://localhost:5000/inventory/${itemsId}`, {
method: "PUT",
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({ newQuantity })
})
.then(res => res.json())
.then(data => console.log(data))
}
//server side:
app.put('/inventory/:id', async (req, res) => {
const id = req.params.id;
const property = req.body;
const query = { _id: ObjectId(id) };
const options = { upsert: true };
const updateDoc = {
$set: {
quantity: property.newQuantity
}
};
const result = await inventoryCollection.updateOne(query, options, updateDoc);
res.send(result)
})```
Client side:
const handleQuantity = (quantity) => {
const newQuantity = parseInt(quantity) - 1;
// console.log(newQuantity);
fetch(`http://localhost:5000/inventory/${itemsId}`, {
method: "PUT",
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({ newQuantity })
})
.then(res => res.json())
.then(data => console.log(data))
}

React-Admin Pagination didn't work properly?

first of all take a look to the problem :pagination problem
I'm using react-admin for the first time, so i just was getting started and creating some small projects to practice before i integrate it to my real project.
so i'm using react for the front-end and nodejs with express middleware for the backend.
as far i know react-admin has a dataprovider so i created dataprovider.js file:
import { fetchUtils } from 'react-admin';
import { stringify } from 'query-string';
const apiUrl = 'http://localhost:5000';
const httpClient = fetchUtils.fetchJson;
export default {
getList: (resource, params) => {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
filter: JSON.stringify(params.filter),
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
httpClient(url).then(({ headers, json }) => {
console.log(headers.get('content-range'))
console.log(json)
});
return httpClient(url).then(({ headers, json }) => ({
data: json.map((resource)=>({...resource, id:resource._id})),
total: parseInt(headers.get('content-range').split('/').pop(), 10),
}));
},
getOne: (resource, params) =>
httpClient(`${apiUrl}/${resource}/${params.id}`).then(({ json }) => ({
data: json,
})),
getMany: (resource, params) => {
const query = {
filter: JSON.stringify({ id: params.ids }),
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
return httpClient(url).then(({ json }) => ({ data: json }));
},
getManyReference: (resource, params) => {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
filter: JSON.stringify({
...params.filter,
[params.target]: params.id,
}),
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
return httpClient(url).then(({ headers, json }) => ({
data: json,
total: parseInt(headers.get('content-range').split('/').pop(), 10),
}));
},
update: (resource, params) =>
httpClient(`${apiUrl}/${resource}/${params.id}`, {
method: 'PUT',
body: JSON.stringify(params.data),
}).then(({ json }) => ({ data: json })),
updateMany: (resource, params) => {
const query = {
filter: JSON.stringify({ id: params.ids}),
};
return httpClient(`${apiUrl}/${resource}?${stringify(query)}`, {
method: 'PUT',
body: JSON.stringify(params.data),
}).then(({ json }) => ({ data: json }));
},
create: (resource, params) =>
httpClient(`${apiUrl}/${resource}`, {
method: 'POST',
body: JSON.stringify(params.data),
}).then(({ json }) => ({
data: { ...params.data, id: json.id },
})),
delete: (resource, params) =>
httpClient(`${apiUrl}/${resource}/${params.id}`, {
method: 'DELETE',
}).then(({ json }) => ({ data: json })),
deleteMany: (resource, params) => {
const query = {
filter: JSON.stringify({ id: params.ids}),
};
return httpClient(`${apiUrl}/${resource}?${stringify(query)}`, {
method: 'DELETE',
}).then(({ json }) => ({ data: json }));
}
};
and the App component which contains Admin:
import * as React from "react";
import { Admin, Resource } from 'react-admin';
import dataProvider from './DataProvider'
import { Products } from "./Products";
const App=()=> {
return (
<div className="App">
<Admin dataProvider={dataProvider}>
<Resource name='Products' list={Products} />
</Admin>
</div>
);
}
export default App;
and this is the products component:
import * as React from "react";
import { List, Datagrid, TextField, EditButton } from 'react-admin';
export const Products = props => (
<List {...props}>
<Datagrid rowClick="edit">
<TextField source='id'/>
<TextField source="Title" />
<TextField source='Brand'/>
<EditButton />
</Datagrid>
</List>
);
--------------------Backend:Nodejs -- expressjs ------------------------------------
and this is my simple server that return products from the database:
const express = require('express')
const app = express()
const port = 5000
var MongoClient = require("mongodb").MongoClient;
const { ObjectId } = require("mongodb"); // or ObjectID
var url = "mongodb://localhost:27017/storedz";
var db;
var storedz;
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", req.header("Origin"));
res.header("Access-Control-Allow-Credentials", true);
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
res.header("Access-Control-Expose-Headers", "Content-Range");
res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE");
next();
});
MongoClient.connect(url, function (err, database) {
if (err) throw err;
db = database;
storedz = db.db("storedz");
});
app.get('/Products',(req, res) => {
storedz
.collection("products")
.find({})
.toArray((err, result) => {
if (err) {
return res.header(400).json("something went wrong");
}
res.header("Content-Range", `getProducts 0-4/${result.length}`);
console.log(result.length)
res.send(result);
});
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
so everything is working i mean i'm getting all the products, and i u res.header("Content-Range", Products 0-4/${result.length}); because react-admin need it to make the pagination.
so guys if i'm missing something here please correct me and give the right path so i can move to my next step.
thank you.

How to handle the data returned from the backend (nodejs) to make pagination work in react-admin

I have problem with pagination in react-admin, you can take a look over here: https://i.stack.imgur.com/KWw5Q.gif
the pagination always show the same records i mean all records at once.
---my backend ---- :
const express = require('express')
const app = express()
const port = 5000
var MongoClient = require("mongodb").MongoClient;
const { ObjectId } = require("mongodb"); // or ObjectID
var url = "mongodb://localhost:27017/storedz";
var db;
var storedz;
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", req.header("Origin"));
res.header("Access-Control-Allow-Credentials", true);
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
res.header("Access-Control-Expose-Headers", "Content-Range");
res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE");
next();
});
MongoClient.connect(url, function (err, database) {
if (err) throw err;
db = database;
storedz = db.db("storedz");
});
app.get('/Products',(req, res) => {
storedz
.collection("products")
.find({})
.toArray((err, result) => {
if (err) {
return res.header(400).json("something went wrong");
}
res.header("Content-Range", `Products 1-${result.length}/${result.length}`);
console.log(result.length)
res.json(result);
});
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
and this the dataprovider :
import { fetchUtils } from 'react-admin';
import { stringify } from 'query-string';
const apiUrl = 'http://localhost:5000';
const httpClient = fetchUtils.fetchJson;
export default {
getList: (resource, params) => {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
filter: JSON.stringify(params.filter),
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
return httpClient(url).then(({ headers, json }) => ({
data: json.map((resource)=>({...resource, id:resource._id})),
total: parseInt(headers.get('content-range').split('/').pop(), 10),
}));
},
getOne: (resource, params) =>
httpClient(`${apiUrl}/${resource}/${params.id}`).then(({ json }) => ({
...json, id: json._id ,
})),
getMany: (resource, params) => {
const query = {
filter: JSON.stringify({ id: params.ids }),
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
return httpClient(url).then(({ json }) => ({
data: json.map(resource => ({ ...resource, id: resource._id }) )
}));
},
getManyReference: (resource, params) => {
const { page, perPage } = params.pagination;
const { field, order } = params.sort;
const query = {
sort: JSON.stringify([field, order]),
range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
filter: JSON.stringify({
...params.filter,
[params.target]: params.id,
}),
};
const url = `${apiUrl}/${resource}?${stringify(query)}`;
return httpClient(url).then(({ headers, json }) => ({
data: json,
total: parseInt(headers.get('content-range').split('/').pop(), 10),
}));
},
update: (resource, params) =>
httpClient(`${apiUrl}/${resource}/${params.id}`, {
method: 'PUT',
body: JSON.stringify(params.data),
}).then(({ json }) => ({ ...json, id: json._id })),
updateMany: (resource, params) => {
const query = {
filter: JSON.stringify({ id: params.ids}),
};
return httpClient(`${apiUrl}/${resource}?${stringify(query)}`, {
method: 'PUT',
body: JSON.stringify(params.data),
}).then(({ json }) => ({ data: json }));
},
create: (resource, params) =>
httpClient(`${apiUrl}/${resource}`, {
method: 'POST',
body: JSON.stringify(params.data),
}).then(({ json }) => ({
data: { ...params.data, id: json.id },
})),
delete: (resource, params) =>
httpClient(`${apiUrl}/${resource}/${params.id}`, {
method: 'DELETE',
}).then(({ json }) => ({ data: json })),
deleteMany: (resource, params) => {
const query = {
filter: JSON.stringify({ id: params.ids}),
};
return httpClient(`${apiUrl}/${resource}?${stringify(query)}`, {
method: 'DELETE',
}).then(({ json }) => ({ data: json }));
}
};
and this App.js:
import * as React from "react";
import { Admin, Resource } from 'react-admin';
import dataProvider from './DataProvider'
import { Products } from "./Products";
const App=()=> {
return (
<div className="App">
<Admin dataProvider={dataProvider}>
<Resource name='Products' list={Products} />
</Admin>
</div>
);
}
export default App;
I don't know how to fix issues i spent two days working on it but can't fix it.
pleas if my question not clear i will update as possible.
It seems like you are sending the required parameters to your backend (i.e. range), however, you don't seem to be doing anything with those parameters in the backend. You have to use them to tell mongoDB that it should perform a pagination.
One way to do pagination in mongoDB is to use the skip(<number>) (docs) and limit(<number>) (docs) functions of the API. If you want to use those, it might make more sense that instead of sending the range query parameter, you send a pageSize and an offset parameter to the backend. The pageSize will be simply your perPage value, the offset would be computed by multiplying page with perPage.
Then, in your backend you will need to retrieve those parameters from the query object. You can do so by
const { offset, pageSize } = req.query;
However, be aware that those parameters will be string values, so you want to parse them to numbers before passing them as parameters to the skip and limit function.

Resources