Skip to content

Instantly share code, notes, and snippets.

@IAmJSD
Created May 13, 2023 19:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IAmJSD/0f2b3e8a4a8f8ce717edff5bfbbf13f4 to your computer and use it in GitHub Desktop.
Save IAmJSD/0f2b3e8a4a8f8ce717edff5bfbbf13f4 to your computer and use it in GitHub Desktop.
Simple test server for testing HTTP requestors.
package main
import (
"encoding/json"
"os"
"strings"
"github.com/fasthttp/router"
"github.com/valyala/fasthttp"
)
type response struct {
Status int `json:"status"`
Headers map[string]string `json:"headers"`
Body string `json:"body"`
}
func log(ctx *fasthttp.RequestCtx) {
// Get the request method.
method := string(ctx.Method())
// Get the request path.
path := string(ctx.Path())
// Get the request headers.
headers := make(map[string]string)
ctx.Request.Header.VisitAll(func(k, v []byte) {
headers[string(k)] = string(v)
})
// Get the response headers.
respHeaders := make(map[string]string)
ctx.Response.Header.VisitAll(func(k, v []byte) {
respHeaders[string(k)] = string(v)
})
// Get the request body.
body := string(ctx.PostBody())
// Print the request.
b, err := json.MarshalIndent(map[string]interface{}{
"method": method,
"path": path,
"headers": headers,
"body": body,
"server_response": map[string]interface{}{
"status": ctx.Response.StatusCode(),
"headers": respHeaders,
"body": string(ctx.Response.Body()),
},
}, "", " ")
b = append(b, '\n')
if err != nil {
panic(err)
}
_, _ = os.Stdout.Write(b)
}
func serve(ctx *fasthttp.RequestCtx) {
// Defer doing logging.
defer log(ctx)
// Get the responses JSON.
b, err := os.ReadFile("responses.json")
if err != nil {
// Just return a 204.
ctx.SetStatusCode(fasthttp.StatusNoContent)
return
}
// Parse the routing tree.
var j map[string]response
err = json.Unmarshal(b, &j)
if err != nil {
// Since this is a test server, we should just panic.
panic(err)
}
// Remap them to the router.
router := router.New()
for methodAndPath, resp := range j {
s := strings.SplitN(methodAndPath, ":", 2)
method := s[0]
path := s[1]
resp := resp // Intentional to stop loop behaviour.
router.Handle(method, path, func(ctx *fasthttp.RequestCtx) {
ctx.SetStatusCode(resp.Status)
if resp.Headers != nil {
for k, v := range resp.Headers {
ctx.Response.Header.Set(k, v)
}
}
ctx.WriteString(resp.Body)
})
}
// Serve the request.
router.Handler(ctx)
}
func main() {
if err := fasthttp.ListenAndServe(":8080", serve); err != nil {
panic(err)
}
}
@IAmJSD
Copy link
Author

IAmJSD commented May 13, 2023

By default, will return a 204 for all requests. When a responses.json is present, will 404 for non existent routes and allow some more granular control:

{
    "GET:/": {
        "status": 200,
        "body": "Hello World!",
        "headers": {
            "Content-Type": "text/plain"
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment