I have a kinda tricky situation: I'm currently building a full meteor-featured application. But I also need to expose some functionality as REST-Service for automation reasons (a third party application should be able to insert and receive data via REST).
The express.js-package seems to be a very solid option for building a REST-Endpoint into a node.js environement but I'm wondering how to integrate this endpoint into meteor.
What I want is to access the "normal" Site via for example http://myfancysite.com/my-display-route and at the same time be able to access my REST-Endpoint via for example http://myfancysite.com/api/insert-crazy-data/.
The "normal" Site is accessible via the port defined when starting Meteor. The thing is, that I have to specify a different port for express.js to listen on and I want both - meteor and express - to share the same port since I don't want to access the REST-Endpoint on a different port.
Is this somehow possible? :D
Here's some code I use for express at the moment.
//<meteor-root>\server\main.jsx
import { Meteor } from 'meteor/meteor';
// do some meteor things
...
//require express
var express = require('express');
//create application
var app = express();
//use environement defined port or 3000
var port = process.env.PORT || 3000;
//create router
var router = express.Router();
//define routes
...
//register all routes with '/api'
app.use('/api', router);
//start server
app.listen(port); // <= this should be the same port as the meteor application itself!
console.log('listening on port ' + port);
Meteor is essentially a node app that already exposes a connect http server, which means you can define server routes simply like:
import { WebApp } from 'meteor/webapp';
WebApp.connectHandlers.use('/hello', (req, res, next) => {
res.writeHead(200);
res.end('Hello world from your server');
});
If you insist on using express, then you can register your express routes as connect middleware like so:
import { Meteor } from 'meteor/meteor';
import { WebApp } from 'meteor/webapp';
import express from 'express';
const app = express();
app.get('/api', (req, res) => {
res.status(200).json({ message: 'Hello from Express!!!'});
});
WebApp.connectHandlers.use(app);
Et voilà!
Related
Background
I am migrating an Angular app in GKE cluster. The base docker image that I must use(company policy) does not have any options to install any new softwares like shell, Angular cli command ng etc. The base docker image has only Node installed.
There is a shared base url, let's say, www.my-company.com, that everyone has to use for app deployment with a path added after the base url like www.my-company.com/my-angular-app/ - all the other Angular apps must be differentiated using the path of the app.
What I did
Since I can't run ng serve command in the base image, I added Express dependency in the package.json in Angular application and created an express server to route the traffic to Angular app.
I was following this youtube video to configure the application - https://www.youtube.com/watch?v=sTbQphoYbK0&t=303s. The problem I am facing is to how I load the the static files in the application.
If I define absolute path inside sendFile method of server.js file, although the application is working, but in future, if I need to add any other files in the application, I have to create another route in server.js file.
I don't know how Express can search a file automatically from the static folder(and sub folders) and return only that file when needed. I defined a static folder too, but seems like it is not working.
Following is my server.js code
==============================
const express = require('express');
const http = require('http');
const path = require('path');
const port = 8080;
const contextPath = '/my-angular-app';
const router = express.Router();
const app = express();
app.use(contextPath, router);
app.listen(port, ()=> {
console.log("Listening on port: ", port);
});
app.use(express.static(__dirname + '/dist/testapp/'));
router.get('/', function(req, res) {
// to get index.html file
res.sendFile(path.resolve(__dirname + '/dist/testapp/index.html'));
});
router.get('/*', function(req, res) {
let path = __dirname +'/dist/testapp/' + req.path
console.log('full path: ', path);
// To return static files based on incoming request, I am facing problem here(I think)
res.sendFile(path);
});
==============================
I want Express will send any files based on file name in the request. It should also take care of nested directories in the /dist/testapp/ directory
/dist/testapp/ -> This is the directory where Angular generates code for my app after I execute ng build command
WEBAPP.get("/admin/script.js", (req, res) => {
console.log(req.path);
if (req.session.username !== "Admin") return res.render("error");
res.sendFile(__dirname + "/admin/admin.js")
});
WEBAPP.get("/admin", (req, res) => {
if (!req.session.loggedin) return res.render("error");
if (req.session.username !== "Admin") return res.render("error",);
res.render("admin", {
csrfToken: req.csrfToken(),
title: "ADMIN PORTAL",
username: req.session.username,
nav_avatar: GetImageURL(req.session.avatar, "small")
});
});
There's no need to publically share /admin/script.js in my case but if a user requests this URL say example.com/admin/script.js a check for username equaling "Admin" if all is okay we sendFile.
I would maybe assume that you're not properly targeting your static files. Perhaps console.log the target.
I think I am missing some concept with basic routing for Express. See here
I created some simple test code as follows in my server index.js file.
app.get('/foo', function (req, res) {
console.log('foo path found');
res.send('foo achieved')
})
In my browser(chrome) URL I type
localhost:3000/foo
to trigger the route but I get no response on the server or client.
I verified localhost:3000 is up and running.
Port is set in a different file as follows:
app.set('port', (process.env.PORT || 3000));
But also I get confirmation in the terminal as follows:
const server = app.listen(app.get('port'), () => {
console.log('DEBUG: express: server up');
});
I am on a campus network that blocks some traffic, but b.c. this is localhost I don't think it should matter.
I don't think you're supplying enough information to correctly debug your issue.
I'd initially ensure that Express is listening on port 3000, double-check this line:
app.listen(3000);
Ideally, this line should be at the bottom of the script.
Response to edit: Yes, this should not matter. localhost is an alias for the system itself. It's a loopback, similar to that of 127.0.0.1.
It seems like you have created two express app, as you have mentioned that you are using two different files, the localhost which you are able to run is the one which has app.listen() code, but this doesn't have the app.get()
I suggest you use a single file for now and try doing it.
Try out the following code, and check now with localhost:3000/foo.
const express = require('express')
const app = express()
const port = 3000
app.get('/foo', function (req, res) {
console.log('foo path found');
res.send('foo achieved')
})
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
When the user goes to mydomain.com/game, I want the user to see what is displayed in my public folder. This works completely fine when I do this:
app.use('/game', express.static('public'))
The problem is that I want to extract some information from the URL, but as I do not know how to continue the routing when using a static site, I can't extract any information. For example, if the user inputs mydomain.com/game/123, I want to retrieve 123, but still route the person to my public folder, like mydomain.com/game does.
Any ideas on how to handle this problems?
This has worked for me in a similar situation
app.use('/game/:id', (req, res) => {
// do something with id
res.redirect(302, '/game');
}
Try to use two middlewares: first is your static middleware, the secont is the fallback, with id (123)
app.use('/game', express.static('public'));
app.use('/game/:id', function(req, res) { // when static not found, it passed to this middleware, this process it
console.log('your id', req.params.id);
res.send('ok');
});
If you are using react static files and you want to serve all react routes using express then you have to do thing like below-
1.First of all you have to run command in your react folder
npm run build
this will create your build folder in react app having one index.html file which you have to serve through express.
Now come to your server.js file and write there
const express = require('express');
var path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'client/build')));
app.get('*', (req,res) => {
res.sendFile(path.join(__dirname+'/client/build/index.html'));
});
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server up and running on port ${port} !`));
I’m building an API for a SPA built with Angular 2, for this app I have a stand alone API and than an Angular 2 app. So they are on built on two separate node.js servers. I’m using node.js and express along with 'express-connection' and 'mysql' modules to build a secure API to handle login and registration with JWT’s (json web tokens), along with other tasks of course. So I’ve successfully built this API so I can access data with my Angular 2 app via a URL. I can use the URL ’localhost:3000/data’ to access a json data object from my Angular 2 app running on 'localhost:3001/'. However, I also need the API to have access to this data object (an array of users) once the data becomes available. What is the best way to approach/accomplish this task? The only way I can think of now is to have a setTimeout function that waits for the app to load than uses an http get to grab the data from the url. There must be a cleaner way of accomplishing this task. Heres some code I have working, basically a simple node server running express. I'm somewhat new with building API's and Angular 2 concepts so any help is greatly appreciated.
app.js
/** Dependencies **/
var logger = require('morgan'),
cors = require('cors'),
http = require('http'),
express = require('express'),
errorhandler = require('errorhandler'),
dotenv = require('dotenv'),
bodyParser = require('body-parser');
/** Setup **/
var app = express();
dotenv.load();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());
app.use(function(err, req, res, next) {
if (err.name === 'StatusError') {
res.send(err.status, err.message);
} else {
next(err);
}
});
if (process.env.NODE_ENV === 'development') {
app.use(logger('dev'));
app.use(errorhandler())
}
/** Requires **/
require('./config/sql.js')(app);
require('./config/routes.js')(app);
/** Port **/
var port = process.env.PORT || 3001;
http.createServer(app).listen(port, function (err) {
console.log('listening in http://localhost:' + port);
});
routes.js
// routes.js
module.exports = function(app) {
var query = require('./query.js')(app);
app.get('/data', function(req, res) {
query.getData(req,res);
});
};
sql.js
var connection = require('express-myconnection');
var mysql = require('mysql');
module.exports = function(app){
app.use(
connection(mysql,{
host : 'localhost',
user : 'root',
password: ‘password’,
port : 3306,
database: ‘my_project’
}, 'request')
);
};
query.js
// DB Queries
module.exports = function(app){
return {
getData: function(req, res) {
req.getConnection(function(err,connection){
connection.query('SELECT * FROM users',function(err,rows){
// console.log("success: ", rows);
res.json(rows);
});
});
}
}
};
user.js
setTimeout(function(){
// http.get function to call to API and grab data and create variable
},500);
// this is where I need an array of users that I get from a mysql database for login and registration logic
var users = [];
I'm not sure I got why you need the Angular code to talk to a different UrL but I would write the server code to take the requests from Angular and then internally reach out to the other API to get the data required. Basically use the node server to act like a proxy to reach the other API.
jfriend00 is right in his comment, this is a question of asynchronous calls.
You are looking for the initial requests to kick off the following: Frontend Request > NodeJS API > Database Query
And the response to fulfill and return promises to create a response chain in the reverse order: Database Response > NodeJS API > Frontend Response
You are probably looking for the angular function $http.get with .then() to perform your frontend calls. But you also need an asynchronous function to request the data from within the API or a database instance, then provide it on an endpoint that the frontend can consume. For that you need a promise or callback in your server-side code as listed in jfriend00's comment.
Consider working on just your NodeJS API until you can achieve the response and requests you need, and build out your frontend with Angular later. The users.js file is a fine endpoint to start on.
I'm building a node.js server and my folder structure looks like this:
server.js
app/routes.js
app/routes/users.js
My problem is that i'm not sure how can i use the app variable inside the users.js file. Do i have to require and setup express again in this file or is there a better/easier way to do it? Here is my sample code(just the bare minimum to understand my problem):
server.js
// Include our packages in our main server file
var express = require('express');
var stormpath = require('express-stormpath');
var app = express();
// Init Stormpath for user management and authentication
app.use(stormpath.init(app));
// Load routes
require('./app/routes')(app);
// Start the server
app.listen(process.env.PORT);
// Stormpath will let you know when it's ready to start authenticating users.
app.on('stormpath.ready', function () {
console.log('Your server is running on port ' + port + '.');
});
app/routes.js
// Import dependencies
const express = require('express');
const stormpath = require('express-stormpath');
// Export the routes for our app to use
module.exports = function(app) {
// Create API group routes
const apiRoutes = express.Router();
// User management: get users, invite users, view user profile
var UsersRoute = require('./routes/users');
apiRoutes.get('/memberinfo', stormpath.loginRequired, UsersRoute.memberInfo);
// Set url for API group routes
app.use('/', apiRoutes);
};
app/routes/users.js
// Protected route test
module.exports.memberInfo = function(req, res){
//how do i access the "app" here?
res.status(200).send({ user: req.user });
}
In your .memberInfo method, you can use req.app to access the app object that is associated with that request.
In cases where you aren't passed a req object that you can use in this way, then you need to initialize the module by calling a method on it and passing it the app object and the module can then store the app object locally so it can use it when desired.