Building a Custom Go HTTP Client Wrapper for API Testing

This article walks through creating a reusable Go HTTP client wrapper, demonstrates its use in a test script, shows console output, and integrates a mock server with Moco to enable quick API testing while applying a learning‑by‑doing approach.

FunTester
FunTester
FunTester
Building a Custom Go HTTP Client Wrapper for API Testing

The author, learning Go, applies the "Learning By Doing" principle and decides to practice by implementing HTTP client utilities for testing, similar to earlier Java experience.

HTTP Client Wrapper

Using Go's net/http package, the author wraps basic request creation functions (GET, POST form, POST JSON) and utilities for converting a map of parameters to query strings, handling responses, and configuring a reusable http.Client with timeout and transport settings.

package task

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
    "strings"
    "time"
)

var Client http.Client = clients()

// Res simulates a response structure
// @Description:
type Res struct {
    Have string `json:"Have"`
}

// Get creates a GET request
// @Description:
// @param uri
// @param args
// @return *http.Request
func Get(uri string, args map[string]interface{}) *http.Request {
    uri = uri + "?" + ToValues(args)
    request, _ := http.NewRequest("get", uri, nil)
    return request
}

// PostForm creates a POST request with form data
// @Description:
// @param path
// @param args
// @return *http.Request
func PostForm(path string, args map[string]interface{}) *http.Request {
    request, _ := http.NewRequest("post", path, strings.NewReader(ToValues(args)))
    return request
}

// PostJson creates a POST request with JSON body
// @Description:
// @param path
// @param args
// @return *http.Request
func PostJson(path string, args map[string]interface{}) *http.Request {
    marshal, _ := json.Marshal(args)
    request, _ := http.NewRequest("post", path, bytes.NewReader(marshal))
    return request
}

// ToValues converts a map to URL‑encoded query string, used for GET and POST form
// @Description:
// @param args
// @return string
func ToValues(args map[string]interface{}) string {
    if args != nil && len(args) > 0 {
        params := url.Values{}
        for k, v := range args {
            params.Set(k, fmt.Sprintf("%v", v))
        }
        return params.Encode()
    }
    return ""
}

// Response reads the response body and returns it as []byte
// @Description:
// @param request
// @return []byte
func Response(request *http.Request) []byte {
    res, err := Client.Do(request)
    if err != nil {
        return nil
    }
    body, _ := ioutil.ReadAll(res.Body) // read response body
    defer res.Body.Close()
    return body
}

// clients initializes the HTTP client with timeout and transport settings
// @Description:
// @return http.Client
func clients() http.Client {
    return http.Client{
        Timeout: time.Duration(5) * time.Second,
        Transport: &http.Transport{
            MaxIdleConnsPerHost:   5,
            MaxConnsPerHost:       100,
            IdleConnTimeout:       90 * time.Second,
            TLSHandshakeTimeout:   10 * time.Second,
            ExpectContinueTimeout: 1 * time.Second,
        },
    }
}

// ParseRes unmarshals JSON response into a Res struct
// @Description:
func (r *Res) ParseRes(res []byte) {
    json.Unmarshal(res, r)
}

// ParseRes unmarshals JSON response into any provided object
// @Description:
func ParseRes(res []byte, r interface{}) {
    json.Unmarshal(res, r)
}

Test Script

A main program demonstrates how to use the wrapper: creating log directories, building request arguments, adding a cookie, sending GET, POST form, and POST JSON requests, and printing the raw responses.

package main

import (
    "fmt"
    "funtester/src/task"
    "io"
    "log"
    "net/http"
    "os"
    "time"
)

const (
    a = iota
    b
    c
    d
    e
)

func init() {
    os.Mkdir("./log/", 0777)
    os.Mkdir("./long/", 0777)
    file := "./log/" + string(time.Now().Format("20060102")) + ".log"
    openFile, _ := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    writer := io.MultiWriter(os.Stdout, openFile)
    log.SetOutput(writer)
    log.SetFlags(log.LstdFlags | log.Lshortfile | log.Ldate)
}

func main() {
    url := "http://localhost:12345/test"
    args := map[string]interface{}{
        "name": "FunTester",
        "fun":  "fdsafj",
    }
    cookie := &http.Cookie{
        Name:  "token",
        Value: "fsjej09u0934jtej",
    }
    get := task.Get(url, args)
    get.Header.Add("user_agent", "FunTester")
    get.AddCookie(cookie)
    response := task.Response(get)
    fmt.Println(string(response))

    form := task.PostForm(url, args)
    bytes := task.Response(form)
    fmt.Println(string(bytes))

    json := task.PostJson(url, args)
    res := task.Response(json)
    fmt.Println(string(res))
}

Console Output

GOROOT=/usr/local/go #gosetup
GOPATH=/Users/oker/go #gosetup
/usr/local/go/bin/go build -o /private/var/folders/7b/0djfgf7j7p9ch_hgm9wx9n6w0000gn/T/GoLand/___go_build_funtester_src_m funtester/src/m #gosetup
/private/var/folders/7b/0djfgf7j7p9ch_hgm9wx9n6w0000gn/T/GoLand/___go_build_funtester_src_m
get请求
post请求form表单
post请求json表单

Process finished with the exit code 0

Mock Test Service

The author uses the moco_FunTester framework (a Java‑based mock server) to define endpoints for GET, POST form, POST JSON, and QPS testing, returning simple text responses.

package com.mocofun.moco.main

import com.funtester.utils.ArgsUtil
import com.mocofun.moco.MocoServer

class Share extends MocoServer {
    static void main(String[] args) {
        def util = new ArgsUtil(args)
        // def server = getServerNoLog(util.getIntOrdefault(0,12345))
        def server = getServer(util.getIntOrdefault(0, 12345))
        server.get(urlStartsWith("/test")).response("get请求")
        server.post(both(urlStartsWith("/test"), existForm("fun"))).response("post请求form表单")
        server.post(both(urlStartsWith("/test"), existParams("fun"))).response("post请求json表单")
        server.get(urlStartsWith("/qps")).response(qps(textRes("恭喜到达QPS!"), 1))
        // server.response(delay(jsonRes(getJson("Have=Fun ~ Tester !")), 1000)
        server.response("Have Fun ~ Tester !")
        def run = run(server)
        waitForKey("fan")
        run.stop()
    }
}

Result

The combined Go wrapper and mock server enable quick API testing without external services, illustrating a practical "learning by doing" workflow for backend developers.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendtestingGolangGoHTTPAPIclient
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.