Send Response in 'then' after Promise resolves - javascript

I want to display the json i got from the search for localhost:8400/api/v1/search. But I have no idea how.
I'm using the Elasticsearch Javascript Client
my routing:
'use-strict';
const express = require('express');
const elasticsearch = require('../models/elasticsearch.js');
const router = express.Router();
router.get('/api/v1/search', elasticsearch.search);
for accessing the ElasticSearch DB
const es = require('elasticsearch');
let esClient = new es.Client({
host: 'localhost:9200',
log: 'info',
apiVersion: '5.3',
requestTimeout: 30000
})
let indexName = "randomindex";
const elasticsearch = {
search() {
return esClient.search({
index: indexName,
q: "test"
})
.then(() => {
console.log(JSON.stringify(body));
// here I want to return a Response with the Content of the body
})
.catch((error) => { console.trace(error.message); });
}
}
module.exports = elasticsearch;

Firstly, the route handlers for express routes always have (request, response, next) as it's parameters. You can use the response object to send data back to the client.
Instead of passing the elasticsearch.search method as a route handler, you can write your own route handler and call elasticsearch.search in there, so you still have access to the response object. For example:
function handleSearch(req, res, next) {
elasticsearch.search()
.then(function(data) {
res.json(data)
})
.catch(next)
}
And structure your search function like so:
const elasticsearch = {
search() {
return esClient.search({
index: indexName,
q: "test"
})
.then((body) => body) // just return the body from this method
}
}
This way you separate your concerns of querying elastic and handling the request. You also have access to the request object in case you want to pass any query string parameters from your request to your search function.

Since you add elasticsearch.search as the route handler, it will be invoked with some arguments.
Change the signature of the search method to search(req, res).
Then just call res.send(JSON.stringify(body));
See https://expressjs.com/en/4x/api.html#res for more details

Related

Mongoose - find() not returning anything when no parameters are passed, but returns data when parameters are passed

I have the following model in teamMembers.js:
const { Schema, model } = require('mongoose');
const teamMembersSchema = new Schema({
uid: String,
name: String,
hours: Number
})
const TeamMembers = model('teamMembers', TeamMembersSchema);
module.exports = TeamMembers;
I've created the following endpoints in teamMemberRoute.js:
const TeamMembers = require('./models/teamMembers');
module.exports = (app) => {
app.get('/api/pods/teamMembers/:uid', async (req, res) => {
let teamMember = await TeamMembers.find( {'uid': req.params.uid } );
return res.status(200).send(teamMember);
});
app.get('/api/pods/teamMembers', async (req, res) => {
let teamMembers = await TeamMembers.find();
return res.status(200).send(teamMembers);
});
}
The first endpoint (/api/pods/teamMembers/:uid) works just fine - when I pass a uid it returns documents specific to that uid in the TeamMember collection.
The second endpoint should return all documents from the TeamMember collection since no parameters are passed. However, when the request is executed, only [] is returned. We know for a fact that documents exist in the TeamMember collection, since the first endpoint returns data from that collection based on the uid parameter that is passed.
I'm stumped on this. Any ideas? I don't think there is anything wrong with my model since I am able to execute the first endpoint with no issues.
Express executes code from top to button, and that is the reason for this issue. It will match your first endpoint and assume that uid is null. Just change the order of defined endpoints, like this:
module.exports = (app) => {
app.get('/api/pods/teamMembers', async (req, res) => {
let teamMembers = await TeamMembers.find();
return res.status(200).send(teamMembers);
});
app.get('/api/pods/teamMembers/:uid', async (req, res) => {
let teamMember = await TeamMembers.find( {'uid': req.params.uid } );
return res.status(200).send(teamMember);
});
}

GET request from a local server not working

I am trying to obtain json files with axios' GET request, but the information is not retrieved.
In index.js (retrieving information):
axios.get('http://localhost:1000/getpost/')
.then((response) => {
console.log(response);
});
Backend endpoint getpost.js (sending information):
var router = require('express').Router();
var Posts = require('../models/post-model.js');
router.route('/').get(() => {
Posts.find({color: "Green"})
.then((res) => {
return res;
});
});
module.exports = router;
I have also tried return Posts.find({color: "Green"}); inside the router.route('/').get... function,
but the value returned is different compared to the one in the promise which is the one I need. I checked that the information is actually sent with console.log(res), but it is not received in the frontend--when I log the result there, it is null.
You are not doing anything with the route response. Maybe something like...
router.route('/').get((req, res1) => {
Posts.find({color: "Green"})
.then((res) => {
res1.end(res);
});
});
(assuming res is the data in plaint text, if it is a JavaScript object you'll do res1.json(res) or res1.jsonp(res))
You need to map the route to getpost as:
router.route('/getpost')
So your getpost would be as:
var router = require('express').Router();
var Posts = require('../models/post-model.js');
router.route('/getpost').get(() => {
Posts.find({color: "Green"})
.then((res) => {
res.send({status:200,message:res});
});
});
module.exports = router;
Apparently, I was not passing the result properly.
The router in getpost.js should be:
router.route('/').get((req, res) => {
Posts.find({color: "Green"})
.then((posts) => res.json(posts));
});

Why would a query param be undefined in NextJS?

I'm calling a page withRouter(Page) and expect the variable for the page (the page is called [category].js) to be present on initial page load. Query itself is there, the key is there, but the value is 'undefined.' There seem to be a few calls to getInitialProps on the server side with 2/3 being undefined.
The react component has a constructor, etc. it's not a functional component.
This is my current getInitialProps:
Category.getInitialProps = async ({ req, query }) => {
let authUser = req && req.session && req.session.authUser
let categoryData = {}
let categoryItemData = {}
let category = query.category
if(category){
let res = await fetch(url1,
{
method: 'POST',
credentials: 'include',
})
categoryData = await res.json();
let categoryItemsRes = await fetch(url2,
{
method: 'POST',
credentials: 'include',
})
categoryItemData = await categoryItemsRes.json();
}
return { query, authUser, categoryData, categoryItemData }
}
This might be redundant at this point, but I ran into this as well and found the docs explain this here
During prerendering, the router's query object will be empty since we do not have query information to provide during this phase. After hydration, Next.js will trigger an update to your application to provide the route parameters in the query object.
You might try this instead:
export async function getServerSideProps(ctx) {
const { id } = ctx.query;
return {
props: {
id,
},
};
}
This way it gets the query params when rendering server side, so they're instantly available.
For others who use express custom server, to fix the undefined params, we have to set the dynamic route at server.js as follow:
# server.js
...
app.prepare().then(() => {
const server = express();
....
server.get('/product/:category', (req, res) => {
const { category } = req.params;
return app.render(req, res, `/product/${category}`, req.query)
})
...
}
And then, as Valentijn answers, we can get the category params.
# pages/product/[category].js
....
export async function getServerSideProps(ctx) {
const {category} = ctx.params;
return {
props: {
category
},
};
};
...
The key is dynamic path /product/${category}. Don't use /product/:category

FeathersJS: Injecting HTTP headers in Service Test

In a feathersJS service, I have a before hook being ran that expects a certain HTTP header to exist:
src/services/service_name/service_name.hooks.js
const validationHook = () => (context, next) => {
if (!context.params.headers.hasOwnProperty('header-wanted'))
throw new errors.BadRequest();
next(null, context);
};
module.exports = {
before: {
all: [cronValidationHook()],
...
..
.
When testing this service in a generated test file from feathers-cli, however, I haven't found a way to inject headers prior to the before hook being called. The test in question is:
test/services/service_name.test.js
describe('get', () => {
it('should run "id" endpoint', async () => {
const service = app.service('v1/cron');
const resp = await service.get('id', params);
// Assertions exist after this call
});
});
Is there a way to do this that does not require utilizing an HTTP call via node-fetch or requests?
params will be whatever you pass. Just set params.headers to what you would like to test, e.g.
const getParams = {
...params,
headers: { 'header-wanted': 'something' }
};
const resp = await service.get('id', getParams);

How to send message in DELETE route - express.js

I want to show message after deleting user but I don't know how to do it. I tried to create req.session properties and then use them but they are not available in GET route. Do you know how to fix this code?
router.get("/", mid.isExpired, mid.isLoggedIn, mid.isAdmin, (req, res) => {
let currentMessage = req.session.message;
let currentState = req.session.state;
req.session.message = undefined;
req.session.state = undefined;
console.log(currentState, currentMessage); //undefined
user.getAll()
.then(result => {
res.render("users", {
name: req.user,
users: result,
msg: currentMessage,
state: currentState
})
})
});
// delete route
router.delete("/delete/:id", mid.isExpired, mid.isLoggedIn, mid.isAdmin, (req, res) => {
user.del(req.params.id)
.then(() => {
req.session.message = "Some message!"
req.session.state = true;
})
});
// jquery
function ajaxDelete(ev, url) {
ev.preventDefault();
$.ajax({
url: url,
type: "DELETE"
});
}
delBtn.click(function(e) {
var user = $(this).data("user");
ajaxDelete(e, "/users/delete/" + user);
window.location.href = "/users";
})
Use res parameter, and make a variable called message
const message= 'MyMessage';
then
res.json ({message}) // es6 feature
output
{"message":"myMessage"}
In your scenario, as far as I understand you want to send the JSON in response. You can use this code
router.delete("/delete/:id", mid.isExpired, mid.isLoggedIn, mid.isAdmin, (req, res) => {
user.del(req.params.id)
.then(() => {
var response = { message : "Some message!",
state : true };
return res.json(response);
})
});
the keyword 'return' is as per your requirement
router and session are middleware to any nodeJs App,If the router is added before session like this:
app.use(router)
app.use(session(...));
Then the session middleware won't get called for any requests that get handled by router.
Hence change the order of adding router and session middleware,like this
app.use(session(...));
app.use(router)

Categories