Express.js 400 (Bad Request) - javascript

I have created new route "/bookroom" for my application, however, I keep getting an error:
POST http://localhost:3000/api/bookings/bookroom 400 (Bad Request)
I am not sure what is causing this error. Below I have listed the code from my frotnend and backend. I would be gratefull for any help.
Server.js
const express = require("express");
const app = express();
const dbConfig = require('./db')
app.use(express.json())
const roomsRoute = require('./routes/roomsRoute')
const usersRoute = require('./routes/usersRoute')
const bookingsRoute = require('./routes/bookingsRoute')
app.use('/api/rooms', roomsRoute)
app.use('/api/users', usersRoute)
app.use('/api/bookings', bookingsRoute)
const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log(`App listening on port ${port}`)
});
Backend - bookingsRoute.js
const express = require('express')
const router = express.Router()
const Booking = require("../models/booking")
router.post("/bookroom", async(req, res)=>{
const {
room,
userid,
fromdate,
todate,
totalamount,
totaldays} = req.body
try{
const newbooking = new Booking({
room: room.name,
roomid: room._id,
userid,
fromdate,
todate,
totalamount,
totaldays,
transactionId: '1234'
})
const booking = await newbooking.save()
res.send('Room booked successfully')
}catch(error){
return res.status(400).json({ message: 'error' });
}
})
module.exports = router
Fronted - Bookingscreeen.js
import React, { useState, useEffect } from 'react'
import axios from 'axios'
import Loader from '../components/Loader'
import Error from '../components/Error'
import moment from 'moment'
function Bookingscreen({ match }) {
const [loading, setloading] = useState(true)
const [error, seterror] = useState()
const [room, setroom] = useState()
const roomid = match.params.roomid
const fromdate = moment(match.params.fromdate , 'DD-MM-YYYY')
const todate = moment(match.params.todate , 'DD-MM-YYYY')
const totaldays = moment.duration(todate.diff(fromdate)).asDays() + 1
const [totalamount, settotalamount] = useState()
useEffect(() => {
try {
setloading(true)
async function gettingRoom() {
const data = (await axios.post('/api/rooms/getroombyid', { roomid: match.params.roomid })).data
setroom(data)
setloading(false)
settotalamount(data.rentperday * totaldays)
}
gettingRoom()
}
catch (error) {
seterror(true)
console.log(error)
setloading(false)
}
}, [])
async function bookRoom(){
const bookingDetails = {
room,
userid: JSON.parse(localStorage.getItem('currentUser'))._id,
fromdate,
todate,
totalamount,
totaldays
}
try{
const result = await axios.post('/api/bookings/bookroom', bookingDetails)
}catch(error){
console.log(error)
}
}
return (
<div className='m-5'>
{loading ?
(<Loader />)
: room ?
(
<div>
<div className='row justify-content-center mt-6 bx_shadow'>
<div className='col-md-5'>
<h1>{room.name}</h1>
<img src={room.imageurls[0]} classname='fullsizeimg' />
</div>
<div className='col-md-5'>
<h1>Szczegóły rezerwacji</h1>
<hr></hr>
<b>
<p>Nazwa: {room.name} </p>
<p>Od: {match.params.fromdate}</p>
<p>Do: {match.params.todate}</p>
<p>Dni: {totaldays}</p>
<p>Cena za dzień: {room.rentperday} </p>
<p>Suma: {totalamount}</p>
</b>
<div>
<button style={{ float: 'right' }} className='room_btn' onClick={bookRoom}> Zarezerwuj</button>
</div>
</div>
</div>
</div>)
: (<Error />)
}
</div>
)
}
export default Bookingscreen
Model - bookings.js
const mongoose = require("mongoose")
const bookingSchema = mongoose.Schema({
room : {
type: String, required: true
},
roomid : {
type: String, required: true
},
userid : {
type: String, required: true
},
fromdate : {
type: String, required: true
},
todate : {
type: String, required: true
},
totalamount : {
type: Number, required: true
},
totaldays : {
type: Number, required: true
},
transactionid : {
type: String, required: true
},
status: {
type: String, required: true, default : "booked"
}
},{
timestamps: true,
})
const bookingmodel = mongoose.model('bookings', bookingSchema)
module.exports = bookingmodel

Your PORT ENV Is undefined currently so Your port is 5000. But you are requesting from localhost:3000

Related

tried every solution why this error occurs ? body: CastError: Cast to string failed for value mongoose

tried every solution why this error occurs ? can not understand at all
i was trying to remove cloudinary upload section from website .
it means users can post in my blog without uploading image .
image was necessary
so i tried to change source code but this error not going away at any cost
this.$__.validationError = new ValidationError(this);
[0] ^
[0]
[0] ValidationError: Post validation failed: body: Cast to string failed for value "{
[0] _immutable: {
[0] allowUndo: true,
[0] currentContent: {
[0] entityMap: {},
[0] blockMap: [Object],
[0] selectionBefore: [Object],
[0] selectionAfter: [Object]
[0] },
[0] decorator: { _decorators: [Array] },
[0] directionMap: { idih: 'LTR' },
[0] forceSelection: false,
[0] inCompositionMode: false,
[0] inlineStyleOverride: null,
[0] lastChangeType: 'insert-characters',
[0] nativelyRenderedContent: null,
[0] redoStack: [],
[0] selection: {
[0] anchorKey: 'idih',
[0] anchorOffset: 5,
[0] focusKey: 'idih',
[0] focusOffset: 5,
[0] isBackward: false,
[0] hasFocus: false
[0] },
[0] treeMap: { idih: [Array] },
[0] undoStack: [ [Object] ]
[0] }
[0] }" (type Object) at path "body", image.publicId: Path `image.publicId` is required., image.url: Path `image.url` is required.
this is my postmodel.js that i remove required:true . but error is same
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PostSchema = new Schema(
{
title: { type: String, required: true },
image: { url: { type: String, required: true }, publicId: { type: String, required: true } },
body: { type: String, required: true },
likes: [{ type: mongoose.Types.ObjectId, ref: 'User' }],
unicorns: [{ type: mongoose.Types.ObjectId, ref: 'User' }],
bookmarks: [{ type: mongoose.Types.ObjectId, ref: 'User' }],
tags: [{ type: mongoose.Types.ObjectId, required: true, ref: 'Tag' }],
comments: [{ type: mongoose.Types.ObjectId, required: true, ref: 'Comment' }],
author: { type: mongoose.Types.ObjectId, required: true, ref: 'User' },
},
{
timestamps: true,
}
);
module.exports = mongoose.model('Post', PostSchema);
and this is my post controller that i was trying to change and remove the upload part from website but i could not after 3 days .
postcontroller .js
const Post = require('../model/Post');
const User = require('../model/User');
const Tag = require('../model/Tag');
const Comment = require('../model/Comment');
const cloudinary = require('../config/cloudinary');
const { uploadToCloudinary } = require('../utils/cloudinary');
const { getPostParams, unCapitalizeFirstLetter } = require('../helpers/string');
const { createTags, updateTags, deleteTags } = require('./tagsController');
const {
likeNotification,
removeLikeNotification,
postNotification,
removePostNotification,
} = require('./notificationsController');
const createPost = async (req, res) => {
const { title, file, body, tags, authorUsername } = req.body;
const { url, public_id: publicId } = await uploadToCloudinary(file, 'Posts');
const author = await User.findOne({ username: authorUsername }).exec();
const formattedTags = tags
.trim()
.split(',')
.map(w => w.trim().replace(/ /g, '-'));
const createdPost = await Post.create({
title,
image: { url, publicId },
body,
author: author._id,
});
author.followers.map(followerId => {
(async () => {
await postNotification(author._id, createdPost._id, followerId);
})();
});
await createTags(formattedTags, createdPost);
author.posts.push(createdPost._id);
await author.save();
res.status(200).json(createdPost.toObject({ getters: true }));
};
const getPost = async (req, res) => {
const author = await User.findOne({ username: req.params.username }).exec();
const authorId = await author?.toObject({ getters: true }).id;
const { postTitle, postId } = getPostParams(req.params.postUrl);
const foundPost = await Post.findOne({
author: authorId,
title: postTitle,
_id: postId,
})
.populate('author')
.populate('comments')
.populate('tags')
.exec();
res.status(200).json(foundPost.toObject({ getters: true }));
};
const getPosts = async (req, res) => {
const { userId } = req.params;
const posts = await Post.find(userId ? { bookmarks: userId } : {})
.sort({ createdAt: -1 })
.populate('author')
.populate('tags');
if (!posts) res.status(204).json('No posts found');
res.status(200).json(posts.map(post => post.toObject({ getters: true })));
};
const updatePost = async (req, res) => {
const authorId = await User.findOne({ username: req.params.username }).exec();
const { postTitle, postId } = getPostParams(req.params.postUrl);
const { url, public_id: publicId } = await uploadToCloudinary(req.body.image.url, 'Posts');
await cloudinary.uploader.destroy(req.body.image.publicId);
req.body.image = { url, publicId };
const formattedTags = req.body.tags
.trim()
.split(',')
.map(w => w.trim().replace(/ /g, '-'));
const post = await Post.findOne({
author: authorId,
title: postTitle,
_id: postId,
})
.populate('author')
.populate('tags');
Object.keys(req.body).map(key => {
if (key !== 'tags') post[key] = req.body[key];
});
await updateTags(formattedTags, post);
await post.save();
res.status(200).json(post.toObject({ getters: true }));
};
const deletePostsByUserId = async user => {
const { _id: userId } = user;
user.comments.forEach(commentId => {
(async () => {
await Post.updateMany({ comments: commentId }, { $pull: { comments: commentId } });
})();
});
const posts = await Post.find({ author: userId }).populate('tags');
['likes', 'unicorns', 'bookmarks'].forEach(k => {
(async () => {
await Post.updateMany({ [k]: userId }, { $pull: { [k]: userId } });
})();
});
posts.forEach(post => {
(async () => {
await deleteTags(
post.tags.map(({ name }) => name),
post,
true
);
await cloudinary.uploader.destroy(post.image.publicId);
await Post.deleteOne({ _id: post._id });
})();
});
await Comment.deleteMany({ author: userId });
};
const deletePost = async (req, res) => {
const author = await User.findOne({ username: req.params.username }).exec();
const { postTitle, postId } = getPostParams(req.params.postUrl);
await cloudinary.uploader.destroy(req.body.publicId);
const foundPost = await Post.findOne({
author: author._id,
title: postTitle,
_id: postId,
})
.populate('tags')
.exec();
if (!foundPost) return res.sendStatus(204);
const comments = await Comment.find({ parentPost: postId }).populate({
path: 'author',
populate: 'followers',
});
comments.forEach(({ author }) =>
(async () => {
author.comments.forEach(comment => author.comments.pull(comment));
})()
);
author.posts.pull(postId);
await author.save();
await Comment.deleteMany({ parentPost: postId });
await deleteTags(
foundPost.tags.map(({ name }) => name),
foundPost,
true
);
removePostNotification(author._id, foundPost._id, author.followers);
await Post.deleteOne({ _id: foundPost._id });
res.status(200).json(foundPost.toObject({ getters: true }));
};
const postReaction = async (req, res) => {
const { userId } = req.body;
const { action, postUrl } = req.params;
const { postTitle, postId } = getPostParams(postUrl);
const isUndoing = action.includes('remove');
const actionKey = isUndoing
? unCapitalizeFirstLetter(action.replace('remove', '')) + 's'
: action + 's';
const author = await User.findOne({ username: req.params.username }).exec();
const authorId = await author.toObject({ getters: true }).id;
const updatedPost = await Post.findOneAndUpdate(
{ author: authorId, title: postTitle, _id: postId },
isUndoing ? { $pull: { [actionKey]: userId } } : { $addToSet: { [actionKey]: userId } },
{ new: true, timestamps: false }
);
if (isUndoing) await removeLikeNotification(userId, updatedPost._id, authorId);
else await likeNotification(userId, updatedPost._id, authorId);
res.status(200).json(updatedPost.toObject({ getters: true }));
};
module.exports = {
createPost,
getPosts,
getPost,
updatePost,
deletePost,
deletePostsByUserId,
postReaction,
};
and this is my front end part new-post.jsx
import 'easymde/dist/easymde.min.css';
import { useContext, useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import SimpleMDE from 'react-simplemde-editor';
import tw from 'twin.macro';
import Error from '../../common/Error';
import LoadingSpinner from '../../common/LoadingSpinner';
import RouteWrapper from '../../common/RouteWrapper';
import socketContext from '../../context/SocketContext';
import { selectCurrentUser } from '../../core/features/auth/authSlice';
import { useCreatePostMutation } from '../../core/features/posts/postsApiSlice';
import { useGetUserDashboardQuery } from '../../core/features/users/usersApiSlice';
import useBase64 from '../../hooks/useBase64';
import useRequireAuth from '../../hooks/useRequireAuth';
import { Editor } from "react-draft-wysiwyg";
// import "../../../node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
// import React, { Component } from 'react';
import "../NewPost/react-draft-wysiwyg.css"
// import "react-draft-wysiwyg/dist/react-draft-wysiwyg.cs";
// import LiveMarkdown from '../markdowneditor/markdowneditor';
// import EasyMDE from 'easymde';
const NewPost = () => {
const [title, setTitle] = useState('');
const [file, setFile] = useState('');
const [body, setBody] = useState('');
const [tags, setTags] = useState('');
const [isTagsFocused, setIsTagsFocused] = useState(false);
const [inputsFilled, setInputsFilled] = useState(false);
const filePickerRef = useRef();
const titleRef = useRef();
const [createPost, { isLoading, isError }] = useCreatePostMutation();
const navigate = useNavigate();
const currentUser = useSelector(selectCurrentUser);
const dispatch = useDispatch();
const previewURL = useBase64(file);
const { isAuthed, handleAuth } = useRequireAuth();
const { socket } = useContext(socketContext);
const { data: user } = useGetUserDashboardQuery(currentUser.username);
useEffect(() => titleRef.current.focus(), []);
useEffect(() => {
if (title && body && tags) setInputsFilled(true);
else setInputsFilled(false);
}, [title, body, tags]);
const handleSubmit = async () => {
if (inputsFilled) {
if (isAuthed) {
try {
const { id } = await createPost({
title,
file: previewURL,
body,
tags,
authorUsername: currentUser.username,
}).unwrap();
socket.emit('post', {
sender: currentUser,
receivers: user?.followers,
post: { title, id },
});
setTitle('');
setFile('');
setBody('');
setTags('');
navigate('/');
} catch (err) {
console.log(err);
}
} else handleAuth();
}
};
return (
<RouteWrapper>
<Wrapper>
{isLoading && <LoadingSpinner />}
{!isLoading && (
<NewPostWrapper>
<Heading>ایجاد پست جدید</Heading>
<InputWrapper>
<Label dir='rtl' htmlFor='title'>موضوع</Label>
<Input
dir='rtl'
ref={titleRef}
id='title'
value={title}
onBlur={e => setTitle(prev => prev.trim())}
onChange={e => setTitle(e.target.value)}
required
/>
</InputWrapper>
<InputWrapper>
// <Input
type='file'
ref={filePickerRef}
onChange={e => setFile(e.target.files[0])}
style={{ display: 'none' }}
/>
<ImagePreview src={previewURL.toString()} alt='عکس انتخاب کنید' />
<Button onClick={() => filePickerRef.current.click()}>انتخاب آواتار</Button>
</InputWrapper>
<InputWrapper2>
{/* <SimpleMDE value={body} onChange={setBody} required /> */}
<Editor
editorState={body}
toolbarClassName="toolbarClassName"
wrapperClassName="wrapperClassName"
editorClassName="editorClassName"
onEditorStateChange={setBody}
textAlignment="right"
placeholder="اینجا تایپ کنید"
/>;
</InputWrapper2>
<InputWrapper>
<Label htmlFor='tags'>
تگ ها
{isTagsFocused && (
<Span>تگ ها با کاما جدا شده هست</Span>
)}
</Label>
<Input
id='tags'
value={tags}
onFocus={() => setIsTagsFocused(true)}
onBlur={() => setIsTagsFocused(false)}
onChange={e => setTags(e.target.value.replace(/ /g, ''))}
required
/>
</InputWrapper>
<Submit onClick={handleSubmit}>تایید</Submit>
{isError && <Error>خطاا در انجام عملیات . دوباره امتحان کنید</Error>}
{!inputsFilled && <Error>تمام فیلدها اجباری هست</Error>}
</NewPostWrapper>
)}
</Wrapper>
</RouteWrapper>
);
};
const Submit = tw.button`bg-lighter-gray hover:bg-light-gray rounded-md text-center py-2 px-1 w-full text-sm`;
const ImagePreview = tw.img`w-32 h-32 mx-auto border border-gray flex justify-center items-center text-center object-cover`;
const Input = tw.input`py-1 px-2 rounded-md outline-none border-2 border-solid border-gray focus:border-blue`;
const Label = tw.label`font-bold text-dark-gray`;
const Span = tw.p`inline ml-sm`;
const InputWrapper = tw.div`flex flex-col gap-2 `;
const Button = tw.button`bg-lighter-gray hover:bg-light-gray rounded-md text-center py-2 px-1 w-28 text-sm mx-auto`;
const Heading = tw.h1`text-dark-gray text-center`;
const NewPostWrapper = tw.div`bg-white w-3/5 mob:(w-full px-4) mx-auto py-20 px-8 [&>*:not(:last-child)]:mb-md`;
const Wrapper = tw.div`flex items-center`;
const InputWrapper2 = tw.div`border border-gray`;
export default NewPost;
i tried to remove file change and change . but this error not going away. please if some one know this answer help me
This error is occuring as you are trying to create a Post with no values but in your schema you have the values of title, body etc set as required and thus this error, check if you are calling the create Post from your frontend with no values.
Try to check this useEffect where you set your inputsfilled, I bet it sets the inputsfilled true even if the values are empty.
useEffect(() => {
if (title && body && tags) setInputsFilled(true);
else setInputsFilled(false);
}, [title, body, tags]);
The backend error is because the you are trying to create Post with required params but with empty values.
Hopefully this helps. This might even not be the problem. My bad if I got it wrong.

Post requests not firing on user form

I have a react blog application with a form to submit a blog post. I have set up a server, routes, a model, and controllers for the fetch requests, and they all work when I use postman, but for some reason when I try to implement the post request on the submit button of the form, nothing gets sent to the database. Can someone help me figure out what I'm missing?
Here is the react code for the form
import React from 'react'
import fireIconImage from '../images/fireIcon.png'
import FireIcon from './FireIcon'
export default function BlogPostForm () {
const [formState, setFormState] = React.useState({ flaire: '', title: '', text: '', fireLevel: ''});
const [isHovered, setIsHovered] = React.useState();
const [isLit, setIsLit] = React.useState();
function changeFlaire(event) {
const selectedFlaire = event.target.value;
setFormState( {...formState, flaire: selectedFlaire });
}
function changeTitle(event) {
const title = event.target.value;
setFormState( {...formState, title: title });
}
function changeText(event) {
const text = event.target.value;
setFormState( {...formState, text: text });
}
function handleMouseOver(e) {
setIsHovered(e.target.id);
}
function handleMouseLeave(e) {
setIsHovered();
}
function handleFireIconClick(e) {
setIsLit(e.target.id);
}
function handleFireIconClass(fireLevel) {
const classNames = ['fireIcon']
classNames.push(`fireIcon${fireLevel}`)
if (isHovered >= fireLevel) {
classNames.push('isHeld')
}
if (isLit >= fireLevel) {
classNames.push('isLit')
}
return classNames.join(' ');
}
function submitForm(event) {
event.preventDefault();
const data = formState;
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
};
fetch('http://localhost:8000/', options);
}
const fireIconsArray = [];
for (let i = 0; i < 5; i++) {
fireIconsArray.push(
<FireIcon
onClick={handleFireIconClick}
onMouseLeave={handleMouseLeave}
onMouseOver={handleMouseOver}
className={handleFireIconClass(i+1)}
src={fireIconImage}
alt="fire icon"
id={i+1}
key={i+1}
/>
)
}
return (
<form className="postForm">
<h1 className="postFormHeader">Create a blog post!</h1>
<select
required
className="flaireSelect"
value={formState.flaire}
onChange={changeFlaire}>
<option disabled={true} value="">Choose a flaire</option>
<option value="JavaScript">JavaScript</option>
<option value="CSS">CSS</option>
<option value="HTML">HTML</option>
<option value="REACT">REACT</option>
<option value="BACKEND">BACKEND</option>
</select>
<input
value={formState.title}
onChange={changeTitle}
className="titleBox"
placeholder="title"
type="text"
id="title"
name="title"
/>
<textarea
value={formState.text}
onChange={changeText}
className="textBox"
placeholder="text"
type="text"
id="blogPost"
name="blogPost"
/>
<div className="fireIconContainer">
{fireIconsArray}
</div>
<div className="blogPostFormButtonContainer">
<button className="blogPostSubmit" type="submit" onClick={submitForm}>SUBMIT</button>
<button className="blogPostCancel" type="submit">CANCEL</button>
</div>
</form>
)
}
Here is the controller code
const asyncHandler = require('express-async-handler')
const Post = require('../models/postModel')
//Set post
//route: POST /api/posts/id
//access: Private
const setPost = asyncHandler(async (req, res) => {
if (!req.body.title) {
res.status(400)
throw new Error('Please add a title')
}
const post = await Post.create({
title: req.body.title,
flaire: req.body.flaire,
postText: req.body.text,
fireLevel: req.body.fireLevel,
})
console.log(post)
res.status(200).json(post)
})
Here are the routes
const express = require('express')
const router = express.Router()
const {getPosts, setPost, updatePost, deletePost} = require('../controllers/postController')
//this tells which url route to use when a post and get request is made
router.route('/').get(getPosts).post(setPost)
//this tells which url route to use when a delete or put request is made
router.route('/:id').delete(deletePost).put(updatePost)
here is the server
const express = require ('express')
const dotenv = require('dotenv').config()
const port = 8000 //process.env.PORT//
const connectDB = require('./config/db')
const cors = require("cors")
const {errorHandler} = require('./middleware/errorMiddleware')
//connect the database to the server//
connectDB()
//initialize the app as express object
const app = express()
app.use(cors({
origin: "http://localhost:3000"
}))
//tell the app to accept incoming and outgoing req, res as json
app.use(express.json())
app.use(express.urlencoded({extended: false})) //?//
//not sure what this does, i think its telling the route it should look for//
app.use('/', require('./routes/postRoutes'))
//make sure the app utulizes the error handler functions//
app.use(errorHandler)
//tell the app what port to listen on
app.listen(port, () => console.log(`Server started on port ${port}`))
console.log('Hello World')
and here is the model
const mongoose = require('mongoose')
const postSchema = mongoose.Schema({
title: {
type: String,
required: [true, 'Please add a title']
},
flaire: {
type: String,
required: [true, 'Please select a flaire']
},
postText: {
type: String,
required: [true, 'Please add a body to your post']
},
fireLevel: {
type: Number,
required: [true, 'Please select a fire level']
}
},
{
timestamps: true,
}
)
module.exports = mongoose.model('Post', postSchema)
You forgot to set the fireLevel in your state so the form data was incomplete GOOFY

Axios POST with the server responded with a status of 500 (Internal Server Error)

I'm using ReactJS to build a blog app. I can use axios get, put, delete but NOT POST. Every time I post a new blog, it gives me server responded with a status of 500 (Internal Server Error).
I have been struggle with this issue for a week and couldn't figure out the reason. Thank you very much for your help! Let me know if you need additional information.
Here are my codes:
API
import axios from 'axios'
const baseUrl = `/api/blogs`
let token = null
const setToken = newToken => {
token = `bearer ${newToken}`
}
const getAll = () => {
const request = axios.get(baseUrl)
return request.then(response => response.data)
}
const create = async newBlog => {
const config = {headers: { Authorization: token }}
const response = await axios.post(baseUrl, newBlog, config)
return response.data
}
const update = async (id, newObject) => {
const request = axios.put(`${baseUrl}/${id}`, newObject)
const response = await request
return response.data
}
const remove= async (id) => {
const config = {headers: { Authorization: token }}
const request = axios.delete(`${baseUrl}/${id}`, config)
const response = await request
return response.data
}
const exportedObject = { getAll, create, update, setToken, remove }
export default exportedObject
Frontend App.js
import React, { useState, useEffect, useRef } from 'react'
import blogService from './services/blogs'
import loginService from './services/login'
import Blog from './components/Blog'
import LoginForm from './components/LoginForm'
import BlogForm from './components/BlogForm'
import Togglable from './components/Togglable'
import Notification from './components/Notification'
import axios from 'axios'
const App = () => {
const [blogs, setBlogs] = useState([])
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [user, setUser] = useState(null)
const [loginVisible, setLoginVisible] = useState(false)
const [notificationText, setNotificationText] = useState("")
const [notificationStyle, setNotificationStyle] = useState("notification")
const [Toggle, setToggle] = useState(false)
const BlogFormRef = useRef()
useEffect(() => {
const Data = async () => {
const initialBlogs = await blogService.getAll()
setBlogs( initialBlogs )
}
Data()
}, [])
useEffect(() => {
const loggedUserJSON = window.localStorage.getItem('loggedBlogUser')
if (loggedUserJSON) {
const user = JSON.parse(loggedUserJSON)
setUser(user)
blogService.setToken(user.token)
}
}, [])
const addBlog = async (blogObject) => {
BlogFormRef.current.toggleVisibility()
if (blogObject.title !== '' && blogObject.author !== '' && blogObject.url !== '') {
const newBlog = await blogService.create(blogObject)
setBlogs(blogs.concat(newBlog))
setNotificationStyle('notification')
setNotificationText(`A new blog ${blogObject.title} by ${blogObject.author} is added`)
setToggle(!Toggle)
setTimeout(() => {
setToggle(false)
}, 5000)
setBlogs('')
console.log(blogObject)
document.location.reload()
} else {
setNotificationStyle('Warning')
setNotificationText('You must fill all fields to create a blog')
setToggle(!Toggle)
setTimeout(() => {
setToggle(false)
}, 5000)
}
}
Backend
const blogsRouter = require('express').Router()
const Blog = require('../models/blog')
const User = require('../models/user')
const jwt = require('jsonwebtoken')
const middleware = require("../utils/middleware")
blogsRouter.get('/', async (request, response) => {
const blogs = await Blog.find({}).populate('user', { username: 1, name: 1 })
response.json(blogs)
})
blogsRouter.get('/:id', (request, response) => {
Blog.findById(request.params.id)
.then(blog => {
if (blog) {
response.json(blog)
} else {
response.status(404).end()
}
})
})
blogsRouter.post('/', middleware.userExtractor, async (request, response) => {
const body = request.body
const user = request.user
const decodedToken = jwt.verify(request.token, process.env.SECRET)
if (!decodedToken.id){
return response.status(401).json({error: 'token missing or invalid'})
}
if(body.title === undefined){
return response.status(400).send({
error: 'title is missing'
})
}
else if(body.author === undefined){
return response.status(400).send({
error: 'author is missing'
})
}
else if(body.url === undefined){
return response.status(400).send({
error: 'url is missing'
})
}
else{
const blog = new Blog({
title: body.title,
author: body.author,
url: body.url,
likes: body.likes,
user: user.id
})
const savedBlog = await blog.save()
//console.log(savedBlog)
//console.log(user)
user.blogs = user.blogs.concat(savedBlog.id)
await user.save()
const populatedBlog = await savedBlog.populate('user', { username: 1, name: 1 }).execPopulate()
response.status(200).json(populatedBlog.toJSON())
}
})
blogsRouter.delete('/:id', middleware.userExtractor, async (request, response) => {
const blog = await Blog.findByIdAndRemove(request.params.id)
const user = request.user
const decodedToken = jwt.verify(request.token, process.env.SECRET)
if(! request.token || !decodedToken.id){
return response.status(401).json({error:'token is missing or invalid'})
}
else if(blog.user.toString() === user.id.toString()){
await Blog.findByIdAndRemove(request.params.id)
response.status(204).end()
}
else{
return response.status(401).json({error:'cannot process deletion'})
}
})
blogsRouter.put('/:id', async (request, response) => {
const body = request.body
const blog = {
title: body.title,
author:body.author,
url: body.url,
likes: body.likes
}
await Blog.findByIdAndUpdate(request.params.id, blog, { new: true })
.then(updatedBlog => {
response.json(updatedBlog)
})
})
module.exports = blogsRouter
Mongoose
const mongoose = require('mongoose')
const blogSchema = new mongoose.Schema({
title: {type:String,
required: true},
author:{type:String,
required: true},
url: {type:String,
required: true},
likes: {type:Number,
default: 0},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'}
})
blogSchema.set('toJSON', {
transform: (document, returnedObject) => {
returnedObject.id = returnedObject._id.toString()
delete returnedObject._id
delete returnedObject.__v
}
})
const Blog = mongoose.model('Blog', blogSchema)
module.exports = Blog
Additional information: terminate output, the info is actually POST just cannot render in the front
terminal output

cant display image to card component on reactjs from backend nodejs

i trying to display the uploaded image from the backend (the backend using nodejs, sequlize) and i try to display it to card component (im using reactjs for the frontend) on the backend i made the image entered and saved to the folder name public/img, when im triying to upload it using postman, the image was successfully enterd into the file, here the result
enter image description here
but when i try to display the image on the frontend, the image doesnt appear, and here the error
enter image description here
the error is
GET http://localhost:3000/img/92c4c0be36fa5f1419f938f509df5472.png 404 (Not Found)
here the code of displaying data
import React, {Component} from 'react';
import {Card, CardGroup} from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import jwt_decode from 'jwt-decode';
class ProdukList extends Component{
constructor(props){
super(props);
this.state = {
items:[],
isLoaded: false
}
}
componentDidMount(){
const token = localStorage.getItem('usertoken')
const decoded = jwt_decode(token)
this.setState({
id_user: decoded.id_user,
})
console.log(decoded.id_user)
fetch(`http://localhost:4000/product/?id_user=${decoded.id_user}`)
.then(res=> res.json())
.then(
(result)=>{
this.setState({
items: result,
isLoaded: true
});
console.log(result)
},
(error) =>{
this.setState((error));
console.log(error)
}
)
}
render(){
console.log(this.state.items)
var{isLoaded,items}=this.state;
if(!isLoaded){
return<div>Loading.......</div>
}else{
return(
<div className="ProdukList">
{items && items.length > 0 ? items.map(item =>(
<CardGroup>
<Card style={{width: '18rem'}} key={item.id_produk}>
<Card.Img variant="top" src={item.image} alt="img"></Card.Img>
<Card.Body>
<Card.Title>
{item.Nama_produk}
</Card.Title>
<Card.Text>
{item.Price}<br/>
{item.Deskripsi}
</Card.Text>
<Card.Footer>
<small className="text-muted">Stock : {item.Jumlah_stock}</small>
</Card.Footer>
</Card.Body>
</Card>
</CardGroup>
)) : 'Kosong'}
{console.log(items)}
</div>
)
}
}
}
export default ProdukList;
here the model of database
const Sequelize = require("sequelize")
const db = require("../database/db")
//const {uploadDir} = require("../upload")
const multer = require("multer");
const express = require("express")
const app = express();
const path = require('path');
const crypto = require('crypto');
app.use(express.static('public/img'));
const uploadDir = '/img/';
const storage = multer.diskStorage({
destination:"./public"+uploadDir,
filename: function (req,file,cb){
crypto.pseudoRandomBytes(16, function(err,raw){
if (err) return cb (err)
cb(null, raw.toString('hex')+path.extname(file.originalname))
})
}
})
const uploadfile = multer({storage: storage, dest:uploadDir})
module.exports= uploadfile;
module.exports = db.sequelize.define(
'produks',
{
id_produk:{
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
id_user: {
type: Sequelize.INTEGER
},
Nama_toko:{
type: Sequelize.STRING
},
Nama_Produk:{
type: Sequelize.INTEGER
},
image:{
type: Sequelize.STRING,
get(){
const image = this.getDataValue('image');
return uploadDir+image;
}
},
Deskripsi:{
type: Sequelize.STRING
},
Price:{
type: Sequelize.INTEGER
},
Jumlah_stock:{
type:Sequelize.INTEGER
}
},
{
timestamps: false
}
)
here the code for post the data to database
const express=require("express")
const product = express.Router()
// const multer = require("multer");
const uploadfile = require('../upload')
const produk = require('../models/produk')
const {validationResult } = require('express-validator/check');
const { matchedData, sanitize } = require('express-validator/filter'); //sanitize form params
produk.sync().then(()=>{
console.log("produk berhasil sync")
}).catch(err=>{
console.log("produk gagal sync",err)
})
product.post('/addproduk/',[
uploadfile.single('image')
],(req,res)=>{
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(422).json({errors: errors.mapped()})
}
const produkData = {
id_user:req.body.id_user,
Nama_toko:req.body.Nama_toko,
Nama_Produk:req.body.Nama_Produk,
image: req.file === undefined ? "": req.file.filename,
Deskripsi:req.body.Deskripsi,
Price:req.body.Price,
Jumlah_stock:req.body.Jumlah_stock
}
console.log(produkData)
if(!produkData){
res.status(400)
res.json({
error: 'Bad data'
})
}else{
produk.create(produkData)
.then(data=>{
res.send(data)
})
.catch(err=>{
res.json('error: '+err)
})
}
})
your react project has the same "/public" folder? when you launch your react project for development it launch their own "server" at port 3000, you need share the "public" folder between react and express projects

Finding one element in graphQL by id/email

I'm trying to make a findOneByEmail/id for graphQL. I saw a couple of questions, blog posts, and videos, but they didn't help my case. I know I have to add a filter, but I have to be missing something
Here are my resolvers
const users = [
{id: 1, email:'a#a.a',password:'zaq1#WSX', pons:[{value:'test'}]},
{id: 2, email:'b#b.b',password:'ZAQ!2wsx', pons:[{value:'tset'}]}
];
const pons = [{value: 'test'}];
module.exports = {
Query: {
users: () => users,
pons: () => pons,
}
};
typeDefs
const {gql} = require('apollo-server-express');
module.exports = gql`
type Pon {
value: String!
}
type User {
id: Int
email: String!
password: String!
pons: [Pon]!
}
type Query {
findUser(id: Int): [User]
users: [User]
pons: [Pon]
}
`;
app.js
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const typeDefs = require('./graphql/typeDefs.js');
const resolvers = require('./graphql/resolvers.js');
const server = new ApolloServer({typeDefs, resolvers});
const app = express();
server.applyMiddleware({ app });
app.listen({ port: 4000 }, () =>
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
);
I am using express with apollo-server-express.
I tried adding users(id: Int) and users(email: String), but with no success. You can see it in findUser query. I am calling the query like:
query{
findUser(id: 1) {
email
pons {
value
}
}
}
In the GQL playground.
I'd like to able to filter the data on the server, not on the client, and can't find the solution anywhere
You can get the id parameters in GraphQL resolver and query user by it.
E.g.
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const { gql } = require('apollo-server-express');
const users = [
{ id: 1, email: 'a#a.a', password: 'zaq1#WSX', pons: [{ value: 'test' }] },
{ id: 2, email: 'b#b.b', password: 'ZAQ!2wsx', pons: [{ value: 'tset' }] },
];
const pons = [{ value: 'test' }];
const typeDefs = gql`
type Pon {
value: String!
}
type User {
id: Int
email: String!
password: String!
pons: [Pon]!
}
type Query {
findUser(id: Int): User
users: [User]
pons: [Pon]
}
`;
const resolvers = {
Query: {
users: () => users,
pons: () => pons,
findUser: (_, { id }) => users.find((u) => u.id === id),
},
};
const server = new ApolloServer({ typeDefs, resolvers });
const app = express();
server.applyMiddleware({ app });
app.listen({ port: 4000 }, () => console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`));
query in GraphQL playground:
query{
findUser(id: 1){
email
pons {
value
}
}
}
response:
{
"data": {
"findUser": {
"email": "a#a.a",
"pons": [
{
"value": "test"
}
]
}
}
}

Categories