I've been Googling for some time, but can't find any useful answers. I'm trying to get a subdomain for an api on my website api.example.com. However, all answers said that I needed to change my DNS to redirect api.example.com to example.com/api, which I don't want. Is it possible to just serve api. instead of redirect to /api? How would I go about doing that?
I'm using express.
I don't want to use any other packages that aren't built-in.
const path = require('path'),
http = require('http'),
https = require('https'),
helmet = require('helmet'),
express = require('express'),
app = express();
const mainRouter = require('./routers/mainRouter.js');
// security improvements
app.use(helmet());
// main pages
app.use('/', mainRouter);
// route the public directory
app.use(express.static('public'));
app.use(/* API subdomain router... */)
// 404s
app.use((req, res) => {
res.status(404).sendFile(path.join(__dirname, "views/404.html"));
})
I recommend You to use nginx and separate api service.
But because of some reasons You cannot avoid it (or You don't want it, cause You just want show prototype to customer ASAP).
You can write middleware that will catch host from header and forward to some custom router:
1) /middlewares/forwardForSubdomain.js:
module.exports =
(subdomainHosts, customRouter) => {
return (req, res, next) => {
let host = req.headers.host ? req.headers.host : ''; // requested hostname is provided in headers
host = host.split(':')[0]; // removing port part
// checks if requested host exist in array of custom hostnames
const isSubdomain = (host && subdomainHosts.includes(host));
if (isSubdomain) { // yes, requested host exists in provided host list
// call router and return to avoid calling next below
// yes, router is middleware and can be called
return customRouter(req, res, next);
}
// default behavior
next();
}
};
2) api router as an example /routers/apiRouter.js:
const express = require('express');
const router = express.Router();
router.get('/users', (req, res) => {
// some operations here
});
module.exports = router;
3) attach middleware before / handler:
const path = require('path'),
http = require('http'),
https = require('https'),
helmet = require('helmet'),
express = require('express'),
app = express();
const mainRouter = require('./routers/mainRouter');
// security improvements
app.use(helmet());
// ATTACH BEFORE ROUTING
const forwardForSubdomain = require('./middlewares/forwardForSubdomain');
const apiRouter = require('./routers/apiRouter');
app.use(
forwardForSubdomain(
[
'api.example.com',
'api.something.com'
],
apiRouter
)
);
// main pages
app.use('/', mainRouter);
// route the public directory
app.use(express.static('public'));
// 404s
app.use((req, res) => {
res.status(404).sendFile(path.join(__dirname, "views/404.html"));
})
P.S. It does the same that in express-vhost package, look at the code
There is an official vhost plugin for Express.js: https://github.com/expressjs/vhost
What you are describing, having multiple domains/hostnames hosted/handled by a single server, is typically referred to as a "vhost" (virtual host).
It will definitely be possible to point just the subdomain (api.example.com) to your api server.
DNS doesn't control subdirectories so a DNS entry of example.com/api would be invalid
If you have an IP address for your server you will need to add an A record with the value: api.example.com.
If you have a domain name for your server you will need to create a CNAME record.
Related
Could you help me solve this error? It seems that I can not connect between server.js and app.js.
What I want to do is: display the result of the postData('/add', {answer:42}); and postData('/addMovie', {movie:'the matrix', score:5}); in the console.
Thank you for your help in advance.
error image
server.js
// Setup empty JS object to act as endpoint for all routes
projectData = {};
// Require Express to run server and routes
const express = require('express');//add
// Start up an instance of app
const app = express();//add
/* Dependencies */
const bodyParser = require('body-parser') //add
/* Middleware*/
//Here we are configuring express to use body-parser as middle-ware.
//we can connect the other packages we have installed on the command line to our app in our code with the .use() method
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Cors for cross origin allowance
const cors = require('cors');//add
app.use(cors());//add
// Initialize the main project folder
app.use(express.static('website'));
////////////////////creating a local server
const port = 5500;//add
// Setup Server
//////////////////////add
const server = app.listen(port, listening);
function listening(){
// console.log(server);
console.log(`running on localhost: ${port}`);
};
app.get('/all', function (req, res) {
res.send(projectData)
})
// POST route
const data = []
app.post('/add', callBack);
function callBack(req,res){
res.send('POST received');
console.log(data)
}
const movieData = []
app.post('/addMovie', addMovie )
function addMovie (req, res){
movieData.push(req.body)
console.log(movieData);
}
app.js
app.js
[Addition]
Thank you for your feedback!!
I changed the port in server.js, but nothing changed.
port5500
The issue was resolved.
// when using local server ( ≒ server.js in this case)
postData('/add', {answer:42});
postData('/addMovie', {movie:'the matrix', score:5});
// when using live server
postData('http://localhost:5500/add', {answer:42});
postData('http://localhost:5500/addMovie', {movie:'the matrix', score:5});
You need to add an "allow" in the header field to support this or explicitly allow it in your webserver configuration
A lot of the time, this is set up in the configuration of your .htaccess or nginx.conf file (depending on the webserver). It will commonly be found in your RewriteRule section. You can look for a "R=405" flag there.
I've got a React app that via an API pulls data from a separate database.
When I run it locally, the app is one port and the API is on another port.
Since when I make AJAX calls in the app to the API, I need to include the URL where the API can connect.
It works if I hardcode the separate port (e.g., the app is on http://localhost:3000 and the API on http://localhost:3100, making the AJAX url call to the API http://localhost:3100/api/trusts).
However, since the app and API are on different ports, I can't make the AJAX url a relative path because it erroneously sends the AJAX call to http://localhost:3000/api/trusts and not http://localhost:3100/api/trusts.
How do I get them to run on the same port?
Thanks!
Here's my server.js:
var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var path = require('path');
var app = express();
var router = express.Router();
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//set our port to either a predetermined port number if you have set it up, or 3001
var port = process.env.PORT || 5656;
//db config
var mongoDB = 'mongodb://XXX:XXX!#XXX.mlab.com:XXX/XXX';
mongoose.connect(mongoDB);
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
//body parsing
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// allow cross-browser
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
next();
});
// handling static assets
app.use(express.static(path.join(__dirname, 'build')));
// api handling
var TrustsSchema = new Schema({
id: String,
name: String
});
var Trust = mongoose.model('Trust', TrustsSchema);
const trustRouter = express.Router();
trustRouter
.get('/', (req,res) => {
Trust.find(function(err, trusts) {
if (err) {
res.send(err);
}
res.json(trusts)
});
});
app.use('/api/trusts', trustRouter);
//now we can set the route path & initialize the API
router.get('/', function(req, res) {
res.json({ message: 'API Initialized!'});
});
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(port, function() {
console.log(`api running on port ${port}`);
});
Below is the AJAX call I'm trying to make that doesn't work because the relative path is appended to the app's port (i.e., http://localhost:3000/) and not the API's port (i.e., http://localhost:3100/):
axios.get("/api/trusts")
.then(res => {
this.setState({trusts: res.data});
})
.catch(console.error);
To tell the development server to proxy any unknown requests to your API server in development, add a proxy field to your package.json, for example:
"proxy": "http://localhost:4000",
This way, when you fetch('/api/todos') in development, the development server will recognize that it’s not a static asset, and will proxy your request to http://localhost:4000/api/todos as a fallback. The development server will only attempt to send requests without text/html in its Accept header to the proxy.
"Keep in mind that proxy only has effect in development (with npm start), and it is up to you to ensure that URLs like /api/todos point to the right thing in production."
Note: this feature is available with react-scripts#0.2.3 and higher.
More details here: https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#proxying-api-requests-in-development
I'm trying to use https://github.com/bmullan91/express-subdomain for subdomain routing in express. The following are the contents of my main.js and src/routes/site files.
const express = require('express');
const bodyParser = require('body-parser');
const subdomain = require('express-subdomain');
const siteRouter = require('./src/routes/site');
const app = express()
app.use(express.json() );
app.use(express.urlencoded());
app.use(express.static('public'));
app.use(subdomain('*.www', siteRouter));
app.get('/', function(req, res) {
res.send('Homepage');
});
const server = app.listen(80,'x3.loc', function () {
var host = server.address().address;
var port = server.address().port;
console.log('X3 listening at http://%s:%s', host, port);
});
const express = require('express');
let router = express.Router();
router.get('/', function(req, res) {
res.send('Welcome to site');
});
module.exports = router;
This way of doing app.use(subdomain('*.www', siteRouter)); has been suggested in https://github.com/bmullan91/express-subdomain/issues/33 but does not work.
I have also tried just * as the subdomain aswell, but that caused the homepage w/o a subdomain, to get treated like one aswell. How could I get this to work?
We know that / matches any base path regardless of subdomain. So I made your homepage middleware "subdomain-aware" like so:
app.get('/', function(req, res,next) {
/* If there are any subdomains, skip to next handler, since request is not for the main home page */
if (req.subdomains.length > 0) {
return next();
}
res.send('Homepage');
});
Then I placed the middleware for subdomains below the homepage middleware like so:
app.use(subdomain('*', siteRouter));
This makes homepage middleware to serve requests for x3.loc and the subdomain middleware to serve requests for any subdomain like api.x3.loc or api.v1.x3.loc.
But in my opinion, the real fix should be done in the module. I think it should be changed so that either the case where req.subdomains being empty is handled, or * is matched against an actual string, instead of skipping the iteration.
I am surprised that the fix suggested in bug 33 worked as-is for the reporter. In my testing, it works the opposite way i.e. www.example.com goes to subdomain middleware while stat1.example.com goes to the homepage middleware. Perhaps the reporter saw this and swapped the middleware bodies.
I'm attempting to build a MEAN app and trying to test POSTing with POSTMAN. When I do, I keep getting the dreaded "TypeError: Cannot read property 'name' of undefined". If I type in a simple string, the POST goes through fine. But when I use "req.body.name" I get the error. I've looked in every place and I'm not seeing my mistake. I even followed the suggestions on this thread with no luck. Any help or suggestions would be greatly appreciated.
Here's the code I am currently working with in my server.js file:
const express = require('express');
var bodyParser = require('body-parser');
var Bear = require('./models/bear')
var path = require('path');
var mongoose = require('mongoose');
var router = express.Router();
var app = express();
var staticAssets = __dirname + '/public';
app.use(express.static(staticAssets));
app.use('/api', router)
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// Routes for my API
//===================================
// middleware to use for all requests
router.use(function(req,res,next){
// logging happens here
console.log('Something will happen.');
next(); // Head to the next router...don't stop here
});
// Test router to make sure everything is working (accessed at GET http://localhost:3000/api)
router.get('/', function(req, res){
res.json({message: 'hooray! welcome to our api!'})
})
//More routes will happen here with routes that end in "/bears"
router.route('/bears')
//Create a bear (accessed at POST http://localhost:3000/api/bears)
.post(function(req,res){
var bear = new Bear(); // Create a new instance of the bear model
console.log(req);
bear.name = req.body.name; // set the bears name (comes from the request)
//res.send(200, req.body);
bear.save(function(err){
if (err)
res.send(err);
res.json({message: 'Bear Created!!'});
});
});
//======================================
//var Products = require('./products.model.js');
var Product = require('./models/product.model');
var db = 'mongodb://localhost/27017';
mongoose.connect(db);
var server = app.listen(3000);
console.log("App is listening on port 3000");
Thanks.
Also, the url I'm trying to use inside of POSTMAN is http://localhost:3000/api/bears
Express processes requests Top-Down, meaning if you require a piece of functionality to be applied to all routes via middleware, than that middleware needs to be added to your app before any routes that require it. This is usually the case for middleware such as body-parser.
When using Router Middleware, you don't typically construct the router in the same file as the actual Express app that will use it as middleware. Instead, place it in a separate file and/or directory for organization purposes, this is considered a best practice.
Express Apps can be structured like so
/lib
/models
bear.js
product.js
/node_modules
/public
/css
/routes
api.js
package.json
server.js
The routes directory is where you would place any applicable Router Middleware files such as your api router. server.js is your main Express App and public is where your static assets are stored. lib is directory that contains any business logic files and models.
The actual Express app and Router files should look something like this
server.js
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const apiRouter = require('./routes/api');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, public)));
app.use(/api, apiRouter);
app.listen(port, () => {
console.log(`Listening on port ${port});
});
module.exports = app;
routes/api.js
'use strict';
const router = require('express').Router();
const Bear = require('./lib/models/bear');
router.use((req, res, next) => {
// logging happens here
console.log('Something will happen.');
next(); // Head to the next router...don't stop here
});
router.get('/', (req, res) => {
return res.json({ message: 'hooray! welcome to our api!'})
});
router.route('/bears')
//Create a bear (accessed at POST http://localhost:3000/api/bears)
.post((req, res) => {
var bear = new Bear(); // Create a new instance of the bear model
console.log(req);
bear.name = req.body.name; // set the bears name (comes from the request)
//res.send(200, req.body);
bear.save((err) => {
if (err)
return res.send(err);
return res.json({message: 'Bear Created!!'});
});
});
module.exports = router;
To note, you could break up your API even further to increase the amount of decoupling. An example of this would be to move the /api/bear route to its own router middleware and into its own route file. Then simply add it to your routes/api.js router as a middleware like you would in server.js. If your app is going to have a decent sized API, then this would be the best approach because it would allow the most flexibility when it comes to applying middleware to only certain routes and would make maintaining the source much easier.
I'm writing an API using Node.js and Express. My API has GET methods of the form:
/api/v1/doSomething
/api/v1/doSomethingElse
My code is looking something like this:
server.js:
var app = express();
...
var routes = require('./routes')
routes.attachHandlers(app, '/api/v1')
routes/index.js
...
module.exports.attachHandlers = function(app, context) {
//get a list of all the other .js files in routes
//for each route, require() it and call it myRoute
myRoute.attachHandlers(app, context)
}
routes/some-route.js
...
module.exports.attachHandlers = function(app, context) {
app.get(context + '/doSomething', doSomething)
app.get(context + '/doSomethingElse', doSomethingElse)
}
...
Effectively I'm passing the context path/mount point down through the app. If somebody were to write a route like the following, though, the context would be lost:
app.get('/doFoo', foo)
Rather than having that part of the API mounted on /api/v1/doFoo it's on /doFoo. I would like to avoid having to pass the context path around like this.
app.use supports mounting middleware on an optional mount path. I have seen references online to mounting an entire Express application on a mount path using app.use. This seems like the sort of thing I want to do, but I'm not sure how to do it or if it's the best solution for my particular use case.
To summarise - I want to mount my app.get() routes with a particular prefix by default. What's the best way of doing this?
With Express 4.0, the task is much cleaner with the Router. You can create as many routers as you need to nicely partition your app, and then attached them with app.use(). For example:
myapp.js
var express = require("express"),
router = express.Router(),
app = express(),
port = 4000;
// Here we declare our API which will be visible under prefix path
router.get('/', function (req, res) {
console.log("request to subspace hello");
res.send({ message: "Hi from subspace /api/v1/"});
});
// we attach our routes under /api/v1
app.use('/api/v1', router);
// here we have direct, root-level routing
app.get('/', function (req, res) {
console.log("request to rootspace hello");
res.send({message: "Hi from root /"});
});
app.listen(port);
console.log("App active on localhost:" + port);
Then run
node myapp.js
and visit
http://localhost:4000 and http://localhost:4000/api/v1
Here's a working example of mounting a route in Express 3:
./snipe3app.js
var express = require('express');
var app = module.exports = express();
app.get('/subapp', function (req, res) {
res.send('You are on the /sub/subapp page.');
});
./app.js
var express = require('express'),
http = require('http'),
subApp = require('./snipe3app'),
app = express();
app.use(express.favicon());
app.use(express.bodyParser());
app.use(app.router);
app.use('/sub', subApp);
app.get('/', function (req, res) {
res.send('You are on the root page');
});
http.createServer(app).listen(3000, function(){
console.log('Express server listening on port 3000. Point browser to route /secure');
});
You have to pay attention to the order in which the routes are handled when doing this.
I think express-namespace will work for this.