I am new to Node/Express and to API's in general. Long story short, I am a front end guy diving into backend and architecture for the first time. The breakdown of my problem is as follows:
App description: A web app that allows users to view medical data records.
Desired feature: Change the state of a json record on page load. When a user opens a record(page), I want to change a json object from UNDIAGNOSED to DIAGNOSED automatically. This needs to be done server side to avoid exposing the api endpoint, which needs to stay hidden for security reasons. Think of it like a 'read/unread' email. Once it has been opened, it changes the state to 'read'
Probelem: ...I am a newb...
//When the server GETs a request to this URL
router.get('/content/:contentid', function(req, res, next) {
// Configure the REST platform call
var platform_options = {
resource: '/content/' + req.params.contentid,
method: 'POST',
json: "diagnosis_state: DIAGNOSED"
};
// Make the call
var platform = ihplatform(_config, req.session, platform_options, callback);
platform.execute();
// Result processing
function callback(error, response, body) {
console.log(response.body);
}
});
I am using a custom HTTP API that was built in-house by another developer. The endpoint for the call is dynamically generated via the re.params.contentid. You will also notice that the call itself is built into the platform.execute function.
There is a bit of copy/pasting going on, as I am trying to modify a working call.
My question is this: How do I make an api POST call to a remote API upon the HTTP request for a certain url via express.js?
Here is what you can do on express.js -
1) write a module for route mappings in a separate js file where all the mappings can be listed. Below is the code snippet of the module file
function mappings(app)
{
var email = require('./routes/emails');// ./routes/emails is js file location exporting UpdateEmail variable which contains function for update
app.put('/email/update', email.UpdateEmail); // mapping url /email/update to exported variable UpdateEmail
}
2) add following statement in app.js file where mapRoutes is a .js file created in step 1
require('./mapRoutes').mappings(app);
3) Below is the sample app.js file
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
app.all('*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Credentials', false);
res.header('Access-Control-Max-Age', '86400');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
next();
});
app.options('*', function(req, res) {
res.send(200);
});
require('./mapRoutes').mappings(app);
/// catch 404 and forwarding to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
4) live website running on above code - kidslaughs.com
I'm not quite sure your question here, because "POSTing from ExpressJS" could mean two different things.
In the most common case, you are making a POST request from a web page. While this might be served or even rendered via Express, the call is originating from the web page. In that case the javascript on the web page is making the post. Common web frameworks for that might be jQuery's $.ajax or Angular's $http. Whatever framework you use, you'll define the data to post, the API endpoint to post to, and what to do with the response.
Another meaning of your question might be that you want your Express app to make a http request from the server side. You will need a package to do so, so that you can make a HTTP programatically. A popular package for this is request.
It's hard to say more without knowing what frameworks you are working with. Keep searching around, you'll figure it out!
I think you're looking for request.js.
var request = require('request');
request.post('/content/' + req.params.contentid').form({json: "diagnosis_state: DIAGNOSED"})
Related
I'm fairly new to node.js and trying to make a simple website which first asks the authentication and then redirects the user to a page.
so, what i do is that i create a middleware which listenes to every request made to my website.
what this middleware does that it checks if the the user is logged in with my website or not is yes then redirect to the requested page if not, then redirect to the login page, here is my code for that.
var express = require('express');
var app = express();
// middleware for using static files
app.use('/public', express.static(__dirname + '/public')); // all the js files for check_before.html
app.use('/templates', express.static(__dirname + '/templates')); // here are css/js files for login.html
// setting up views folder
app.set('views', __dirname + '/views'); // check_before.html is sitting here
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use((req, res, next) => {
res.render('check_before.html');
// here in the html I implement the logic using js files which are located in public folder.
next();
});
// if not logged in , the user gets here
app.get('/login', (req, res, next) => {
res.render('login.html')
});
// if logged in redirect to some page
app.get('/welcome_page', (req, res) => {
return 'welcome'
});
everything goes well untill the user hits the http://localhost:8000/login page (after the check if they are signed in or not) the page keeps on loading multiple times and it won't stop reloading.
I have defined all the css, js files of login.html page in the templates folder which is loaded above the middleware by reffereing to this question
Express middleware getting called many times. could that be a problem?
what could be the reason for this?
here is the error i'm getting in the console.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
any guesses?
Edit1
I went through this question Error: Can't set headers after they are sent to the client , and i guess it concludes that setting headers explicitly could be problematic.
Could this be a reason? because in my logic if the user is not signed In, I'm just using window.location.replace('http://localhost:8000/login') to redirect the user to login page.
should I use any another method for redirection?
Edit2
There are suggestions that i must write a middleware to check is the user is authenticated or not, and get a sort of flag for that, but as i've stated above that i'm implementing the logic in check_before.html(client side). so it won't be possible to use that.
I have two guesses:
You shouldn't call send (or any other function )after res.render.
Middleware to verify user is logged in should be something like this (applied only to routes you want to verify user)
Middleware should be something like this
const isAuthenticated = (req, res, next) => {
if(req.isAuthenticated()) {
next();
} else {
res.redirect('/');
}
}
app.get('/welcome_page', isAuthenticated, (req, res) => {
return 'welcome'
});
The reason is that middleware is called before your /login request. To fix it, you need to modify your middleware function. It should be something like:
app.use((req, res, next) => {
if(isLoggedIn) { //isLoggedIn is a flag that checks whetehr user is logged-in or not
res.render('check_before.html');
} else {
// here in the html I implement the logic using js files which are located in public folder.
next();
}
});
I thought this was a caching issue, but after three complete removals of all code on my server, I'm still encountering the same issue:
Express Generator comes with the default error handling in the app.js file:
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.redirect('/');
});
I have since replaced that code with my own catch all route, using app.all:
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
app.use('/users', users);
// catch 404 and forward to error handler (catch-all)
app.all('*', function(req, res) {
res.render('index.html');
});
Keep in mind that the render statement works. I'm using a single page application and I need it to redirect back to the index.html file.
This actually works locally, but does not work on my server. The server is a Node.js server.
The default message for the 404 error is "Not Found". No matter how many times I remove this code and the 404 error message, I continue to see "Not Found" (Express.js style) on my browser, instead of a redirect to my home page.
Coming back to this question, the issue was with my web host. The server uses Phusion Passenger and the app.js on the Node.js server needed to be restarted.
I needed to create a file in the root of the server called restart.txt inside of a folder named 'tmp':
nano tmp/restart.txt
Afterwards, if I wanted to manually restart the server, I would have to run the following command:
touch tmp/restart.txt
Which would restart the app.js file.
I'm doing an university project with NodeJs but I have some trouble in testing it in local.
This is the problem:
I have a GET API "/api/services/names" and the NodeJS server is running on port 8080.
If I test the API with Postmanor by putting the URL in the Chrome bar ("http://localhost:8080/api/services/names") it works fine and I can get my response.
The problem is that if I test it in my local website using fetch() inside this function:
function fetchServicesNames(){
fetch('/api/services/names')
.then(function(response){
return response.json();
})
.then(function(data){
data.map(addServiceLink);
});
}
The Javascript console gives me this error:
Failed to load resource: the server responded with a status of 404 (Not Found)
I noticed that when I hover the console error, it shows the request string "http://localhost/api/services/names" without the port. But I don't think this is the problem because when I deploy the application on the Heroku platform it works fine... the problem is just in localhost (I'm working with a mid 2010 macbook pro with Mac OSX 10.10.2).
Any help is appreciated, thank you in advance.
Edit:
as requested I'm adding here the server code
// server.js for Hypermedia Application project.
// BASE SETUP
//============================================================
// call packages
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(express.static(__dirname + "/public"));
// we use body-parser, so we need to be able to read data either from
// GET and POST:
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// setting the application port to listen
var serverPort = process.env.PORT || 5000;
// --- database connection omitted ---
// API ROUTES
// ================================================================
// first of all: get the Router
var router = express.Router();
/**
* Services names
* /api/services/names - get - get all services ids and names
*/
router.route('/services/names')
.get(function (req, res) {
Service.find({}, 'id name', function (err, services) {
if (err)
res.send(err);
res.json(services);
});
});
// --- Other APIs omitted ---
// REGISTER ROUTES:
// all of our routes will be prefixed with /api
app.use('/api', router);
// START THE SERVER
//===================================================================
app.set("port", serverPort);
app.listen(serverPort, function() {
console.log(`Your app is ready at port ${serverPort}`);
});
at your server page you add
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
before your API's
it might help you for CORS
Dear i suggest you to write total Path like
http://localhost:<your port number>/api/services/names
inside fetch()and u check once
I too tried and i got Success
Hi try modifying the line like fetch('http://'+window.location.host+':8080/api/services/...)
I'm not new to JavaScript but I am new to Node.js and back end languages. I have a very simple question.
I've installed and setup Node.js on my computer and I'm attempting to get a server going between my static files & directory(s) and my browser to be able to send and receive requests. I've downloaded Braintree's free Sandbox (found here) for practice to get some faux transactions going just to gain a better understanding of how this can work.
I set up a local server by running npm install -g http-server on my command line and then http-server to set it up.
I then received the following message in my command line:
Starting up http-server, serving ./public
Available on:
http://127.0.0.1:8080
http://10.0.1.4:8080
Hit CTRL-C to stop the server
So, with this setup...if I wanted to do get() and post() methods and see it rendered and communicating between my "server" and my static files. How do I do this? For example, if I were to set up Braintree's sandboxed environment and then create a clientToken using the following code from Braintree's website
const http = require('http'),
url = require('url'),
fs = require('fs'),
express = require('express'),
braintree = require('braintree');
const gateway = braintree.connect({
environment: braintree.Environment.Sandbox,
merchantId: "xxxxx",
publicKey: "xxxxx",
privateKey: "xxxxx" //blocked out real numbers for privacy
});
Here is the remaining code I hae to create a "client Token" for a transaction...and here is the guide I'm following via Braintree's website...
http.createServer((req,res) => {
gateway.clientToken.generate({
},(err, response) => {
if(err){
throw new Error(err);
}
if(response.success){
var clientToken = response.clientToken
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(clientToken);
res.end("<p>This is the end</p>");
} else {
res.writeHead(500, {'Content-Type': 'text/html'});
res.end('Whoops! Something went wrong.');
}
});
}).listen(8080,'127.0.0.1');
So, my question is...if I wanted to generate send a token to a client using the get() method...how would I do that? Would it have to be a separate js file? How would they be linked? If they're in the same directory will they just see each other?
Here is an example on Braintree's website of how a client token may be sent:
app.get("/client_token", function (req, res) {
gateway.clientToken.generate({}, function (err, response) {
res.send(response.clientToken);
});
});
How could this be integrated into my current code and actually work? I apologize if these are elementary questions, but I would like to gain a better understanding of this. Thanks a lot in advance!
I don't know much about braintree, but usually you would use somthing like express.js to handel stuff like this. So I'll give you some quick examples from an app I have.
#!/usr/bin/env node
var http = require('http');
var app = require('../server.js');
var models = require("../models");
models.sync(function () {
var server = http.createServer(app);
server.listen(4242, function(){
console.log(4242);
});
});
So that's the file that gets everything started. Don't worry about models, its just syncing the db.
var express = require('express');
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = express();
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
// share public folder
app.use(express.static(path.join(__dirname, 'public')));
require('./router.js')(app);
module.exports = app;
next up is the server.js that ties eveything together. app.use() lines are for adding middleware and the app.use(logger('dev')); sets the route logger for what your looking for.
app.use(express.static(path.join(__dirname, 'public'))); shares out all files in the public directory and is what your looking for for static files
var path = require('path');
module.exports = function(app){
//catch
app.get('*', function(req, res){
res.sendFile(path.join(__dirname, '..', 'public', 'index.html'));
});
}
last piece is the router.js. This is were you would put all of you get and post routes. generally I've found that if you see app.get or app.post in examples there talking about express stuff. It's used a lot with node and just makes routing way easier.
Also if your using tokens a route would look like this.
app.get('/print', checkToken, function(req, res){
print.getPrinters(function(err, result){
response(err, result, req, res);
});
});
function checkToken(req, res, next){
models.Tokens.findOne({value: req.headers.token}, function(err, result){
if(err){
res.status(500).send(err);
}else if(result == null){
console.log(req.headers);
res.status(401).send('unauthorized');
}else{
next();
}
});
}
so any route you want to make sure had a token you would just pass that function into it. again models is for db
I'm using Node and Anugular, and I have created a RESTful api from my application, and created an angular resource to use this. I'm confused as to how the Angular ui-router directive reconciles with the Node Routing system on the server.
At the moment I have set up my routes/states in ui-router like this:
$stateProvier
.state('admin', {
url:'/admin',
templateUrl:'views/admin.html',
controller: 'adminController'
});
And this loads into the ui-view on my homepage, when I navigate to this url from a link on the loaded page.
HOWEVER, when I manually type in localhost/admin I get the route from Node, rather than the state render through angular.
Now I'd like to Angular to handle all the navigation on my app, and my resource to get the information, even if the address is typed manually into the navigation bar.
I've created a route in Node is for index, which contains my index.html page from angular, which effectively contains the whole app angular code, including all the routing.
My question is, how can I get angular redirect if I manually type the url into the address bar, and still have the data from the $resource.
I'm directing my resource to '/admin' - could this be the problem?
Does this mean that I need to add the contents of /routes/appointments' into the base node file (server.js), and then remove the route? If so then how do i direct my resource to the correct REST api?
app structure
public
-angular app
-app.js //for angular
routes
index.js
appointments.js
models
views
- index.ejs
server.js //node server file
here is my code exerpts
server.js
//standard routing code
var routes = require('./routes/index');
var appointments = require('./routes/appointments');
var app = express();
//configuring Express
app.set('port', process.env.PORT || 3000);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use('/', routes);
app.use('/', appointments);
routes/index.js
var express = require('express');
var router = express.Router();
// ./routes/index.js
router.get('/', function(req, res) {
res.render('index', { title: 'Homepage' });
});
module.exports = router;
routes/appointments.js - this is the basis of my RESTFUL api
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Todo = require('../models/Appointments.js');
/* GET /todos listing. */
router.get('/admin', function(req, res, next) {
Todo.find(function (err, todos) {
if (err) return next(err);
res.json(todos);
});
});
module.exports = router;
One way to do this is via the Accept header. If the request only accepts JSON then let the request go through to your API. If the request accepts HTML then always serve up your index page. Then once the index page loads angular's router will take care of the rest.
// Angular config - default Accept header for all ajax requests
$httpProvider.defaults.headers.common = {
'Accept': 'application/json'
};
// Middleware in Node to "intercept" non JSON requests
// Place this after express.static middleware but before your route definitions.
app.use(function(req, res, next) {
// keep in mind this applies to all requests, so 404s will need to be handled by your angular app since any url will serve up the index page
if(req.header('Accept') !== 'application/json') {
console.log('serving the index page');
req.url = '/'; // force the url to serve the index route.
}
next();
});
One more thing to note about this approach is that obviously you won't be able to see/debug your JSON data by hitting the URL directly anymore. There are several useful tools like Advanced REST Client or POSTman which actually give you better control and more options for things like that. Just make sure you set the Accept header in one of those tools and you'll be able to see the JSON response.
The actual URL is localhost#!/admin, try that. Angular hides the hashbang #!
Angular's URL routing is an "illusion" in that way. It only works on the client-side and only when your Angular app is loaded, which is on the main / route.
A solution could be to conditionally redirect from localhost/admin to localhost#!/admin, i.e. redirecting to your Angular app and passing it the #!/admin path. The condition could be a check for whether or not JSON was requested.
router.get('/admin', function(req, res, next) {
if(req.header('Accept') !== 'application/json')
return res.redirect('/#!/admin');
Todo.find(function (err, todos) {
if (err) return next(err);
res.json(todos);
});
});
You'll also need to configure Angular such that when it requests '/admin' json data from the server, it should only accept json (by setting the request header), which is how the the server will distinguish it from the regular '/admin' request. For that, if you're using $http.get you would do $http.get('/admin', {'Accept':'application/json'})