I'm trying to deploy a react-django app to production using digitalocean droplet. I have a file where I check for the current environment (development or production), and based on the current environment assign the appropriate url to use to connect to the django backend like so:
export const server = enviroment ? "http://localhost:8000" : "domain-name.com";
My app is working perfectly both on development and production modes in local system (I temporarily still used http://localhost:8000 in place of domain-name.com). But I observed something rather strange. It's the fact that when I tried to access the site (still in my local computer) with "127.0.0.1:8000" ON THE BROWSER, the page is blank with a console error "No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' ....".
When I changed it back to "http://localhost:8000", everything was back working. My worry is isn't 127.0.0.1:8000 the same as http://localhost:8000? From this I conclude that whatever you have in the domain-name.com place when you build your react frontend is exactly what will be used.
Like I said, I'm trying to deploy to a digital ocean droplet, and I plan to install ssl certificate so the site could be served on https. Now my question is given the scenario painted above, what should be the right way to write the url in production? Should it be "serverIP-address", "domain-name.com", "http://domain-name.com", "https://domain-name.com" ?.
I must mentioned that I had previously attempted to deploy to the said platform using the IP-address in the domain-name.com place. After following all the steps. I got a 502 (Bad gateway) error. However, I'm not saying using Ip address was responsible for the error in that case.
Please I would appreciate any help especially from someone who had previously deployed a react-django app to the said platform. Thanks
From this I conclude that whatever you have in the domain-name.com
place when you build your react frontend is exactly what will be used.
Not exactly true, the domain from which the react app is served will be used. If you build it local and upload it to the server and configure domain.com to serve it, then domain.com will be used for cors. The best idea is to allow all CORS until your project is deployment ready. Once done, whitelist the domain.com
The solution actually lies in providing the host(s) allowed to connect to the Back-end in the setting.py file like so: CORS_ALLOWED_ORIGINS = [ domain-name.com, https:domain-name.com , ... ] etc. That way, you wouldn't be tied to using the url provided in the react environment variable. Though I have not deployed to the server, my first worry within the local machine is taken care off.
Firstly, I just wanted to say that this is my first web application project. I've spent the past few days trying to find answers on how to essentially put the frontend and backend together. I have a lot of questions, but the main one I want answered is on how to return my frontend 'final product' from a backend endpoint.
This is what I understand (please correct me if I'm wrong):
The frontend code is run by the client (browser).
When the client interacts with the webpage, the frontend makes API calls to the backend to retrieve/modify data, as necessary.
The backend and frontend is often developed separately, and could be hosted on separate servers.
It is, however, possible (and maybe simpler) to host it on a single domain/server. I am hoping to do this, in order to avoid a whole set of issues with CORS.
Then comes the following problem:
When I want to test out my front end and see how it's coming along, I just run npm run start. I then go to the given url (usually http://localhost:8080/) and I have access to the frontend that I've developed. And when I want to deploy it, I run npm run build, which gives me a dist folder (bundled together and minified).
If I want to run and test my backend locally, as I am using FastAPI, I simply run uvicorn main:app --reload.
How to put the two together? More specifically, in my backend code, how do I return the product of my frontend work (i.e., the dist folder?). I've tried the following (simplified):
#app.get("/", response_class=HTMLResponse)
def root():
return open("../frontend/dist/index.html", "r").read()
but, of course, this only gives me the static html without the React components.
I realize this post may be loaded with incorrect assumptions and poor practices (in which case, my apologies! and I would appreciate any corrections/suggestions.) However, if the following questions could be answered, I would greatly appreciate it. These are questions I have that will hopefully help me test my whole web application locally on my computer.
How do I return the product of my frontend work for the GET request at the domain root endpoint?
If there is a page A, page B, and page C for my web app, each with url www.example.com/A, www.example.com/B, and www.example.com/C do I have to create three separate React frontend projects? I.e., equivalent of having three dist folders? What is the standard way this is handled?
These are good questions and it is certainly possible. I will tell you what I do, with the caveat that there may be a better way...
I'm using Vue instead of React, but its build process also sends static html, js and css to a dist/ directory, so the process should be about the same.
First you can copy the dist/index.html file you mention into your FastAPI templates/ directory. You will use your FastAPI route to serve that file as a Template.
Then copy your js and css into a static/ directory and make sure FastAPI knows about both static and templates.
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
#app.get("/")
async def serve_spa(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
You may need to set something in React in order for your build to know that the js and css will live in a dir called static. For Vue, there is the assetsDir option within vue.config.js
For your question about handling different paths, like example.com/a and example.com/b, it depends how you want to handle those requests. Are you wanting your single react app to handle all of those routes?
If that is the case, you may want to see also: How to capture arbitrary paths at one route in FastAPI?
One option is to copy the serve_spa() route above and handle your routes, like /a, /b, etc.
Or use a catch-all route:
#app.route("/{full_path:path}")
async def catch_all(request: Request, full_path: str):
print("full_path: "+full_path)
return templates.TemplateResponse("index.html", {"request": request})
The "traditional" approach to running a web application is to have a server that serves your web application (i.e. your React app). Usually you'll hear about nginx being used as the web server being used for modern day single page applications. When you run npm run start you start up a local server on your machine and it makes your app available at http://localhost:8080 (the port and hostname are of course configurable).
When it comes to your API, it should be it's own server available at a different endpoint/url, and then your web app will make API calls to that endpoint/url in order to fetch data.
The way you're describing things, it sounds like you're trying to use FastAPI to server render your web app, but I'm not sure how feasible that is, especially considering there is an entire framework solely dedicated to server rendering react applications.
I've also struggled with this and here's an approach that worked for me
import logging
from fastapi import FastAPI
from starlette.responses import RedirectResponse
from starlette.staticfiles import StaticFiles
app = FastAPI()
#app.get("/")
async def index():
return RedirectResponse(url="/index.html")
app.mount("/", StaticFiles(directory="backend/ui/"), name="ui")
Note: Please observe that app.mount is called after registering the / route. From my experience if the mount is called before the registration then it will simply not redirect to index.html
Note: I use react-scripts to generate the app.
Dear hainabaraka
Your question resembles this one: How do I serve a React-built front-end on a FastAPI backend?. In that one, I contributed an answer, but I'd like to also refer you to Mike Chaliy's answer, which updates mine.
In any case, here are two thoughts on that solution (that I should really update) and the answers you get here:
the nginx approach: this removes responsibility from your code, meaning that it also removes control from you. DevOps love this kind of "you do your thing and let me worry about that" approach, but let's just say that this is a good solution... not for your case. You want to serve from your API.
By the way, "it should be it's own server" has no apostrophe!
the Jinja2 approach: I'm not sure this would work, and even if it did, it would be introdsucing a lot of CPU waste. Jinja2 is an excellent tool for Python based backend tremplate rendering. I used it extensively to generate HTML medical reports to be then PDF-rendered but in this case it always sounds like a "Yes, it works, but...". Rule of thumb for "but"-sentences: everything to the left of the "but" is irrelevant.
the FastAPI RTFM approach: I am a HUGE fan of FastAPI and I'm (extremely slowly) trasnslating its documentation to European Portuguese, but the examples there are very very limited. Referring you to the FastAPI docs is assuming you're an idiot that never thought of that.
other approaches: I saw a bungh of these that, while well intentioned, did not really work because they were either produced by that kinf of people here in SO that don't really test their answer before answering, or by pure back-end devs that have no clue how a React (or a SPA) app works. Some can even serve a home page but then routing kills it.
The solution I present works and has been working for me for years now, both with Vue and React SPAs. The caveat is that you either serve your app from a special endpoint (I suggest /my-spa, which is quite lame), or, if you want the app to come from /, you have to do the
app.mount('/', SPAStaticFiles(directory='folder', html=True), name='whatever')
after all other endpoints, and you cannot obviously have other endpoints conflicting with either / or any React route within it. This perhaps adds to why APIs are recommended to hang from an /api endpoints, and possibly versioned, like /api/v1/.... Please let me know if this works for you.
For that, there an excellent resource in Zalando RESTful API and Event Guidelines.
I defined 2 virtual servers with Nginx to handle
marketing stuff and user authentication on the master domain www.example.com and
the admin app on the subdomain admin.example.com once the user is authenticated
server {
listen 8080;
server_name example.com;
root html;
location / {
index index.html index.htm;
}
server {
listen 8080;
server_name admin.example.local;
root html/admin;
location / {
index index.html index.htm;
}
}
I would like to handle the marketing stuff with an Angular.js one-page app
and the admin stuff with an Angular.js multi-page app..
is it possible ? should I design 2 apps or 1 ap only ?
I don't think that you should split them as they are likely to require lots of the same functions / data. Think DRY design.
You do not want to have to maintain two codebases for one project or have to patch things twice everytime there is a change in the API.
Look closely into the $route documentation and plan your implementation accordingly: you can have an isolated path for your admin without having to duplicate anything. Also, even on the same domain you might run into some weird XHR issues that you will have to code specifically for.
In short, here's my answer: don't split it. If you absolutely want to have admin.domain.com, just do a redirect from your DNS to domain.com/admin and deal with it within a single codebase. Down the line you can slightly refactor your code to match the exact behavior you want. Have a look here for some inspiration: Dynamic routing by sub domain with AngularJS
You can get separated code with modules.
Here is ideally how you you should make it 3 separated projects :
a common module - no index with ng-app or angular.bootstrap. it's alibrary to be shared.
an application module contains a index.html with an ng-app and a bootstrap module
an admin module contains another index.html file wit another bootstrap module
Then you set up 2 builds :
the application build : merging 1 & 2
ther admin build : merginig 1 & 3
But this can be rather difficult to do. So if you can't really made it properly then you merge the application module in the admin one too for the admin build. This shouldn't be a problem.
I have a double project solution: 1) Angular front-end 2) WebAPI back end.
We are deploying to Amazon EC2 instance. On that box I create one website on port 80 (stopping the default) for the Angular code. I also create a second website on a non 80 port for the WebApi. The solution doesn't work on the EC2 box at the moment only on my dev box with dev type settings. Before I choose which remedy path I was wondering what is best practice.
Obviously, one puts the Angular on port 80 because it is html content but what about the api, does one put this on another port or does one use a dns subdomain and still port 80. [At some point I'll need to do https as well so that is a factor, too many ports?]
Both html and webapi's should be served by a single server ultimately.
This is because browers enforce CORS i.e same origin policy. If you receive html content from 'http://domainname:80/index.html', you cannot make ajax and http put/get queries to 'http://domainname:8080/api/feature' and so on.
That being said, you can have a front end listener like nginx or tomcat on port 80 and serve the angular app + all other static html directly on port 80.
i.e you get your page at http://domainname:80/index.html and you can host all the api calls on a different port, but ask nginx to redirect those calls to a different port based on some rule you have to define , subdomain or anything which does not ask for index.html , make them redirect to your another server running on port 8080. Make sure to block public access to this port in your production environment so that nobody can directly call your api's
I have an angular js app whose main container page "index.html" is updated each version. This is hosted in app-engine that I've built using Go. The server end offers straight serving of the html views and the static content as well as a restful API.
It all works great until I push a new version then I have to hard reload the page to avoid getting a 304.
My app.yaml file is really basic right now:
handlers:
- url: /.*
script: _go_app
I'm not setting any caching policies yet so I understand app engine will default the caching of static files for 10 minutes.
What's happening?
I believe I have found the answer.
Two things were bothering me about this:
Firstly, I knew I wasn't handling static files as efficiently as I could have been, it was a job I hadn't gotten around to yet but the static files were being delivered via routing code in the main go script rather than declared in the app.yaml
Using the latter method would let app engine do the work rather than my script and hopefully save a few precious processor cycles.
Secondly I wasn't exactly sure how index.html was being served when the path was "/", it was just working. I know that various web servers (Apache, IIS, etc) have a default page and app engine seemed to be working the same way.
So when I was deciding that each request didn't require any dynamic script I would simply serve it with the following code:
http.ServeFile(w, r, r.URL.Path[1:])
This magically turned "/" into "/index.html" for me but appears to have the caching bug described above. I will take this up with the Go community.
As for the fix, adding the page as a static file to the app.yaml made this work:
- url: /
static_files: index.html
upload: index.html
I will make sure I add all the other static folders too.