I have a database in Mlab that is MongoDB that has two collections and I am trying to make a POST endpoint to which I can post whatever a user has entered in a commentbox. However I am doing something wrong, because when I test my endpoint with Postman it says 404 that the endpoint is not found. Trying to post via the commentbox does not work too ofcourse. This is the url to my post endpoint:
https://astroecstatic-express.herokuapp.com/comments. However if I run this in the browser it displays an empty array, so how come I get a 404 error when trying to POST? What am I doing wrong and how can I make my POST endpoint? Here is my node.js server:
// Requiring the dependencies
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
const PORT = process.env.PORT || 3001;
const itemRoutes = express.Router();
let Comment = require('./comment.model');
app.use(cors());
app.use(bodyParser.json());
mongoose.connect("mongodb://admin:SomeUSersecretpassword.mlab.com:41968/heroku_hc9xjmcl", { useNewUrlParser: true } )
const connection = mongoose.connection;
connection.once('open', function() {
console.log('Connection to MongoDB established succesfully!');
});
// Serve static assets
if(process.env.NODE_ENV === 'production') {
app.use(express.static('build'));
}
itemRoutes.route('/').get( async (req, res) => {
let collection = connection.collection("posts");
let response = await collection.find({})
.toArray();
res.send(response);
});
itemRoutes.route('/comments').get( async (req, res) => {
let collection = connection.collection("comments");
let response = await collection.find({})
.toArray();
res.send(response);
});
itemRoutes.route('/comments')
.post((req, res) => {
res.setHeader('Content-Type', 'application/json');
let comment = new Comment(req.body);
comment.save()
.then(comment => {
res.status(200).json({comment})
})
.catch(err => {
res.status(400).send('failed')
})
});
app.use('/', itemRoutes);
app.use('/comments', itemRoutes);
app.listen(PORT, function() {
console.log('Server is running on' + ' ' + PORT);
})
and my post component:
import React, { Component } from 'react';
import axios from 'axios';
class CommentBox extends Component {
constructor(props) {
super(props);
this.path = window.location.href;
this.postId = this.path.split("/").slice(-1)[0];
}
state = {
userComments: []
}
componentDidMount() {
const fetchPosts = async () => {
const res = await axios.get('https://astroecstatic-express.herokuapp.com/comments');
this.setState({...this.state, userComments: res.data})
};
fetchPosts();
}
getCommentData = (res) => {
let today = new Date();
let dd = String(today.getDate()).padStart(2, '0');
let mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
let yyyy = today.getFullYear();
today = mm + '/' + dd + '/' + yyyy;
const commentContent = document.querySelector(".comment-box-container__div-comment-box").textContent;
axios.post('https://astroecstatic-express.herokuapp.com/comments', {title: commentContent, date: today, commentId: this.postId })
window.location.reload();
}
render() {
let currentPostComments = this.state.userComments.filter((item) => {
return item.commentId === this.postId
})
return(
<div className="comment-box-container">
<div className="comment-box-container__div">
<button className="comment-box-container__post-comment-btn" onClick={this.getCommentData}> Post Comment</button>
<div className="comment-box-container__div-comment-box" contentEditable="true"></div>
</div>
<div className="comment-box-container__show-coments-section">
{currentPostComments.map(comment =>
<section>
<h3>{comment.date}</h3>
{comment.title}
</section>
)}
</div>
</div>
)
}
}
export default CommentBox;
Here's a simple way to create both a .get() and a .post() route for /comments on a router:
itemRoutes.get("/comments", function(req, res, next) {
// code here
});
itemRoutes.post("/comments", function(req, res, next) {
// code here
});
app.use(itemRoutes);
You can also use .route() instead like this:
itemRoutes.route("/comments").get(function(req, res, next) {
// code here
}).post(function(req, res, next) {
// code here
});
app.use(itemRoutes);
And, you don't even really have a compelling case for using a router for these two routes. You could also just do:
app.get("/comments", ...);
app.post("/comments", ...);
Or
app.route("/comments")
.get(...)
.post(...);
And, not even use a router for just two top level routes.
Related
I am trying to send data from a search bar into my backend express server. However for some reason, it's not being updated.
import { useState } from "react";
import Button from 'react-bootstrap/Button';
const StockSearchBar = () => {
const [search, setSearch] = useState("Stock or Crypto Symbol");
const handleSearch = e => {
setSearch(e.target.value)
}
const handleClick = (e) => {
e.preventDefault()
console.log({search})
if (setSearch !== '') {
const searchResult = {search};
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(searchResult)
};
fetch('http://localhost:3001/search', options)
.then(
() => {
console.log("Search entered");
}
);
// console.log(searchResult);
}
};
return (
<>
<div className="searchBar">
<label>Look for other Stocks or Cryptos: </label>
<input type='text' onChange={handleSearch} placeholder={search}/>
<Button variant="success" type="submit" onClick={handleClick}>Success</Button>
</div>
</>
);
};
export default StockSearchBar;
and here's the backend code
const request = require("request-promise");
const fs = require("fs");
const mongoose = require("mongoose");
const cheerio = require("cheerio");
const Stock = require("./model/Stock");
const express = require("express");
const cors = require("cors");
const cron = require('node-cron');
const app = express();
const bodyParser = require('body-parser');
//MIDDLEWARE
app.use(express.json({limit: '1mb' }));
app.use(cors());
app.use(express.static('backend'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}))
// DATABASE
app.get("/", (req, res) => {
Stock.find({}).then(
items => res.json(items)
).catch(err => console.log(err))
});
app.get("/search", (req, res) => {
console.log(req.body);
res.json({
search: req.body,
});
});
app.post("/search", (req, res) => {
console.log(req.body);
res.json({
search: req.body,
});
});
app.listen(3001, function () {
console.log("Server is running...");
});
In the front end - after clicking a button it console logs an object with the search entered.
However on the backend, all I get is json text like so:
{
"search": {}
}
It doesnt get updated even though the server is continually running. Thoughts?
I tried to get data from my SQL Server Management Studio. I already made the the query inside API, so when I access those links using postman, it will retrieve data equals to the query inside those links. But when i want to show the data at page, it not comes out even though it already comes out at the console log. The error always changing, but never solved.
DbOperations Query
const config = require('./dbConfig');
const sql = require('mssql');
async function getRoles() {
try {
let pool = await sql.connect(/My Configuration Database/);
let products = await pool.request().query("SELECT [id],[division] FROM [FMLX_IME].[dbo].[ime.tbl_roles]");
return products.recordsets;
}
catch(error) {
console.log(error);
}
}
This is how I insert the function to API links
const express = require('express');
const cors = require('cors');
const app = express();
const bodyParser = require('bodyParser');
const Db = require('./dbOperations');
const router = express.Router();
const PORT = process.env.PORT || 3001;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
app.use('/api', router);
router.use((request, response, next) => {
console.log("============ MIDDLEWARE ============");
next();
});
router.route('/get-roles').get((request, response) => {
Db.getRoles().then(result => {
response.json(result);
console.log(result);
});
});
This how I tried to fetch the data, already tried so many ways but nothing works. Only success to retrieved the data if using API that already online or running, not from my localhost. (Already tried using axios too)
Class ManualTest extends React.Component {
constructor(props) {
super(props);
this.state = {
roles: [],
isLoaded: false
}
}
componentDidMount() {
fetch('http://localhost:3001/api/get-roles')
.then(result => console.log(result.json()))
.then(res => res.json())
.then(json => {
this.setState({
roles: json,
isLoaded: true
})
}).catch((err) => {
console.log(err);
});
}
render() {
const { isLoaded, roles } = this.state;
if(!isLoaded)
return <div>Loading...</div>
return (
<div className="App">
<ul>
{roles.map(role => (
<li key={role.id}>
ID: {role.id} || ROLE: {role.role}
</li>
))}
</ul>
</div>
);
}
}
export default ManualTest
So I have spent hours trying to figure out why express-fileupload is not working for me.. I have also tried using multer, but I keep getting req.files as either undefined or null. From looking around, it seems like it may have to do with my middleware bc the form is multipart data. I still can't figure out how to get this to work though. Forgive me if it's a stupid mistake.
express app (index.js)
const path = require('path')
const express = require('express')
const morgan = require('morgan')
const compression = require('compression')
const session = require('express-session')
const passport = require('passport')
const SequelizeStore = require('connect-session-sequelize')(session.Store)
const db = require('./db')
const sessionStore = new SequelizeStore({db})
const PORT = process.env.PORT || 8080
const app = express()
const socketio = require('socket.io')
const fileUpload = require('express-fileupload')
var methodOverride = require('method-override');
var multipart = require('multipart');
module.exports = app
// This is a global Mocha hook, used for resource cleanup.
// Otherwise, Mocha v4+ never quits after tests.
if (process.env.NODE_ENV === 'test') {
after('close the session store', () => sessionStore.stopExpiringSessions())
}
/**
* In your development environment, you can keep all of your
* app's secret API keys in a file called `secrets.js`, in your project
* root. This file is included in the .gitignore - it will NOT be tracked
* or show up on Github. On your production server, you can add these
* keys as environment variables, so that they can still be read by the
* Node process on process.env
*/
if (process.env.NODE_ENV !== 'production') require('../secrets')
// passport registration
passport.serializeUser((user, done) => done(null, user.id))
passport.deserializeUser(async (id, done) => {
try {
const user = await db.models.user.findByPk(id)
done(null, user)
} catch (err) {
done(err)
}
})
const createApp = () => {
// logging middleware
app.use(morgan('dev'))
// body parsing middleware
app.use(express.json())
app.use(express.urlencoded({extended: true}))
//file uploads
app.use(fileUpload()); //express-fileupload
// app.use(multer({dest:'./uploads/'})); //multer
// compression middleware
app.use(compression())
// session middleware with passport
app.use(
session({
secret: process.env.SESSION_SECRET || 'my best friend is Cody',
store: sessionStore,
resave: false,
saveUninitialized: false
})
)
app.use(passport.initialize())
app.use(passport.session())
// auth and api routes
app.use('/auth', require('./auth'))
app.use('/api', require('./api'))
// static file-serving middleware
app.use(express.static(path.join(__dirname, '..', 'public')))
// any remaining requests with an extension (.js, .css, etc.) send 404
app.use((req, res, next) => {
if (path.extname(req.path).length) {
const err = new Error('Not found')
err.status = 404
next(err)
} else {
next()
}
})
// sends index.html
app.use('*', (req, res) => {
res.sendFile(path.join(__dirname, '..', 'public/index.html'))
})
// error handling endware
app.use((err, req, res, next) => {
console.error(err)
console.error(err.stack)
res.status(err.status || 500).send(err.message || 'Internal server error.')
})
}
const startListening = () => {
// start listening (and create a 'server' object representing our server)
const server = app.listen(PORT, () =>
console.log(`Mixing it up on port ${PORT}`)
)
// set up our socket control center
const io = socketio(server)
require('./socket')(io)
}
const syncDb = () => db.sync()
async function bootApp() {
await sessionStore.sync()
await syncDb()
await createApp()
await startListening()
}
// This evaluates as true when this file is run directly from the command line,
// i.e. when we say 'node server/index.js' (or 'nodemon server/index.js', or 'nodemon server', etc)
// It will evaluate false when this module is required by another module - for example,
// if we wanted to require our app in a test spec
if (require.main === module) {
bootApp()
} else {
createApp()
}
app.post('/photos/upload', async (req, res, next) => {
try {
console.log(req.files, 'req.files ------')
if (req.files === null) {
res.status(400).send("no file uploaded");
}
console.log(req.files, 'req.files!!!----')
const file = req.files.file;
file.mv(`${__dirname}/client/public/uploads/${file.name}`, err => {
if(err) {
console.error(err);
return res.status(500).send(err);
}
res.json('hello')
// res.json({ fileName: file.name, filePath: `uploads/${file.name}`});
})
// const {name, data} = req.files.picture;
// await knex.insert({name: name, img: data}).into('picture');
} catch (err) {
next(err)
}
}
)
File upload form (CreateListingTest.js)
import React, {useEffect, useState} from 'react'
import {connect} from 'react-redux'
import {useForm} from 'react-hook-form'
import {addNewListing} from '../store/listings'
import axios from 'axios'
/**
* COMPONENT
*/
export const CreateListing = props => {
// const {register, handleSubmit, errors} = useForm()
const [file, setFile] = useState('');
const [filename, setFilename] = useState('Choose File')
const [uploadedFile, setUploadedFile] = useState({});
const onChange = (e) => {
setFile(e.target.files[0]);
setFilename(e.target.files[0].name);
console.log('onChange' , file, filename)
}
const onSubmit = async e => {
e.preventDefault();
const formData = new FormData();
formData.append('files', file);
try {
const res = axios.post('/photos/upload', formData, {
headers: {
'Content-Type' : 'multipart/form-data'
}
});
console.log(res.data, 'res.data in test')
const { fileName, filePath } = res.data;
setUploadedFile({ fileName, filePath });
} catch(err) {
console.log(err, 'error')
}
}
return (
<div className="create-listing">
<h2>Create New Listing</h2>
<div className="all-listings">
<form className="create-listing-form" onSubmit={onSubmit} action="/upload" method="POST">
<input
type="file"
id="img"
name="file"
accept="image/*"
onChange={onChange}
/>
<label>{filename}</label>
<div className="create-listing-form-section">
<input type="submit" value="Upload"/>
</div>
</form>
</div>
</div>
)
}
/**
* CONTAINER
*/
const mapState = state => {
return {
// myListings: state.listings.myListings,
user: state.user
}
}
const mapDispatch = (dispatch, state) => {
return {
addNewListing: (userId, listing) => dispatch(addNewListing(userId, listing))
}
}
export default connect(mapState, mapDispatch)(CreateListing)
I have a MongoDB collection that I search through by using a value from an input field using the $search operator and it works, when I console log the result it shows me only those documents that match the search, but I want them to be visible on the endpoint http://localhost:3001/search as well, but currently I get all the documents listed, how can I list the result of the search? I am trying with res.send(result); but it does not work. Here is my attempt:
// Requiring the dependencies
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
require('dotenv').config();
const mongoose = require('mongoose');
const PORT = process.env.PORT || 3001;
const BASE_URL = process.env.REACT_APP_BASE_URL;
const itemRoutes = express.Router();
let Comment = require('./comment.model');
app.use(cors());
app.use(bodyParser.json());
mongoose.connect(BASE_URL, { useNewUrlParser: true })
const connection = mongoose.connection;
connection.once('open', function () {
console.log('Connection to MongoDB established succesfully!');
});
let collection = connection.collection("posts_with_tags_test");
collection.createIndex(
{
postContent: 'text',
title: 'text'
}
);
itemRoutes.route('/search').post(async (req, res) => {
let result = await connection.collection("posts_with_tags_test").find({
$text: {
$search: req.body.queryString
}
}).toArray();
res.send(result);
console.log(result)
});
app.use('/search', itemRoutes);
app.listen(PORT, function () {
console.log('Server is running on' + ' ' + PORT);
})
and here is my input field:
import React, { Component } from "react";
import axios from "axios";
class Search extends Component {
getSearchQuery = () => {
const queryString = document.querySelector(
".search-input"
).value;
axios.post("http://localhost:3001/search", {
queryString: queryString,
});
console.log(queryString)
};
render() {
return (
<div>
<input
type="text"
className="search-input"
/>
<button type="submit" onClick={this.getSearchQuery}></button>
</div>
);
}
}
export default Search;
If you just access localhost:3001/search from a browser, it won't be visible because you aren't sending the data { queryString: "sample" } to be used in the query as req.body.queryString unless you're using Postman
If you're accessing it from frontend, in your React component's getSearchQuery, try using .then() on your axios.post() to receive the response from your backend
axios.post("http://localhost:3001/search", {
queryString: queryString,
}).then(response => {
console.log(response);
console.log(response.status);
console.log(response.data);
});
I figured out how to make a request to SQL server and post as JSON on the server side. I'm wondering how I can pull that data into the react side.
Server.js:
let pullTable = require('./actions/pullTable.js');
var express = require('express');
var app = express();
app.get('/', async (req, res, next) => {
try {
const result = await pullTable.pullTable();
return res.status(200).json(result);
} catch (error) {
next(error);
}
});
app.listen(5000, () => {console.log('Server is running..')});
SQL Request - pullTable.js:
var sql = require("mssql");
var express = require('express');
var app = express();
// config for your database
var config = {
user: 'user',
password: 'pass',
server: 'localhost',
database: 'Master'
};
const pullTable = async () => {
try {
const pool = await sql.connect(config);
const sqlQuery = 'SELECT * FROM Persons';
const result = await pool.request().query(sqlQuery);
return result.recordset;
} catch (err) {
throw err;
}
};
exports.pullTable = pullTable;
The code works fine up to here. I look at port 5000 and can see the JSON data being displayed from my server. Just not sure how to get this into React. This is my attempt at the react side (not including the App.js file - don't need help with that):
getData.js:
import React, { Component } from 'react';
class getData extends Component {
constructor(){
super();
this.state={
data:[],
}
}
componentDidMount(){
fetch('http://localhost:5000')
.then((Response)=>Response.json())
.then((findresponse)=>
{
this.setState({
data:findresponse,
});
});
}
render() {
return (
<div>
{
this.state.data.map((dynamicData)=>
<div>
<span>{dynamicData.LastName} </span>
<span>{dynamicData.FirstName}</span>
</div>
)
}
</div>
);
}
}
export default getData;
Just looking to display the first and last name of people in that SQL table.
#Shawn Yap pointed me in the right direction. Basically had to include the Access-Control-Allow-Origin header on the server script:
let pullTable = require('./actions/pullTable.js');
var express = require('express');
var app = express();
app.get('/', async (req, res, next) => {
try {
res.set('Access-Control-Allow-Origin', '*');
const result = await pullTable.pullTable();
return res.status(200).json(result);
} catch (error) {
next(error);
}
});
app.listen(5000, () => {console.log('Server is running..')});
Not sure if this even good code, but it's working.