External Backend Service, Redirect Help

Hello Netlify enthusiasts! I’ve come across this difficulty with several Netlify apps in the past and am hoping to learn the best practice once and for all.

I commonly have to interact with a completely external backend service that I do no control in any way. My frontend infrastructure is typically a very normal create-react-app service that uses react-router.

In local development, I cannot hit this API directly:

fetch(https://externalservice.com/users/)

Because it will cause a CORS issue fetching from localhost:3000.

I solve this by putting a proxy in my package.json, a create-react-app feature:

{
   "proxy": "https://externalservice.com"
}

At which point, relative frontend queries work expectedly, like:

fetch(/users)

During local development, my apps work perfectly now. However, when I got to deploy the app is where my problems begin. Of course, now the relative fetch requests do not work, because the proxy is only for local development.

I go to my netlify.toml file and add:

[[redirects]]
  from = "/*"
  to = "https://externalservice.com"

Which nearly works, except that now when my React-Router does not appear to work.

https://myapp.com/homepage

Will always return route not found. Searching online shows me that this is because you need something like this change to your YAML file in order to let client side routing take effect:

[[redirects]]
  from = "/*"
  to = "/index.html"

But I cannot make this change since the from is the same.

Any and all help or guidance is greatly appreciated, thanks :pray:

Welcome to the forums @trevorwhealy

Excellent first post!

Correct, to make React Router work you need

[[redirects]]
  from = "/*"
  to = "/index.html"

in a netlify.toml or the following in a _redirects file

/*    /index.html    200

This rewrite is a must.

Rules are processed top to bottom and _redirects rules are processed first then netlify.toml rules. Better to choose one file for redirects only.

To proxy to another service the convention is to have a rewrite

[[redirects]]
  from = "/api/*"
  to = "https://api.somewhere.com/v1/:splat"
  status = 200

Rather than using

fetch("https://api.somewhere.com/v1/users", ...)
// or
fetch("/users", ...)

as previously, all calls go via the /api e.g

fetch("/api/users", ...)
// or
fetch("/api/user/123456", ...)

This rule (and any other rules) must go above the SPA catch-all rule otherwise everything gets routed back to the SPA.

[[redirects]]
  from = "/api/*"
  to = "https://api.somewhere.com/v1/:splat"
  status = 200

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

or if you wanted to use a _redirects

/api/*   https://api.somewhere.com/v1/:splat    200
/*    /index.html    200

If you have any questions or issues, don’t hesitate to reply.

1 Like

@coelmay Could you please tell what to do if I have the API routes not start with /api and instead stay the same as /

On the face of it though, I might suggest not using / for routes and use a specific path.

A little more information on your use case might help @veb.

@coelmay thanks for the quick reply.

What I meant was that all my API routes don’t start with a /api
For example, Login POST route is /login and my Login page route is also named /login on the React Router.

I tried this _redirects file but it doesn’t seem to work:

/*  /index.html  200
/*  https://website.com/:splat  200

API calls work if I reverse the order but then my pages don’t load.

I was hoping that Netlify would first check if the page exists on the frontend. And if it gives a 404, it would redirect the traffic to the backend.

I am not very experienced in this so sorry if this is a noob question.

The behaviour you are seeing is correct and expected. In the case of an SPA with a router, Netlify has no way of checking what pages exist—this is all handled internally by the router. If you have index.html, about.html, contact.html, etc. then yes, Netlify will know if the requested resource exists or not.

As is stated above, move all your external calls to a dedicated path (e.g. /api) and put this rule above the SPA rewrite. This is a much more practical way of doing things.

1 Like