Using express js, i want to render json that has been produced by my to ejs file.
here is my controller that produce json
const getAllQuotes = asyncWrapper(async (req, res) => {
const quotes = await qSchema.find({});
res.status(200).json({ quotes });
});
I want to pass the JSON from controller to my router below, then what my router does is bring the data and show the data to admin page
adminRoute.get('/', async (req, res) => {
//what should i type here?
res.render("admin")
})
or maybe my question is about how the data can be thrown/passed in between js file
Don't make HTTP requests from your server back to your server.
You have a function that gets your data. Use that function.
adminRoute.get('/', async (req, res) => {
const quotes = await qSchema.find({});
res.render("admin", { quotes });
})
Related
Below is my project folder structure :
app
Controller
testController.js
Service
testInfoService.js
testMoreDataService.js
config
node-modules
public
index.js
routes
routes.js
Here some code :
routes.js
router.get('/config', (req, res) => {
require(controllerDirectoryPath+"/testController.js").index(req, res)
})
testController.js
const testInfoService = require('somePath/Service/testInfoService')
const index = async (req, res) =>{
console.log('Request object : ');
console.log(req);
console.log('Response object : ');
console.log(res);
//getting more info from service
testMoreInfo = await testInfoService.getMoreInformation(args)
return res.status(200).send(testMoreInfo);
}
module.exports = {index:index}
testInfoService.js
const testMoreDataService = require("somePath/testMoreDataService")
const getMoreInformation = async (args)=> {
...some code here
response = await testMoreDataService.getMoreData(args)
return response
}
module.exports = {getMoreInformation:getMoreInformation}
testMoreDataService.js
const getMoreData = async (args)=> {
**//here I want to use Request and Response object**
...some code here
return response
}
module.exports = {getMoreData:getMoreData}
Is there any way I can access req and res object in my service?
I am using node : 12.16.2 with Express.
Main file is public/index.js
Also let me know is this the correct way I am following for any application(REST-API)?
The structure is correct,
Route -> Controller -> Service
You don't have to propagate the actual req, res object all the way down to all the services.
In your controller, you would fetch the following,
Query parameter. Eg. req.query.limit
Path variable. Eg.req.param.id
Request body. Eg. req.body/req.body.name
Once you get the required information in the controller, you could construct an object or pass the relevant information to your service.
Do all the business logic in your service and return the final information to the controller.
The controller would then send this response back to the client.
In my express router I check if the data inserted on a form are valid then if they are I render another page passing form data. I would like to access the data I pass client-side. On the chat.ejs view I have a chatroom.js client file, I want to access the data there without having to access them in a script tag.
I thought about using Ajax but the only answer I found here on StackOverflow was marked as wrong, so how do I go about that?
router.js
module.exports=function(app) {
const express = require('express');
const router = express.Router();
const {check, validationResult} = require('express-validator');
const {matchedData} = require('express-validator/filter');
router.get('/', (req, res) => {
res.render('index', {
data: {},
errors: {}
})
});
router.post('/enter', [
check('username')
.isLength({min: 1})
.withMessage('Username is required').trim(),
check('room')//implement personalized check
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.render('index', {
data: req.body,
errors: errors.mapped()
})
}
else {
const data = matchedData(req);
return res.render('chat',{
user: data.username,
room:data.room
})
}
});
return router;
//MOVE TO SUPPORT
function find(name) {
return 1;
}
}
there is really nothing client-side so far so It seems useless just posting my views. Alternatively, I could use Ajax on client.ejs to handle the form submission but I would like to keep this clean and handle the routing with the router file.
I ended up creating two global variables in a script tag for my index.ejs page like this
<script>
var user = <%- JSON.stringify( user ) %>
var room = <%- JSON.stringify(room)%>;
</script>
and then I could access them in the chatroom.js file linked below
Preamble: I'm new to web dev so maybe this might be a very basic question for you vets.
I'm using MVC architecture pattern for this basic app. I've models (MongoDB), views (Express Handlebars), and controllers (functions that take in req, res, next and returns promises (.then > JSON is returned, .catch > error is returned). I'll be routing the paths reqs to their corresponding api endpoints in the controllers.
This makes sense (right?) when I'm purely working on API calls where JSON is the res. However, I also want to call these api endpoints > get their res.json > and use that to render my HTML using Handlebars. What is the best way to accomplish this? I can create same controllers and instead of resp being JSON, I can do render ("html view", res.json). But that seems like I'm repeating same code again just to change what to do with the response (return JSON or Render the JSON).
Hope I'm making sense, if not, do let me know. Please advise.
p.s. try to ELI5 things for me. (:
Edit:
//Model Example
const Schema = require('mongoose').Schema;
const testSchema = new Schema({
testText: { type: String, required: true },
});
const Test = mongoose.model('Test', testSchema);
module.exports = Test;
//Controller Example
const model = require('../models');
module.exports = {
getAll: function(req, res, next) {
model.Test.find(req.query)
.then((testItems) => {
!testItems.length
? res.status(404).json({ message: 'No Test Item Found' })
: res.status(200).json(testItems);
})
.catch((err) => next(err));
},
};
//Route Example
const router = require('express').Router(),
controller = require('../controllers');
router.get('/', controller.getAll);
module.exports = router;
I want the endpoints to return JSON and somehow manage whether to render (if the req comes from a browser) or stay with JSON (if called from Postman or an API web URL for example) without repeating the code. I'm trying to not create two endpoitns with 99% of the code being the same, the only difference being .then > res.status(200).json(testItems); vs .then > res.status(200).render('testPage', { testItems}).
For postman you could check the existence of postman-token in req.headers, then you could render accordingly, something like this:
req.headers['postman-token'] ? res.json({ /* json */ }) : render('view', {/ * json */});
If you want to go with checking postman token then you can use similar to method1.
if you want to check with query params in this case you can get json response or html even from browser for future use also and is not dependent on postman then use similar to method2 of the following example.
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
const port = 5000
app.get('/method1', (req, res) => {
const isJSONResp = req.headers['postman-token']
const resp = { status: "hello" }
if (isJSONResp) {
res.json(resp)
} else {
res.render('some.html', resp)
}
})
app.get('/method2', (req, res) => {
const params = req.params
const resp = { status: "hello" }
if (params.resp === 'json') {
res.json(resp)
} else {
res.render('some.html', resp)
}
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
I'm making an API call in a POST route but for some reason, I can't pass the JSON data through res.render in the POST route. So I'm thinking about passing the JSON object to GET route so I can render it to the right client page.
Heres my GET and POST routes:
router.get('/bookDetails', (req, res) => {
res.render('bookDetails');
});
router.post('/bookDetails', (req, res) => {
let ID = req.body.ID;
request('https://www.googleapis.com/books/v1/volumes/' + ID, (err, response, body) => {
if(!err && response.statusCode == 200){
let bookdata = JSON.parse(body);
res.render('bookDetails', {bookdata: bookdata});
}else{
console.log(err);
}
});
});
I can't read the bookdata in my bookDetails.ejs file? Is there another way pass this data to the page?
On semantic, it should be a GET router to display something about the ID resource.
router.get('/bookDetails/:id', (req, res) => {
let resource = await fetchResourceById
res.render('bookDetails', resource);
});
also, you can define a middleware function to reuse the fetchResource logic, as following:
function fetchResourceMiddleware(){
return function(req, res, next){
var id = req.query.id || req.body.id
if(id){
req.resource = await fetchResource(id)
}
next()
}
}
reuse the middleware function for GET and POST router:
function renderResource(req, res){
res.render('bookDetails', req.resource);
}
router.get('/bookDetails/:id', fetchResourceMiddleware(), renderResource)
router.post('/bookDetails', fetchResourceMiddleware(), renderResource)
hope helpful, good luck!
After post, your get method will run.
In the get method, you are not sending any data to ejs template, so it will not detect it.
You should redirect in post method, it is bad idea sometimes,
I'm trying to receive a json with list of items in a nodejs code, but it doesn't works.
router.post('/', (req, res) => {
models.sequelize.transaction().then(transation => {
let entity = req.body;
If req.body it's just an element, works perfectly well.
Add app.use(bodyParser.json()); to your code, make sure the JSON could be parsed correctly.
I needed use JSON.stringfy first, then JSON.parse.
router.post('/', (req, res) => {
models.sequelize.transaction().then(transation => {
let entities = JSON.stringify(req.body, null, 2);
entities = JSON.parse( entities ); here
Probably it's not the best way, but works for me.