In my case, Nginx was responding with the index.html source file thanks to not configuring reverse-proxying properly. In such case, the response returns http 200 (ok) perfectly, but there is practically "no server home" (so to speak) to return the expected json response.
So, the fix is simply to setup reverse-proxying in the Nginx.conf file. Here is an excellent resource that explains how Nginx proxying works: https://www.digitalocean.com/community/tutorials/understanding-nginx-http-proxying-load-balancing-buffering-and-caching
For example, for a React app with a backend dependency on an API (all deployed on Kubernetes, say), the .conf file can be like:
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
location /foo {
proxy_pass http://bar-service.default.svc.cluster.local:8080;
}
Note the reverse-proxying being enabled here by proxy_pass, in this (example) case to a Kubernetes API service, using its fully-qualified DNS name (with namespace as "default" and port included). Also note that /foo here represents your API server's URL in the frontend. In React it could be implemented like:
export const getFoo = () => {
const api = '/foo'
return sendRequest('GET', api);
};
The React app's build can be Dockerised for Nginx's proxying something like:
FROM nginx:alpine
COPY build/ /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
ENTRYPOINT ["nginx", "-g", "daemon off;"]
With such you can now setup, for example, a Kubernetes Ingress service using a manifest like:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress
spec:
rules:
- host: my-host.com
http:
paths:
- path: /*
backend:
serviceName: frontend-service
servicePort: 80
The Ingress controller in this case can forward all traffic to the frontend React app via a NodePort service like:
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
selector:
app: react-frontend
.. with its Deployment manifest as:
apiVersion: apps/v1
kind: Deployment
metadata:
name: react-app
spec:
selector:
matchLabels:
app: react-frontend
template:
metadata:
labels:
app: react-frontend
spec:
containers:
- name: app-container
image: my-react-app-image
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
Finally, the backend service that Nginx passes API traffic to can be like (and note the service name):
apiVersion: v1
kind: Service
metadata:
name: bar-service
spec:
selector:
app: api
ports:
- port: 8080
targetPort: 8080
.. with its Deployment manifest say as:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 2
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api-container
image: my-api-container-image
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
location /api/v1/*supposed to do? Nginx does not use shell wildcard characters inlocationstatements. See this document./api/v1/*is meant to mark any API request, for eg-hostname.com/api/v1/usersorhostname.com/api/v1/user/id