I'm running into a small issue with something I thought was possible.
I want to have two express routes, one GET route /post-data and one POST route /post-recieve.
The code would look something like this:
app.get('/post-data', (req, res, next) => {
//set url to '/post-recieve' and set body / headers
})
app.post('/post-recieve', (req, res, next) => {
return res.json(res.body)
})
Now, when you visit /post-data you should be instantly redirected to /post-recieve except if you look in the developer console you should see that the method for the document is POST and not a normal GET request.
Is this possible?
I know you can use a library like request to make a HTTP post request to an endpoint, but I'm talking about actually sending the user to the page via a POST request.
This feels so dumb, but it might be the only way???
function postProxyMiddleware (url, data) {
return (req, res, next) => {
let str = []
str.push(`<form id="theForm" action="${url}" method="POST">`)
each(data, (value, key) => {
str.push(`<input type="text" name="${key}" value="${value}">`)
})
str.push(`</form>`)
str.push(`<script>`)
str.push(`document.getElementById("theForm").submit()`)
str.push(`</script>`)
return res.send(str.join(''))
}
}
app.get('/mock', postProxyMiddleware('/page', exampleHeaders))
The only way to change the client's request method from GET to POST programmatically is to create a form containing hidden elements with method="post" and action="/post-receive", then using client-side JavaScript to automatically submit the form.
Any HTTP redirects in response to a GET request will also be GET.
You can use request-promise to post the data to a url. So, initiate with this function and you can get the data in the api url
const request = require('request');
const rp = require('request-promise');
let req = {
"param1" : "data1",
"param1" : "data2"
}
rp({
method: 'POST',
uri: 'http://localhost:3000/post-data/',
body: req,
json: true // Automatically stringifies the body to JSON
}).then(function (parsedBody) {
console.dir(parsedBody);
return parsedBody;
// POST succeeded...
})
.catch(function (err) {
console.log(err+'failed to post data.');
return err+'failed to post data.';
// POST failed...
});
Apologies If I get your question wrong.
Related
I'm trying to use https://www.npmjs.com/package/json-server as a mock backend, I'm able to match URLs for get, but how can i return some mock-response for POST calls.
Like for create user URL will be like
URL - http://localhost:4000/user
Method - POST
Request Data - {name:"abc", "address":"sample address"}
expected response -
httpStats Code - 200,
Response Data - {"message":"user-created", "user-id":"sample-user-id"}
In Some Cases I also want to send custom http codes like 500,423,404,401 etc.. depending upon some data.
Biggest problem is that my code is not returning anything response for POST, its only inserting records in JSON
By default POST requests through json-server should give a 201 created response.
If you need custom response handling, you might need a middleware to get hold of req and res object.
Here I'm adding a middleware to intercept POST requests and send a custom response. You could tweak it to your specific case.
// Custom middleware to access POST methods.
// Can be customized for other HTTP method as well.
server.use((req, res, next) => {
console.log("POST request listener");
const body = req.body;
console.log(body);
if (req.method === "POST") {
// If the method is a POST echo back the name from request body
res.json({ message:"User created successfully", name: req.body.name});
}else{
//Not a post request. Let db.json handle it
next();
}
});
Complete code (index.js)..
const jsonServer = require("json-server");
const server = jsonServer.create();
const router = jsonServer.router("db.json");
const middlewares = jsonServer.defaults();
server.use(jsonServer.bodyParser);
server.use(middlewares);
// Custom middleware to access POST methids.
// Can be customized for other HTTP method as well.
server.use((req, res, next) => {
console.log("POST request listener");
const body = req.body;
console.log(body);
if (req.method === "POST") {
// If the method is a POST echo back the name from request body
res.json({ message:"User created successfully", name: req.body.name});
}else{
//Not a post request. Let db.json handle it
next();
}
});
server.use(router);
server.listen(3000, () => {
console.log("JSON Server is running");
});
And you can start json-server using node index.js
So I'm running a node.js server with express that has this data. Ultimately I am trying to submit close notes, from a form in my html page, to update the close notes in this data set, which is hard coded into the node server for now.
var data = [
{
inc_num: "INC0001",
close_notes: "blah"
},
{
inc_num: "INC0002",
close_notes: ""
},
]
these are the three back end http requests.
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname + '/index.html'));
});
app.put('/update/:inc_num', (req, res) => {
delete data.close_notes;
var body = req.body
data.close_notes = body.close_notes;
res.status(200).send('ACK');
});
app.get('/update', (req, res) => {
res.send(data);
});
Here is the AJAX request from the front end
$.ajax({
url: '/update/' + inc_num,
type: 'PUT',
constentType: "application/json",
data: dataPut,
success: function(){
console.log('PUT SUCCESS');
}
})
The way it is right now nothing changes at all.
I know for a fact that the front end is sending the correct data through because if I change the function in the app.put to data.push(req.body) it adds the correct information I passed into the data array. I am either not understanding something about PUT request correctly or am just messing something up in the function of the back end PUT request.
Any help is greatly appreciated!
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,
My nodeJS Api needs to return HTML or Json based on the header. If the header is:
Accept = application/json
The Api needs to return Json else my Api needs to return a HTML file.
this is the code I use on my routes:
var app = express();
app.use('/auth', require('./routes/Authenticate'));
In the Authenticate file I catch /login, and do the login stuff. if it succeeds I redirect to /users. In the /users I check for the Accept with an if statement:
router.get('/users', function(req,res){
if(req.get('Accept') === 'application/json'){
res.json({ success: true, user: req.user });
} else {
res.render("account/profile") //redirect to the file
}
});
This works(from this solution) but is there a better way? Because there are like 20 endpoints and the application is growing and this will be a mess for every endpoint.
you can split these actions into 2 functions. One to verify the content type and an other to doing your actions.
router.get('/users', checkIfJson, action);
function checkIfJson(req, res, next) {
if(!(req.get('Content-Type') === 'application/json')) {
res.render("account/profile");
return;
}
next();
}
function action(req, res) {
res.json({ success: true, user: req.user });
return;
}
If you write your code like that you can reuse your checkIfJson into other routes.
You can wrap router.get function with a custom function
router.wrappedGet = function (path, callback) {
router.get(path, function (req, res) {
if (req.get('Content-Type') === 'application/json') {
res.render = res.json;
}
callback(req, res);
})
};
Here's what I've doneāseems pretty straightforward.
router.get("/foo", HTML_ACCEPTED, (req, res) => res.send("<html><h1>baz</h1><p>qux</p></html>"))
router.get("/foo", JSON_ACCEPTED, (req, res) => res.json({foo: "bar"}))
Here's how those middlewares work.
function HTML_ACCEPTED (req, res, next) { return req.accepts("html") ? next() : next("route") }
function JSON_ACCEPTED (req, res, next) { return req.accepts("json") ? next() : next("route") }
Personally I think this is quite readable (and therefore maintainable).
$ curl localhost:5000/foo --header "Accept: text/html"
<html><h1>baz</h1><p>qux</p></html>
$ curl localhost:5000/foo --header "Accept: application/json"
{"foo":"bar"}
Notes:
I recommend putting the HTML routes before the JSON routes because some browsers will accept HTML or JSON, so they'll get whichever route is listed first. I'd expect API users to be capable of understanding and setting the Accept header, but I wouldn't expect that of browser users, so browsers get preference.
The last paragraph in ExpressJS Guide talks about next('route'). In short, next() skips to the next middleware in the same route while next('route') bails out of this route and tries the next one.
Here's the reference on req.accepts.
In my Express app I am receiving a payload from an external POST request:
router.post('/liveReleaseStore', (req,res) => {
let thing = req.body.myPayload
...
I also handle a GET request from my client:
router.get('/liveReleaseStore', (req, res) => {
let myResponse = ...
res.send(myResponse);
});
I need to reroute the payload so that when my client sends a GET to the server I am able to send back the data or tell the client that I haven't received any data yet.
What is the best way to about about this?
Thanks
You could initialize the data outside the two functions to null. And then send the data if it's been initialized by the post function.
let thing = null;
router.post('/liveReleaseStore', (req,res) => {
let thing = req.body.myPayload
...
}
router.get('/liveReleaseStore', (req,res) => {
if (thing === null)
return res.send('no data yet');
res.send(thing);
}