Sorry in advance for my lengthy post.
I am having difficulty changing from MERN localhost to an online hosting. I've been hosting my frontend/ client side website on heroku, with the file structure as follows:
Client Structure
- build
- src
- App.js
- Index.js
- Other Components, Images, Fonts, Pages
-package.json
-package-lock.json
This file structure works fine with heroku.
However, I've been following a Youtube tutorial that uses a MERN stack to build a blog: https://www.youtube.com/watch?v=OML9f6LXUUs&t=3s --> it is a 3 part series
In the video, he has a file structure as such:
API and Client Structure
- api
- images
- models
- public
- routes
- index.js
- package.json
- package-lock.json
- client (frontend code)
- build
- src
- App.js
- Index.js
- Other Components, Images, Fonts, Pages
-package.json
-package-lock.json
2 Instances of LocalHost
He runs api on localhost:3001 and client on localhost:3000.
Methodology
1. Storing Images
He does not store images in MongoDB cloud, but rather store the image name only, and stores the images directly on the api/images directory.
In the api folder, he uses multer to store the images.
app.use("/images", express.static(path.join(__dirname, "/images")))
const storage = multer.diskStorage({
destination: (request, file, callback) => {
callback(null, 'images');
},
filename: (request, file ,callback) => {
callback(null, request.body.name);
},
})
const upload = multer({storage: storage});
app.post('/api/upload', upload.single('file'), (request, response) => {
response.status(200).json('File has been uploaded');
});
Then in the client side, he sends the data via axios:
const response = await axios.post('/upload', data);
2. Retrieving Images
When retrieving, he specifies a public folder PF, uses axios to get the image name, and then concatenates them to get the images.
const PF = "http://localhost:3001/images/";
<Image src={PF + post.image} />
My question is:
How can I change from a localhost to a cloud based hosting (preferably Heroku)? What paths do I specify? I would think that this image retrieval works because I am running both locally on the same computer. I wouldn't be able to use it if they are online as the image src directory will not be searchable
Is it possible to host both simultaneously on 1 Heroku Dyno, and how can I do it?
This is my first time learning backend so thanks for the patience!
Firstly, you'll have to remove all hardcoded 'http://localhost:3000`. This would interfere with the cloud site since it uses its own.
Instead, you could use an environment file to store the API site and in production use a different one.
You will need to make a mongodb cluster (its a cloud database and its free) https://www.mongodb.com/docs/atlas/tutorial/create-new-cluster/. You'll have to manually change your database to the cluster link. I would use an environment variable for this as well, so the db link would be something like this in your db file
const mongoURI = process.env.MONGODB_URI || 'mongodb://localhost:27017/ProjectAPI'
where process.env.mongodb_uri contains cluster uri
In the server file where you host your routes add this to the end of your file and change to match your app:
app.use(express.static(__dirname + "/../client/build"));
app.get("*", (req, res) => {
// check for page routes that we expect in the frontend to provide correct status code.
const goodPageRoutes = ["/", "/login", "/home"];
if (!goodPageRoutes.includes(req.url)) {
// if url not in expected page routes, set status to 404.
res.status(404);
}
// send index.html
res.sendFile(__dirname + "/../client/build/index.html");
});
After that just follow the guide: https://devcenter.heroku.com/articles/git and https://devcenter.heroku.com/articles/deploying-nodejs
Related
I am hosting React app on Netlify and NodeJs server on Heroku.
The image is hosted on the server directory, in an "image" folder..
// Build the image path
const file = req.file ?
req.protocol + '://' + req.get('host') + '/' + req.file.path
: null;
The code above is building the image link which will be stored in the database and will be looking like "https://home-renter.heroku.com/images/1663093729973.jpg". Normally, if I paste the link on the browser, the server should send the image...
But in this case I get 404 error....
The image link is saved into the mongodb as
In the chrome console I have the following errors and warnings:
I do not know what should I look for. I dont have a starting point...
Update. If I add a house, and upload images, the image selection works. However if I refresh the page, the website crashes and send 404...
// Static files
const path = require('path')
app.use('/images', express.static(path.join(__dirname, 'images')));
app.get('/', (req, res, next) => res.send('Wellcome to home renter'));
Update
The problem was while I was deleting the images from the post. I was splitting the image link from 3000 (port) instead of the new URL.
I have an app.js node main file where I define my api path as the following
app.get('/api/users', UserController.get);
Below in the same file I have the following
app.use(express.static(path.resolve(__dirname, "./front/build")));
app.get("*", function (request, response) {
response.sendFile(path.resolve(__dirname, "./front/build", "index.html"));
});
The index.html successfully serves React App.
If I open my heroku app somewhere at my-app.herokuapp.com it will open the React app which is intended but the Problem is my-app.herokuapp.com/api/users also serves index.html file instead of JSON that the endpoint is supposed to return.
I tried
I replaced endpoint route definition to come before the "" definition (didn't suffice)
EVEN more, I removed redirection to index.html but heroku still opens the index.html page with any type of request (the "" redirection still works). So, it might have cached something?
Is it about cache (how to clean?) or any other suggestions?
You should create routes and work in a proper flow for each functionality,
For Example:
//app.js
app.use("/api/user",userRoutes);
//UserRoutes
router.post("/signup",UserController.signup);
//UserController
exports.signup = async (req,res,next) => {
//Signup function to add a new user when the user provides required info
}
In this way, you code will be easily accessible and much efficient
I have a node.js API with several endpoints that is working great. I have created a separate vue.js client app to manipulate data with the API I created. This is also working great. I have run into an issue where I need these apps to be running on the same port so a third party proxy system can access both these apps simultaneously.
I have seen a way to do this by copying the dist directory over to the node server but since I need this for a production env I need an alternative that dynamically builds the front end when building the node API as well.
Is there a production level alternative to adding a client app to run on an existing node server? Any recommendations or help would be greatly appreciated!
Update: I've added this to my router file and have client and server in one project
const path = require('path');
const router = express.Router();
router.use(express.static(path.join(__dirname, '../client/dist')));
//production mode
if(process.env.NODE_ENV === 'production') {
router.use(express.static(path.join(__dirname, '../client/dist')));
//
router.get('/test', (req, res) => {
res.sendFile(path.join(__dirname = '../client/dist/index.html'));
})
}
//build mode
router.get('/test', (req, res) => {
res.sendFile(path.join(__dirname+'../client/dist/index.html'));
})
You can expose the dist directory built with vue-cli using a express static route. This directory should have your built assets along with index.html
app.use('/app', express.static(path.join(__dirname, '../client/dist'));
However, now since your application is not at the root directory you have to add a base url to your vue.config.js. Rebuild the app after this.
module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? '/app/' : '',
...
...
...
}
Now your vue app should be available at
/app/index.html
I have installed bitnami parse server from the AWS market place to provide the backend for an iOS app. In the iOS app the API is configured under http://myURL.com/parse and when I go to what I thought would be the homepage, http://myURL.com, it instead redirects me to the parse dashboard located at http://myURL.com/apps. I would like to have http://myURL.com serve a homepage for my app instead of redirecting to the parse dashboard so that a web application can be constructed that shares the same data the app uses. This is my first project using node.js so I am hoping someone could point me in the right direction on a couple of topics. My previous web application work was always on a LAMP stack so I am curious:
Am I correct to assume that the parse backend that iOS uses can also be the backend for a web application accessed through a browser?
When I analyze the code in server.js at /home/bitnami/apps/parse/htdocs I don't see a function that is redirecting to myURL.com/apps, is there a different area I should be focussed on to understand how myURL.com gets redirected to the apps folder?
I noticed that a folder exists at /home/binami/apps/rockmongo with installation instructions of php scripts, can my AWS instance run php AND the node.js or will installing a LAMP stack interfere with the node.js stack?
I am sure there is some great documentation and/or tutorials on this, can you help me get started by providing the correct way to phrase google searches or even better any links to tutorials themselves?
For context my iOS lets users log on and lets them upload images to parse server classes, I simply want to let the users log on and upload an image from a web browser using the same parse server which has the user/file classes.
For Reference below is the server.js which appears to somehow be directing requests from myURL.com to myURL.com/apps:
require('dotenv').config();
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var app = express();
// Specify the connection string for your mongodb database
// and the location to your Parse cloud code
var api = new ParseServer({
databaseURI: "mongodb://root:9dh********#127.0.0.1:27017/bitnami_parse",
cloud: "./node_modules/parse-server/lib/cloud-code/Parse.Cloud.js",
appId: "19defd7********",
masterKey: "cd8********",
fileKey: "3bce6********",
serverURL: "http://54.**.**.**:80/parse",
filesAdapter: {
"module": "#parse/s3-files-adapter",
"options": {
"bucket": process.env.S3_BUCKET,
}
},
});
// Serve the Parse API on the /parse URL prefix
app.use('/parse', api);
var port = 1337;
app.listen(port, function() {
console.log('parse-server running on port ' + port);
});
//Parse Dashboard
var ParseDashboard = require('parse-dashboard');
var dashboard = new ParseDashboard({
apps: [
{
appName: "My Bitnami Parse API",
appId: "19defd7********",
masterKey: "cd8d*******",
fileKey: "3bce6********",
production: true,
serverURL: "http://54.**.**.**:80/parse"
}
],
users: [
{
user: process.env.ADMIN_USER,
pass: process.env.ADMIN_PASSWORD
}
], useEncryptedPasswords: true
});
var allowInsecureHTTP = true;
// Serve the Parse Dashboard on the /parsedashboard URL prefix
app.use('/', dashboard);
var portdash = 4040;
app.listen(portdash, function() {
console.log('parse-dashboard running on port ' + portdash);
});
Mount point for Parse Dashboard is definded in this line:
app.use('/', dashboard);
When you want to use a separate mount point for dashboard you can do this:
app.use('/dashboard', dashboard);
After changing if you hit http://myURL.com/dashboard it will load the dashboard in /dashboard/apps. '/apps' endpoint is handled by parse dashboard itself.
Now if you want to load your website in root route (/) or the http://myURL.com, you need to create another route (assuming you want to serve a static site for now)
app.use('/public', express.static(path.join(__dirname, '/public'), {
etag: true
}));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, '/public/index.html'));
});
To serve a static site you need to create a folder from where you will server the static site. In this case, I created a folder named as public and place all of my html,css,js there. Now I need to specify the static folder in express. That's what I did in the first line. After that, I simply serve the index.html by creating a 'GET' route.
You can do a lot of other things too like creating APIs or serve a dynamic website as well as using parse server. But to do that you must understand express framework with nodejs first.
Update:
Parse API and Dashboard are two separate things. You can run only parse-server without dashboard and vice-versa. In your code, you mount the parse-server in /parse endpoint. Look at this line
app.use('/parse', api);
So now the parse-server is available in /parse endpoint. You can change it to anything. Make separate endpoints for both parse-server and dashboard.
I am new to nodeJS server area, need help in understanding how to work with REST API (using express) and deploy the angular application over a singe node server and same ports.
By deploying i want to understand if user hit below url http://localhost:8000/<page_name> then the specified page should open.
And is user hit below url using get or post request
http://localhost:8000/api/<api_name> then a json or a text will be returned.
How to run both the thing over a single node server.
Lets assume, you have all your static files in the /public folder of you app. Generally spoken, if you are using express.static, you should also get your index.html because this is handled by default for each directory.
In your case, as you are using Angular, the routing is handled from the client side (SPA). You should only have one single index.html after building your Angular app. All files from your dist folder should then be placed into your /public folder. Then you need to make sure, that initial file serving provides your index.html like so:
In this example static files are served first, then your API and if nothing is found, you are getting back you index file.
const express = require('express');
const app = express();
// serve static files
app.static(__dirname + '/public'));
// serve your API
app.get('/api/welcome', function (req, res) {
res.send('Welcome');
});
// fallback routing (server side handling)
app.get(/.*/, function (req, res) {
res.sendFile(__dirname + ‘/public/index.html‘
});
app.listen(3000);
Next time please make sure, to give all necessary information in your question ;-)
With the help from Sebastian, so far I can find a solution but its not working when i am hitting URL for different pages.
const express = require('express');
const app = express();
app.use(express.static('public'))
Please provide your suggestions.