coupergateway / couper

Couper is a lightweight API gateway designed to support developers in building and operating API-driven Web projects
https://couper.io
MIT License
85 stars 15 forks source link

Inject server data to a SPA #626

Closed malud closed 1 year ago

malud commented 1 year ago

There are some concepts how to bring e.g. environment related configurations to a Single Page Application. One of them is to replace a __SERVER_DATA__ placeholder at the apps index.html while serving it to the client.

<!DOCTYPE html>
<html lang="en">
  <head>
    <script>
      window.SERVER_DATA = __SERVER_DATA__;
    </script>
  </head>
</html>

Which could be configured like this:

spa {
    bootstrap_file = "/htdocs/index.html"
    paths = ["/**"]
    # replaces __SERVER_DATA__ in bootstrap_file (marshalled+cached on startup)
    server_data = {
        "apiUrl": env.API_URL
        "idp": {
          "clientId": env.IDP_CLIENT_ID,
          "idpUrl": env.IDP_URL
      }
    }
  }

To prevent a XSS Vulnerability we have to html-escape the content. (https://pkg.go.dev/encoding/json#HTMLEscape) Related article: https://medium.com/node-security/the-most-common-xss-vulnerability-in-react-js-applications-2bdffbcc1fa0

filex commented 1 year ago

I'm not sure if I like __SERVER_DATA__ so much. It seems to be common to put such initial config in a var in the window object. But each framework calls it differently.

Therefore, I propose to call the config item bootstrap_data and the placeholder __BOOTSTRAP_DATA__:

spa {
  paths = ["/app/**"]
  bootstrap_document = "build/index.html"
  bootstrap_data = {
     apiUrl = env.API_URL
     env = couper.environment
     version = env.APP_VERSION
  }
}
<script>
  window.appContext = __BOOTSTRAP_DATA__;
</script>

Can we choose our name freely? Or is it better to align with a common placeholder, so the local dev-web-servers (like webpack) can use the same?

We could also make the placeholder configurable:

spa {
  paths = ["/app/**"]
  bootstrap_document = "build/index.html"
  bootstrap_data = {
     apiUrl = env.API_URL
  }
  bootstrap_data_placeholder = "__SERVER_DATA__"
}
malud commented 1 year ago

Sounds good to me along with a configurable placeholder we should solve all custom requirements.