JavaScript files are executed at client side, by the browser. The browser does not have access to the server config files, so it is the server's responsibility to read/get proper config values and make them available to the client.
There are multiple ways to deal with this. I will outline some possible solutions.
1. Include the correct endpoints in the HTML files
You may choose to include the correct endpoints in the HTML files that refer to the javascript files in which they would be used.
The HTML files would be templates and not static files, and you can use the html/template
package to execute those templates to include the necessary URLs and everything else you need, and generate the final HTML that will be sent to the clients.
The HTML template may contain a <script>
tag initializing certain JavaScript variables, which then can be used from the included JavaScript files.
Here's a simple example passing the featured httpendpoint
.
HTML Template ("home.html"
):
<html>
<head>
<script>
var featuredHttpEndpoint = "{{.FeaturedHttpEndpoint}}";
</script>
<script src="view.js"></script>
<script src="featured.js"></script>
<script src="home.js"></script>
</head>
<body>Your body</body>
</html>
And the handler that would serve this HTML template:
var homeTempl = template.Must(template.New("").ParseFiles("home.html"))
func homeHandler(w http.ResponseWriter, r *http.Request) {
m := map[string]interface{}{
// Insert the value of endpoint from your config
"FeaturedHttpEndpoint": "http://localhost:8081/api/services/featured/",
}
if err := homeTempl.Execute(w, m); err != nil {
// Handle error
}
}
Mapping the home handler e.g.:
http.HandleFunc("/index.html", homeHandler)
And make sure the home page is not cached, so the browser will always ask for a fresh copy in which your server can insert the actual config values.
2. Perform AJAX requests from the JavaScript files
You may choose to perform AJAX requests from the JavaScript files to query the necessary information. A simple example of this can be found in this question: Dynamically refresh a part of the template when a variable is updated golang
In a real-life example you would transmit all the config values that the client needs with one request (e.g. in JSON format), here I only transmit a single value.
Getting / sending only the featured httpendpoint
:
In JavaScript:
var featuredHttpEndpoint = "";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var config = JSON.parse(xhr.responseText);
featuredHttpEndpoint = config.FeaturedHttpEndpoint;
}
}
xhr.open("GET", "/config.json", true);
try {
xhr.send();
} catch (err) {
// handle error
}
And the Go handler providing the config values:
func configHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
m := map[string]interface{}{
// Insert the value of endpoint from your config
"FeaturedHttpEndpoint": "http://localhost:8081/api/services/featured/",
}
if err := json.NewEncoder(w).Encode(m); err != nil {
// Handle error
}
}
Which must be mapped to the path the client calls, e.g.:
http.HandleFunc("/config.json", configHandler)
3. Use Javascript files as templates
You may also choose to make your Javascript files templates, and when serving them, you may use a template engine to include endpoints based on your environment / APP_STAGE
. See point #1 as an example to serving templates.
If you're going down this path, you have to take care of properly configuring caching of the Javascript files, as the browser will not ask you again for the js files if their caching info says they are not expired.