{"id":37867760,"url":"https://github.com/tsingson/fasthttp-guide","last_synced_at":"2026-01-16T16:38:29.083Z","repository":{"id":43053321,"uuid":"200124471","full_name":"tsingson/fasthttp-guide","owner":"tsingson","description":"step by step to build web application via fasthttp","archived":false,"fork":false,"pushed_at":"2024-04-04T12:07:57.000Z","size":786,"stargazers_count":62,"open_issues_count":2,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-21T07:59:55.167Z","etag":null,"topics":["fasthttp","flatbuffers","middleware","web-client","web-server","websocket","zap"],"latest_commit_sha":null,"homepage":"http://tsingson.github.io","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tsingson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-08-01T22:01:30.000Z","updated_at":"2025-10-16T07:21:09.000Z","dependencies_parsed_at":"2024-06-19T01:45:24.043Z","dependency_job_id":null,"html_url":"https://github.com/tsingson/fasthttp-guide","commit_stats":null,"previous_names":["tsingson/fasthttp-example"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tsingson/fasthttp-guide","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsingson%2Ffasthttp-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsingson%2Ffasthttp-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsingson%2Ffasthttp-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsingson%2Ffasthttp-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tsingson","download_url":"https://codeload.github.com/tsingson/fasthttp-guide/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsingson%2Ffasthttp-guide/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28480019,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fasthttp","flatbuffers","middleware","web-client","web-server","websocket","zap"],"created_at":"2026-01-16T16:38:29.006Z","updated_at":"2026-01-16T16:38:29.071Z","avatar_url":"https://github.com/tsingson.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fasthttp-guide ( Build Web Application via FastHTTP )\n\nstep by step to build web application via [fasthttp](https://github.com/valyala/fasthttp) -- Fast HTTP implementation for Go\n\n\n## 0. reference \n\n1. [GopherCon 2019 - How I write HTTP web services after eight years](https://about.sourcegraph.com/go/gophercon-2019-how-i-write-http-web-services-after-eight-years)\n\n1. [chinese guide ----\u003e go语言Fasthttp实践系列(1) helloWorldGetHandler World](https://tsingson.github.io/tech/fasthttp01/)\n\n## 0. note\n\nI had built some business project with golang about 8 years. And use fasthttp in different projects over 5 years. fasthttp help to build high performance API server / web server / upload serv, etc. I had shared some good practice and experience of fasthttp to friends in tech meet up. It’s excited for me to share something, and friends enjoy on. So, I write this booklet to help some developer that work in a web application.\n\nThere are some different between ‘standard’ go net/http and fasthttp. I will clarify the different , show out the How/when/why to use fasthttp. show ideas, basic usage and experience of fasthttp.\n\n\n## 1. fasthttp server side\n\n### 1.1 define fasthttp server\n```\n\ntype webServer struct {\n\tConfig WebConfig\n\taddr   string\n\tLog    *zap.Logger\n\tln     net.Listener\n\trouter *router.Router\n\tdebug  bool\n}\n\n\nfunc (ws *webServer) Run() (err error) {\n\tws.muxRouter()\n\t// reuse port\n\tws.ln, err = listen(ws.addr, ws.Log)\n\tif err != nil {\n\t\treturn err\n\t}\n\tvar lg = zaplogger.InitZapLogger(ws.Log)\n\ts := \u0026fasthttp.Server{\n\t\tHandler:            ws.router.Handler,\n\t\tName:               ws.Config.Name,\n\t\tReadBufferSize:     ws.Config.ReadBufferSize,\n\t\tMaxConnsPerIP:      ws.Config.MaxConnsPerIP,\n\t\tMaxRequestsPerConn: ws.Config.MaxRequestsPerConn,\n\t\tMaxRequestBodySize: ws.Config.MaxRequestBodySize, //  100 \u003c\u003c 20, // 100MB // 1024 * 4, // MaxRequestBodySize:\n\t\tConcurrency:        ws.Config.Concurrency,\n\t\tLogger:             lg,\n\t}\n\n \n\treturn s.Serve(ws.ln)\n \n}\n\n```\n\n### 1.2 router\nyes ,  [fasthttp router](https://github.com/fasthttp/router)\n\nwhat is **ws.Recovery**?\n\n**YES, it's middleware**\n\n```\nfunc (ws *webServer) muxRouter() {\n\tws.router.GET(\"/\", ws.Recovery(ws.helloWorldGetHandler()))\n\tws.router.GET(\"/get\", ws.Recovery(ws.simpleGetHandler()))\n\tws.router.POST(\"/post\", ws.Recovery(ws.simplePostHandler()))\n}\n\n```\n\n**middleware**, cool.....\n```\n\nfunc (ws *webServer)   Recovery(next func(ctx *fasthttp.RequestCtx)) func(ctx *fasthttp.RequestCtx) {\n\tfn := func(ctx *fasthttp.RequestCtx) {\n\t\tdefer func() {\n\t\t\tif rvr := recover(); rvr != nil {\n\t\t\t\tctx.Error(\"recover\", 500)\n\t\t\t}\n\t\t}()\n\t\t// your middleware logic here\n\n\n\t\t// do next\n\t\tnext(ctx)\n\t}\n\treturn fn\n}\n\n```\n\n### 1.3 handler\n\n\n\na POST handler via fasthttp\n```\nfunc (ws *webServer) simplePostHandler() func(ctx *fasthttp.RequestCtx) {\n\treturn func(ctx *fasthttp.RequestCtx) {\n\t\tvar tid = strconv.FormatInt(int64(ctx.ID()), 10)\n\t\tl := ws.Log.Named(tid)\n\t\tl.Debug(\"simplePostHandler\")\n\n\t\tif ws.debug {\n\t\t\tl.Debug(tid, zap.String(\"request\", ctx.String()))\n\t\t\tctx.Request.Header.VisitAll(func(key, value []byte) {\n\t\t\t\tl.Debug(tid, zap.String(\"key\", gotils.B2S(key)), zap.String(\"value\", gotils.B2S(value)))\n\t\t\t})\n\t\t\tl.Debug(tid, zap.String(\"http payload\", gotils.B2S(ctx.Request.Body())))\n\t\t}\n\n\t\tctx.SetContentType(ContentRest)\n\t\tctx.SetStatusCode(200)\n\t\tctx.SetBody([]byte(`{\"id\":2101127497763529765,\"plan_start_date\":\"2019-07-29\",\"plan_end_date\":\"2019-02-12\",\"actual_start_date\":\"2019-07-29\",\"actual_end_date\":\"2019-07-29\",\"is_done\":false,\"last_updated\":\"2019-08-01T14:12:17.983236\",\"is_deleted\":false,\"user_id\":2098735545843717147,\"title\":\"00002\"}`))\n\t\treturn\n\t}\n}\n\n```\n\n### 1.4  running fasthttp web-server\n```\n\tvar s = webserver.DefaultServer()\n \n \n \n\ts.Run()\n\t\n```\n\n\n## 2. fasthttp client side\n\n### 2.1 define web client struct via fasthttp client \n\n```\ntype WebClient struct {\n\tBaseURI        string\n\tTransactionID  string\n\tAuthentication bool\n\tJwtToken       string\n\tUserAgent      string\n\tContentType    string\n\tAccept         string\n\tTimeOut        time.Duration\n\tlog            *zap.Logger\n\tDebug          bool\n}\n\n// Default  setup a default fasthttp client\nfunc Default() *WebClient {\n\tvar log = zaplogger.ConsoleDebug()\n\treturn \u0026WebClient{\n\t\tAuthentication: false,\n\t\tTransactionID:  time.Now().String(),\n\t\tUserAgent:      \"testAgent\",\n\t\tContentType:    \"application/json; charset=utf-8\",\n\t\tAccept:         AcceptJson,\n\t\tDebug:          true,\n\t\tlog:            log,\n\t}\n}\n```\n\n### 2.2 define a GET method\n```\n\n// FastGet do GET request via fasthttp\nfunc (w *WebClient) FastGet(requestURI string) (*fasthttp.Response, error) {\n\tvar log = w.log.Named(\"FastGet\")\n\tt1 := time.Now()\n\tw.TransactionID = t1.String()\n\treq := fasthttp.AcquireRequest()\n\tresp := fasthttp.AcquireResponse()\n\tdefer func() {\n\t\tfasthttp.ReleaseResponse(resp)\n\t\tfasthttp.ReleaseRequest(req)\n\t}()\n\treq.SetRequestURI(requestURI)\n\treq.Header.SetContentType(w.ContentType)\n\treq.Header.Add(\"User-Agent\", w.UserAgent)\n\treq.Header.Add(\"TransactionID\", w.TransactionID)\n\treq.Header.Add(\"Accept\", w.Accept)\n\tif w.Authentication \u0026\u0026 len(w.JwtToken) \u003e 0 {\n\t\treq.Header.Set(\"Authorization\", \"Bearer \"+w.JwtToken)\n\t}\n\n\t// define web client request Method\n\treq.Header.SetMethod(\"GET\")\n\t\n\t\n\tif w.Debug {\n\t\treq.Header.VisitAll(func(key, value []byte) {\n\t\t\tlog.Debug(w.TransactionID, zap.String(\"key\", gotils.B2S(key)), zap.String(\"value\", gotils.B2S(value)))\n\t\t})\n\t\tlog.Debug(w.TransactionID)\n\t}\n\n\tvar timeOut = 3 * time.Second\n\tif w.TimeOut != 0 {\n\t\ttimeOut = w.TimeOut\n\t}\n\t// DO GET request\n\tvar err = fasthttp.DoTimeout(req, resp, timeOut)\n\t\n\tif err != nil {\n\t\tlog.Error(\"post request error\", zap.Error(err))\n\t\treturn nil, err\n\t}\n\tif w.Debug {\n\t\telapsed := time.Since(t1)\n\t\tlog.Debug(w.TransactionID, zap.Duration(\"elapsed\", elapsed))\n\t\tlog.Debug(w.TransactionID, zap.Int(\"http status code\", resp.StatusCode()))\n\t\tresp.Header.VisitAll(func(key, value []byte) {\n\t\t\tlog.Debug(w.TransactionID, zap.String(\"key\", gotils.B2S(key)), zap.String(\"value\", gotils.B2S(value)))\n\t\t})\n\t\tlog.Debug(w.TransactionID, zap.String(\"http payload\", gotils.B2S(resp.Body())))\n\t}\n\n\t// add your logic code here , to handle response \n\t\n\tvar out = fasthttp.AcquireResponse()\n\tresp.CopyTo(out)\n\n\treturn out, nil\n}\n```\n\n\n### 1.3 call  a GET request  method\n```\n\tvar w = webclient.Default()\n\tw.Debug = true\n\n\tw.Authentication = true\n\tw.JwtToken = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTY2NzIwMDAsInJvbGUiOiJ0ZXJtaW5hbF9hcGsiLCJzdGF0dXMiOiJhY3RpdmUiLCJ1c2VyX2lkIjoiNTBjNjg5MTAtNjEyYi00NjMzLTk2YjktNTA3NzhjNDViNTAwIn0.l1JHnOL85s3ajto0MKs-D6paW1YxpaMuxA0nzI0Xlfk\"\n\tvar url = \"http://localhost:3001/get\"\n\tvar resp, err = w.FastGet(url)\n\n\tif err != nil {\n\n\t}\n\tif resp != nil {\n\t\tlitter.Dump(gotils.B2S(resp.Body()))\n\t}\n\t// clean-up\n\tfasthttp.ReleaseResponse(resp)\n```\n\n\n##  3. clone,  build and run\n\n\n\n### 3.1 **clone**\n```\nexport GOBIN=~/bin\n\ncd ~\nmkdir go-project\ncd go-project\n\ngit clone https://github.com/tsingson/fasthttp-guide\ncd ./fasthttp-guide\n\ngo mod tidy\n```\n\n### 3.2 **build**\n```\n\ngo install  -gcflags=-trimpath=OPATH -asmflags=-trimpath=OPATH -ldflags \"-w -s\" ./cmd/... \n```\n\n### 3.3 **run** in two terminal\n\nterminal 1\n```\ncd $GOBIN\n./test-server\n```\nterminal 2\n```\ncd $GOBIN\n./test-client\n```\n\n**output**\n\nclient side\n```\n2019-08-02T06:23:38.671+0800\tDEBUG\tFastGet\twebclient/client.go:126\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\t{\"key\": \"Content-Type\", \"value\": \"application/json; charset=utf-8\"}\n2019-08-02T06:23:38.671+0800\tDEBUG\tFastGet\twebclient/client.go:126\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\t{\"key\": \"User-Agent\", \"value\": \"testAgent\"}\n2019-08-02T06:23:38.672+0800\tDEBUG\tFastGet\twebclient/client.go:126\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\t{\"key\": \"Transactionid\", \"value\": \"2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\"}\n2019-08-02T06:23:38.672+0800\tDEBUG\tFastGet\twebclient/client.go:126\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\t{\"key\": \"Accept\", \"value\": \"application/json\"}\n2019-08-02T06:23:38.672+0800\tDEBUG\tFastGet\twebclient/client.go:126\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\t{\"key\": \"Authorization\", \"value\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTY2NzIwMDAsInJvbGUiOiJ0ZXJtaW5hbF9hcGsiLCJzdGF0dXMiOiJhY3RpdmUiLCJ1c2VyX2lkIjoiNTBjNjg5MTAtNjEyYi00NjMzLTk2YjktNTA3NzhjNDViNTAwIn0.l1JHnOL85s3ajto0MKs-D6paW1YxpaMuxA0nzI0Xlfk\"}\n2019-08-02T06:23:38.672+0800\tDEBUG\tFastGet\twebclient/client.go:128\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\n2019-08-02T06:23:38.676+0800\tDEBUG\tFastGet\twebclient/client.go:142\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\t{\"elapsed\": \"4.627531ms\"}\n2019-08-02T06:23:38.676+0800\tDEBUG\tFastGet\twebclient/client.go:143\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\t{\"http status code\": 200}\n2019-08-02T06:23:38.676+0800\tDEBUG\tFastGet\twebclient/client.go:145\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\t{\"key\": \"Content-Length\", \"value\": \"275\"}\n2019-08-02T06:23:38.676+0800\tDEBUG\tFastGet\twebclient/client.go:145\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\t{\"key\": \"Content-Type\", \"value\": \"application/vnd.pgrst.object+json; charset=utf-8\"}\n2019-08-02T06:23:38.676+0800\tDEBUG\tFastGet\twebclient/client.go:145\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\t{\"key\": \"Server\", \"value\": \"EPG-xcache-service\"}\n2019-08-02T06:23:38.676+0800\tDEBUG\tFastGet\twebclient/client.go:145\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\t{\"key\": \"Date\", \"value\": \"Thu, 01 Aug 2019 22:23:37 GMT\"}\n2019-08-02T06:23:38.676+0800\tDEBUG\tFastGet\twebclient/client.go:147\t2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\t{\"http payload\": \"{\\\"id\\\":2101127497763529765,\\\"plan_start_date\\\":\\\"2019-07-29\\\",\\\"plan_end_date\\\":\\\"2019-02-12\\\",\\\"actual_start_date\\\":\\\"2019-07-29\\\",\\\"actual_end_date\\\":\\\"2019-07-29\\\",\\\"is_done\\\":false,\\\"last_updated\\\":\\\"2019-08-01T14:12:17.983236\\\",\\\"is_deleted\\\":false,\\\"user_id\\\":2098735545843717147,\\\"title\\\":\\\"00002\\\"}\"}\n\"{\\\"id\\\":2101127497763529765,\\\"plan_start_date\\\":\\\"2019-07-29\\\",\\\"plan_end_date\\\":\\\"2019-02-12\\\",\\\"actual_start_date\\\":\\\"2019-07-29\\\",\\\"actual_end_date\\\":\\\"2019-07-29\\\",\\\"is_done\\\":false,\\\"last_updated\\\":\\\"2019-08-01T14:12:17.983236\\\",\\\"is_deleted\\\":false,\\\"user_id\\\":2098735545843717147,\\\"title\\\":\\\"00002\\\"}\"\n2019-08-02T06:23:38.677+0800\tDEBUG\tFastPostByte\twebclient/client.go:71\t2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\t{\"key\": \"Content-Type\", \"value\": \"application/json; charset=utf-8\"}\n2019-08-02T06:23:38.677+0800\tDEBUG\tFastPostByte\twebclient/client.go:71\t2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\t{\"key\": \"User-Agent\", \"value\": \"testAgent\"}\n2019-08-02T06:23:38.677+0800\tDEBUG\tFastPostByte\twebclient/client.go:71\t2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\t{\"key\": \"Transactionid\", \"value\": \"2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\"}\n2019-08-02T06:23:38.677+0800\tDEBUG\tFastPostByte\twebclient/client.go:71\t2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\t{\"key\": \"Accept\", \"value\": \"application/vnd.pgrst.object+json\"}\n2019-08-02T06:23:38.677+0800\tDEBUG\tFastPostByte\twebclient/client.go:73\t2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\n2019-08-02T06:23:38.678+0800\tDEBUG\tFastPostByte\twebclient/client.go:87\t2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\t{\"elapsed\": \"1.19083ms\"}\n2019-08-02T06:23:38.678+0800\tDEBUG\tFastPostByte\twebclient/client.go:88\t2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\t{\"http status code\": 200}\n2019-08-02T06:23:38.678+0800\tDEBUG\tFastPostByte\twebclient/client.go:90\t2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\t{\"key\": \"Content-Length\", \"value\": \"275\"}\n2019-08-02T06:23:38.678+0800\tDEBUG\tFastPostByte\twebclient/client.go:90\t2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\t{\"key\": \"Content-Type\", \"value\": \"application/vnd.pgrst.object+json; charset=utf-8\"}\n2019-08-02T06:23:38.678+0800\tDEBUG\tFastPostByte\twebclient/client.go:90\t2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\t{\"key\": \"Server\", \"value\": \"EPG-xcache-service\"}\n2019-08-02T06:23:38.678+0800\tDEBUG\tFastPostByte\twebclient/client.go:90\t2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\t{\"key\": \"Date\", \"value\": \"Thu, 01 Aug 2019 22:23:37 GMT\"}\n2019-08-02T06:23:38.678+0800\tDEBUG\tFastPostByte\twebclient/client.go:92\t2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\t{\"http payload\": \"{\\\"id\\\":2101127497763529765,\\\"plan_start_date\\\":\\\"2019-07-29\\\",\\\"plan_end_date\\\":\\\"2019-02-12\\\",\\\"actual_start_date\\\":\\\"2019-07-29\\\",\\\"actual_end_date\\\":\\\"2019-07-29\\\",\\\"is_done\\\":false,\\\"last_updated\\\":\\\"2019-08-01T14:12:17.983236\\\",\\\"is_deleted\\\":false,\\\"user_id\\\":2098735545843717147,\\\"title\\\":\\\"00002\\\"}\"}\n\"{\\\"id\\\":2101127497763529765,\\\"plan_start_date\\\":\\\"2019-07-29\\\",\\\"plan_end_date\\\":\\\"2019-02-12\\\",\\\"actual_start_date\\\":\\\"2019-07-29\\\",\\\"actual_end_date\\\":\\\"2019-07-29\\\",\\\"is_done\\\":false,\\\"last_updated\\\":\\\"2019-08-01T14:12:17.983236\\\",\\\"is_deleted\\\":false,\\\"user_id\\\":2098735545843717147,\\\"title\\\":\\\"00002\\\"}\"\n```\n\n**server side**\n```\n----- fasthttp server starting -----\n2019-08-02T06:23:38.675+0800\tDEBUG\t4294967297\twebserver/testHandler.go:15\tsimpleGetHandler\n2019-08-02T06:23:38.675+0800\tDEBUG\t4294967297\twebserver/testHandler.go:19\t4294967297\t{\"request\": \"#0000000100000001 - 127.0.0.1:3001\u003c-\u003e127.0.0.1:64674 - GET http://localhost:3001/get\"}\n2019-08-02T06:23:38.675+0800\tDEBUG\t4294967297\twebserver/testHandler.go:22\t4294967297\t{\"key\": \"Host\", \"value\": \"localhost:3001\"}\n2019-08-02T06:23:38.675+0800\tDEBUG\t4294967297\twebserver/testHandler.go:22\t4294967297\t{\"key\": \"Content-Length\", \"value\": \"0\"}\n2019-08-02T06:23:38.675+0800\tDEBUG\t4294967297\twebserver/testHandler.go:22\t4294967297\t{\"key\": \"Content-Type\", \"value\": \"application/json; charset=utf-8\"}\n2019-08-02T06:23:38.675+0800\tDEBUG\t4294967297\twebserver/testHandler.go:22\t4294967297\t{\"key\": \"User-Agent\", \"value\": \"testAgent\"}\n2019-08-02T06:23:38.675+0800\tDEBUG\t4294967297\twebserver/testHandler.go:22\t4294967297\t{\"key\": \"Transactionid\", \"value\": \"2019-08-02 06:23:38.671678 +0800 CST m=+0.004252696\"}\n2019-08-02T06:23:38.675+0800\tDEBUG\t4294967297\twebserver/testHandler.go:22\t4294967297\t{\"key\": \"Accept\", \"value\": \"application/json\"}\n2019-08-02T06:23:38.675+0800\tDEBUG\t4294967297\twebserver/testHandler.go:22\t4294967297\t{\"key\": \"Authorization\", \"value\": \"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTY2NzIwMDAsInJvbGUiOiJ0ZXJtaW5hbF9hcGsiLCJzdGF0dXMiOiJhY3RpdmUiLCJ1c2VyX2lkIjoiNTBjNjg5MTAtNjEyYi00NjMzLTk2YjktNTA3NzhjNDViNTAwIn0.l1JHnOL85s3ajto0MKs-D6paW1YxpaMuxA0nzI0Xlfk\"}\n2019-08-02T06:23:38.676+0800\tDEBUG\t4294967297\twebserver/testHandler.go:25\t4294967297\t{\"http payload\": \"\"}\n2019-08-02T06:23:38.677+0800\tDEBUG\t4294967298\twebserver/testHandler.go:42\tsimplePostHandler\n2019-08-02T06:23:38.677+0800\tDEBUG\t4294967298\twebserver/testHandler.go:46\t4294967298\t{\"request\": \"#0000000100000002 - 127.0.0.1:3001\u003c-\u003e127.0.0.1:64674 - POST http://localhost:3001/post\"}\n2019-08-02T06:23:38.677+0800\tDEBUG\t4294967298\twebserver/testHandler.go:50\t4294967298\t{\"key\": \"Host\", \"value\": \"localhost:3001\"}\n2019-08-02T06:23:38.677+0800\tDEBUG\t4294967298\twebserver/testHandler.go:50\t4294967298\t{\"key\": \"Content-Length\", \"value\": \"183\"}\n2019-08-02T06:23:38.677+0800\tDEBUG\t4294967298\twebserver/testHandler.go:50\t4294967298\t{\"key\": \"Content-Type\", \"value\": \"application/json; charset=utf-8\"}\n2019-08-02T06:23:38.677+0800\tDEBUG\t4294967298\twebserver/testHandler.go:50\t4294967298\t{\"key\": \"User-Agent\", \"value\": \"testAgent\"}\n2019-08-02T06:23:38.677+0800\tDEBUG\t4294967298\twebserver/testHandler.go:50\t4294967298\t{\"key\": \"Transactionid\", \"value\": \"2019-08-02 06:23:38.677108 +0800 CST m=+0.009682961\"}\n2019-08-02T06:23:38.677+0800\tDEBUG\t4294967298\twebserver/testHandler.go:50\t4294967298\t{\"key\": \"Accept\", \"value\": \"application/vnd.pgrst.object+json\"}\n2019-08-02T06:23:38.677+0800\tDEBUG\t4294967298\twebserver/testHandler.go:53\t4294967298\t{\"http payload\": \"{\\\"actual_start_date\\\":\\\"2019-07-29\\\",\\\"actual_end_date\\\":\\\"2019-07-29\\\",\\\"plan_start_date\\\":\\\"2019-07-29\\\",\\\"plan_end_date\\\":\\\"2019-02-12\\\",\\\"title\\\":\\\"养殖计划00002\\\",\\\"user_id\\\":2098735545843717147}\"}\n```\n\n## 4.  How to Unit Testing \n\n### 4.1  simple handler testing ( fasthttp hadler as function)\n\ndefine handler as a function\n```\nfunc helloWorldGetHandler() func(ctx *fasthttp.RequestCtx) {\n\treturn func(ctx *fasthttp.RequestCtx) {\n\t\ttid := strconv.FormatInt(int64(ctx.ID()), 10)\n\n\t\tctx.Request.Header.Add(\"tid\", tid)\n\t\tctx.SetContentType(ContentText)\n\t\tctx.SetStatusCode(200)\n\t\tctx.SetBody([]byte(`hello world`))\n\t\treturn\n\t}\n}\n\n```\n\n\nthe unit testing code here \n```\nfunc TestHello(t *testing.T) {\n\t\n\t// setup fasthttp server \n    addr := \":3000\"\n    s := \u0026fasthttp.Server{\n        Handler: helloWorldGetHandler(),\n    }\n    // setup listener \n    ln, _ := reuseport.Listen(\"tcp4\", addr)\n\n    // remember to close listener \n    defer func() {\n        _ = ln.Close()\n    }()\n    \n    // now running fasthttp server in a goroutine \n\n    go func() {\n        _ = s.Serve(ln)\n    }()\n\n    // -------------------------------------------------------\n    // now, the real http client what you want\n\t// -------------------------------------------------------\n\n    c := \u0026fasthttp.HostClient{\n        Addr: \"localhost:3000\",\n    }\n\n    // http client Fetch the testing fasthttp server  via local proxy.\n    statusCode, body, err := c.Get(nil, \"http://google.com/hello\")\n    assert.NoError(t, err)\n    assert.Equal(t, statusCode, 200)\n    assert.Equal(t, body, []byte(`hello world`))\n}\n\n```\n\n### 4.2  simple handler testing ( fasthttp hadler as method )\n\njuse like **4.1** but in method mode\n```\nfunc (ws *webServer) helloWorldGetHandler() func(ctx *fasthttp.RequestCtx) {\n\treturn func(ctx *fasthttp.RequestCtx) {\n\t\ttid := strconv.FormatInt(int64(ctx.ID()), 10)\n\t\tlog := ws.Log.Named(tid)\n\t\tlog.Debug(\"helloWorldGetHandler\")\n\n\t\tif ws.debug {\n\t\t\tctx.Request.Header.VisitAll(func(key, value []byte) {\n\t\t\t\t// log.Info(\"requestHeader\", zap.String(\"key\", gotils.B2S(key)), zap.String(\"value\", gotils.B2S(value)))\n\t\t\t\tlog.Debug(tid, zap.String(\"key\", goutils.B2S(key)), zap.String(\"value\", goutils.B2S(value)))\n\t\t\t})\n\n\t\t\tlog.Debug(tid, zap.String(\"http payload\", goutils.B2S(ctx.Request.Body())))\n\n\t\t}\n\n\t\tctx.SetContentType(ContentText)\n\t\tctx.SetStatusCode(200)\n\t\tctx.SetBody([]byte(`hello world`))\n\t\treturn\n\t}\n}\n```\n\nand \n\nunit testing \n\n```\n\nfunc TestWebServer_hello(t *testing.T) {\n\n    // setup logger that output to console\n    log := logger.Console()\n    ws := \u0026webServer{\n        Addr:  \":3000\",\n        Log:   log,\n        debug: true,\n    }\n    // setup fasthttp logger\n\n    flog := logger.InitZapLogger(ws.Log)\n\n    // setup fasthttp server\n\n    s := \u0026fasthttp.Server{\n        Handler: ws.helloWorldGetHandler(),\n        Logger:  flog,\n    }\n\n    // setup listener\n    ln, _ := reuseport.Listen(\"tcp4\", ws.Addr)\n\n    // remember to close listener\n    defer func() {\n        _ = ln.Close()\n    }()\n\n    // now running fasthttp server in a goroutine\n\n    go func() {\n        _ = s.Serve(ln)\n    }()\n\n    // -------------------------------------------------------\n    // now, the real http client what you want\n    // -------------------------------------------------------\n\n    c := \u0026fasthttp.HostClient{\n        Addr: \"localhost:3000\",\n    }\n\n    // http client Fetch the testing fasthttp server  via local proxy.\n    statusCode, body, err := c.Get(nil, \"http://google.com/hello\")\n    assert.NoError(t, err)\n    assert.Equal(t, statusCode, 200)\n    assert.Equal(t, body, []byte(`hello world`))\n}\n\n\n```\n\n\n\n### 4.3 run test\n\n```\n/go/src/github.com/tsingson/fasthttp-example/webserver   go test -v .\n=== RUN   TestWebServer_hello\n2019-10-26T19:25:15.197+0800\tDEBUG\t4294967297\thelloWorldGetHandler\n2019-10-26T19:25:15.197+0800\tDEBUG\t4294967297\t4294967297\t{\"key\": \"Host\", \"value\": \"google.com\"}\n2019-10-26T19:25:15.197+0800\tDEBUG\t4294967297\t4294967297\t{\"key\": \"Content-Length\", \"value\": \"0\"}\n2019-10-26T19:25:15.197+0800\tDEBUG\t4294967297\t4294967297\t{\"key\": \"User-Agent\", \"value\": \"fasthttp\"}\n2019-10-26T19:25:15.197+0800\tDEBUG\t4294967297\t4294967297\t{\"http payload\": \"\"}\n--- PASS: TestWebServer_hello (0.00s)\n=== RUN   TestHello\n--- PASS: TestHello (0.00s)\nPASS\nok  \tgithub.com/tsingson/fasthttp-example/webserver\t0.015s\n\n```\n\n\n\ncool, just try it by yourself.\n\n\n\n\n\n\n## 5. license\n\nMIT\n\nby tsingson 2019\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftsingson%2Ffasthttp-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftsingson%2Ffasthttp-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftsingson%2Ffasthttp-guide/lists"}