I would need to extend http package to achieve non standard response containing error description in status ie: 400 Required parameter is missing instead of 400 Bad request that is standard status description.
This is my actual implementation:
package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
)
type GatewayHandler int
func main() {
var gh GatewayHandler
http.ListenAndServe(":9000", gh)
}
func (gh GatewayHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
legacyApiUrl := "http://some-url.com" + req.URL.RequestURI()
client := &http.Client{}
request, _ := http.NewRequest(req.Method, legacyApiUrl, nil)
response, _ := client.Do(request)
res.Header().Set("Status", response.Status)
for k, v := range response.Header {
fmt.Println(k, ": ", v)
i := ""
for _, j := range v {
i += j
}
res.Header().Set(k, i)
}
res.WriteHeader(response.StatusCode)
if response.Status != "200 OK" {
fmt.Println(response.Status)
}
result, _ := ioutil.ReadAll(response.Body)
output := string(result)
fmt.Println(output)
io.WriteString(res, output)
}
In general I need to forward that status from other URL that uses it and I need to keep it compatible.
Thank you very much in advance.
Jozef
You can use the http.Hijacker
interface https://golang.org/pkg/net/http/#Hijacker to "hijack" (take over) the server's TCP connection to the client and write to it the custom response. Here is a modification of the example https://golang.org/pkg/net/http/#example_Hijacker to return "400 Required parameter is missing" instead of the standard "400 Bad request" response to the client:
package main
import "net/http"
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
hj, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError)
return
}
conn, bufrw, err := hj.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Don't forget to close the connection:
defer conn.Close()
// non-standard HTTP status text and an HTTP header are written;
// end of the Headers part of the messages is marked by extra \r\n
bufrw.WriteString("HTTP/1.1 400 Required parameter is missing\r\nContent-Type: text/html; charset=utf-8\r\n\r\n")
// write the body of the HTTP response message
bufrw.WriteString("400 Required parameter is missing\n")
bufrw.Flush()
})
http.ListenAndServe(":9000", nil)
}
Running this program and sending a curl request produces the desired response:
$ curl -i http://localhost:9000/ HTTP/1.1 400 Required parameter is missing Content-Type: text/html; charset=utf-8 400 Required parameter is missing
It should be straightforward to extend it to propagate other responses from your legacy API server.
Edit
used \r\n\r\n
in the example program to terminate the Headers portion of the HTTP response in accordance with the HTTP message standard (https://www.rfc-editor.org/rfc/rfc7230#section-3); separated WriteString
calls for the headers and body of the HTTP response for clarity.