bldg14 / eventual

A simple event calendar
https://eventual-client.fly.dev
MIT License
0 stars 0 forks source link

Kf/5 link server client #17

Closed kevinfalting closed 1 year ago

kevinfalting commented 1 year ago

Overview

We need to be able to run the client and server on separate ports and still have them talk to each other. This maintains React's hot reloading capabilities without requiring the server to be running.

Resolves #5

Thought Process

I initially thought this was a CORS problem, and while it is, it's not necessarily a problem for purely local development. The only required change to link the two for local development is adding a proxy to package.json.

However, since we do plan to run this in a publicly available fashion, I decided to also tackle the CORS problem, which was relatively straightforward. Preferably, we'd like to not have to prepend all fetch calls on the client with the server address. Additionally, since the stdlib doesn't have a great way to manage middleware, and I had been looking for an opportunity to test my homegrown github.com/kevinfalting/mux module, I swapped it in.

I then wrote a CORS middleware and applied it to the top level mux.

Testing Steps

You can test that the proxy works by just running the client and server after adding the following snippet anywhere in the client:

(async () => {
  try {
    const res = await fetch("/api/v1/events");
    console.log(await res.json());
  } catch (e) {
    console.log("failed to fetch:", e);
  }
})();
  1. client: npm start
  2. server: go run ./cmd/eventual
  3. You'll need to open the devtools console in your browser to see the output.

And then to test that the CORS is working, remove the "proxy": "http://localhost:8080", from the package.json file. You'll need to restart React after making this change. This will return some wacky error because it's no longer proxy-ing the request. You'll need to make the following change to the snippet you previously added to the client:

(async () => {
  try {
    const res = await fetch("http://localhost:8080/api/v1/events"); // here
    console.log(await res.json());
  } catch (e) {
    console.log("failed to fetch:", e);
  }
})();

Then you'll be getting the response successfully because of CORS.

Now, let's break it by turning off CORS. Comment the following line in cmd/eventual/main.go:

// middleware.CORS("http://localhost:3000"),

and rerun the server. The request should fail and output the following error in the browser's console:

Access to fetch at 'http://localhost:8080/api/v1/events' from origin 'http://localhost:3000' has been blocked by CORS policy: 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' to fetch the resource with CORS disabled.

And that's that!

Risks

Doing it this way means that we're not really properly testing our CORS implementation, and if we change something that might violate it, without proper testing it will find it's way into production and break. The proxy trick is only relevant in development mode, so once we're ready to start publishing to the public, we'll have to revisit this. The assumption is that in production we'll be serving the client from the some origin as the server. A problem left for later.