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.
Related
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
Ive been trying to deploy a Twitch like application using react, redux, node media server and json server module to Heroku. However, I keep running into a issue when trying to connect my react client and express server via a api request, during production.
Im trying to make the actual request through my action creators and by using axios with a base url of http://localhost:4000, however that only works on my local machine.
const response = await streams.get("/streams");
dispatch({ type: FETCH_STREAMS, payload: response.data });
};
You can view my full repo at https://github.com/XorinNebulas/Streamy
You can also view my current deployed version of the site on Heroku at
https://streamy-app.herokuapp.com/
here is my api/server.js file. My express server will be watching on a random port equal to process.env.PORT, so I have no way of knowing how to make a network request via my action creators to that random port during production.
const path = require("path");
const cors = require("cors");
const jsonServer = require("json-server");
const server = jsonServer.create();
const router = jsonServer.router("db.json");
const middlewares = jsonServer.defaults({
static: "../client/build"
});
const PORT = process.env.PORT || 4000;
// Set default middlewares (logger, static, cors and no-cache)
server.use(cors());
server.use(middlewares);
if (process.env.NODE_ENV === "production") {
// Add custom routes before JSON Server router
server.get("*", (req, res) => {
res.sendFile(
path.resolve(__dirname, "../", "client", "build", "index.html")
);
});
}
// Use default router
server.use(router);
server.listen(PORT, () => {
console.log(`JSON Server is listening on port ${PORT}`);
});
I expected the request to go thru and load up some data from api/db.json, with a resquest url of https://streamy-app.herokuapp.com/streams but instead i got a request url of http://localhost:4000/streams, which of course leads to the CORS issue below
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:4000/streams. (Reason: CORS request did not succeed).
I would truly appreciate any suggestions, been working on this for days.
Alright looks like I figured it out. I simply went into streams/client/package.json and added
"proxy":"http://localhost:4000"
I then went into streams\client\src and deleted the api folder which contained my custom axios with a base url. using instead axios out of the box for my action creators
const response = await axios.get("/streams");
dispatch({ type: FETCH_STREAMS, payload: response.data });
};
Now while running locally in development mode, I'm able to make a request to http://localhost:4000/streams, but after deploying my node app to Heroku I successfully make a request over to https://streamy-app.herokuapp.com/streams
hope this helps someone with slimier issues.
First, you should know that Heroku doesn't allow to expose multiple ports, which means you should change the approach of multiple ports to something else (see this answer).
Second, the file client/src/apis/streams.js is hard-coded configured to send requests to http://localhost:4000/ - which is not a good idea.
Whatever approach you choose - even deploying to another host server - you will need to dynamically configure the API endpoint, per environment.
I would also recommend you to:
Change the way you deploy react, as explained here.
After doing the above, consider consolidating your API service with the static server, so that you don't need multiple ports, and then everything becomes easier.
I have express on back-end and react.js on frontend, but i also have admin page with pug view engine, working on express routes, how can i use these in one domain
Expressjs is composable in a really nice way. You can have a top level express application which routes off to sub-express apps and serve your individual services.
Lets say you want to serve your react frontend from www.example.com, your admin (pug views) from www.example.com/admin, and you also want to have an api which serves the react frontend at www.example.com/api`.
You would want something a bit like the following code sample which demonstates the composition of express applications. I've not run the code but it should be enough to get you going.
// This parent app acts as a parent layer and router
// for all your "sub apps". Any middleware you apply
// to this express app will apply to *all your other
// sub-apps*.
const parentApp = express();
// We now create another express instance, this will
// house the API. It can be in another file and you
// could require in something like "require('api');"
// instead but for brevity we'll keep it all in one
// file.
const apiApp = express();
apiApp.get('/info', (req, res, next) => {
console.log('/info');
return res.sendStatus(200);
});
// Mount the sub app on the /api route. This means
// you can how hit 'www.example.com/api/info' and
// you'll get back a 200 status code.
parentApp.use('/api', apiApp);
// Now we setup the admin app which we'll add pug
// views into. This is an example so just pretend
// the views exist.
const adminApp = express();
adminApp.set('views', './views');
adminApp.set('view engine', 'pug');
adminApp.get('/login', (req, res, next) => {
return res.render('login', { title: 'Hey' });
});
// Mount the sub app on the /admin route. This way
// we can hit www.example.com/admin/login to get
// our login page rendered.
parentApp.use('/admin', adminApp);
// Now we create and mount the frontend app that
// serves our fully built react app. You could do
// this with nginx instead but you wanted to do
// it with express so lets do it that way.
const frontendApp = express();
frontendApp.use(express.static('/frontend));
parentApp.use('/', frontendApp);
If you'd rather not create yourself a top level express app (and thus creating a bit of a monolith application) then I'd recommend checking out the nginx documentation, or the docs for the HTTP server you use. You should be able to direct requests to particular endpoints to different node applications running on different ports. Static files can then be served natively by your HTTP server. This is definetely a more efficient and elegant approach, but since you asked about express I wanted to showcase that approach primarily.
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.
My website is a SPA built with Angular, but it uses SSR with Angular Universal to provide crawlable and social media sharing content.
All GET requests in my server are handled by Universal like this:
app.engine(
'html',
ngExpressEngine({
bootstrap: ServerAppModuleNgFactory,
providers: [provider]
})
)
app.set('view engine', 'html')
app.set('views', __dirname)
app.use('/', express.static('./dist', {index: false}))
app.use('/', expressStaticGzip('./dist', {
enableBrotli: true
}))
app.get('/*', (req, res) => {
res.render('./dist/index', {
req: req,
res: res
})
})
and my pages contents are provided by Angular Services POST requests built with the same queryParams of the requested url.
One example:
If the user visits the url https://mywebsite.com/products?page=1&itemsPerPage=12 (GET request by default), the Angular Universal app and the Angular Router dynamically build my page template and the products list is provided by a Service that triggers a POST request to this URL: https://mywebsite.com/request-products with the following params in body:
{
page: 1,
itemsPerPage: 12
}
Then the Universal App builds the template with some *ngFor directives to populate it before serving it to the client.
This approach makes all my pages visible to webcrawlers and I also get the benefits of a Single Page Application.
When I'm testing my app, I build my Angular app, both Browser and Server builds, and set my environment like this:
export const environment = {
production: true,
apiUrl: 'http://localhost:7070/'
}
and serves my app in localhost, it works perfectly, without errors. My POST requests, like mentioned before, are all handled perfectly. But when I try to set my apiUrl to 'https://mywebsite.com/' and serve my app also in localhost, to access directly my API hosted in Heroku, I just can't access my POST routes.
My node express server app in Heroku is configured to accept requests from other domains, I can access it normally in my localhost server, but when I try to access it through my Angular Universal server build, it just won't work.
I know that I have to use absolute URLS in my Universal Apps, and I'm doing it already, but it's not working.
Does anyone know what I have to do to access external APIs in my Angular Universal Apps via https?
Thanks!
I've found the problem, and it's something really simple.
It turns out that I must use 'www' in my absolute url, like this:
'https://www.mywebsite.com/'
Now everything works perfectly, both from my localhost and my heroku servers.
Thanks to everyone that took some time to read my question!