aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorGravatar Sergey Ponomarev <stokito@gmail.com> 2022-02-09 12:09:36 +0200
committerGravatar GitHub <noreply@github.com> 2022-02-09 11:09:36 +0100
commit632e222c2a41ada95f26ee395e5e4dbb8553aff9 (patch)
tree7c1aa0a58aa5620cbb96b7612d51849465abaf27 /examples
parenturi_test.go use example.com for clearness (#1212) (diff)
downloadfasthttp-632e222c2a41ada95f26ee395e5e4dbb8553aff9.tar.gz
fasthttp-632e222c2a41ada95f26ee395e5e4dbb8553aff9.tar.bz2
fasthttp-632e222c2a41ada95f26ee395e5e4dbb8553aff9.zip
Client examples (#1208)
* examples/host_client * examples/client * examples/client/client.go refine imports Co-authored-by: Erik Dubbelboer <erik@dubbelboer.com> * examples/host_client/hostclient.go refine imports Co-authored-by: Erik Dubbelboer <erik@dubbelboer.com> Co-authored-by: Erik Dubbelboer <erik@dubbelboer.com>
Diffstat (limited to 'examples')
-rw-r--r--examples/client/.gitignore1
-rw-r--r--examples/client/Makefile6
-rw-r--r--examples/client/README.md21
-rw-r--r--examples/client/client.go125
-rw-r--r--examples/host_client/.gitignore1
-rw-r--r--examples/host_client/Makefile6
-rw-r--r--examples/host_client/README.md13
-rw-r--r--examples/host_client/hostclient.go35
8 files changed, 208 insertions, 0 deletions
diff --git a/examples/client/.gitignore b/examples/client/.gitignore
new file mode 100644
index 0000000..b051c6c
--- /dev/null
+++ b/examples/client/.gitignore
@@ -0,0 +1 @@
+client
diff --git a/examples/client/Makefile b/examples/client/Makefile
new file mode 100644
index 0000000..d2844fb
--- /dev/null
+++ b/examples/client/Makefile
@@ -0,0 +1,6 @@
+client: clean
+ go get -u github.com/valyala/fasthttp
+ go build
+
+clean:
+ rm -f client
diff --git a/examples/client/README.md b/examples/client/README.md
new file mode 100644
index 0000000..cef2d35
--- /dev/null
+++ b/examples/client/README.md
@@ -0,0 +1,21 @@
+# Client Example
+
+The Client is useful when working with multiple hostnames.
+
+See the simplest `sendGetRequest()` for GET and more advanced `sendPostRequest()` for a POST request.
+
+The `sendPostRequest()` also shows:
+* Per-request timeout with `DoTimeout()`
+* Send a body as bytes slice with `SetBodyRaw()`. This is useful if you generated a request body. Otherwise, prefer `SetBody()` which copies it.
+* Parse JSON from response
+* Gracefully show error messages i.e. timeouts as warnings and other errors as a failures with detailed error messages.
+
+## How to build and run
+Start a web server on localhost:8080 then execute:
+
+ make
+ ./client
+
+## Client vs HostClient
+Internally the Client creates a dedicated HostClient for each domain/IP address and cleans unused after period of time.
+So if you have a single heavily loaded API endpoint it's better to use HostClient. See an example in the [examples/host_client](../host_client/)
diff --git a/examples/client/client.go b/examples/client/client.go
new file mode 100644
index 0000000..0bb66f0
--- /dev/null
+++ b/examples/client/client.go
@@ -0,0 +1,125 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "os"
+ "reflect"
+ "time"
+
+ "github.com/valyala/fasthttp"
+)
+
+var headerContentTypeJson = []byte("application/json")
+
+var client *fasthttp.Client
+
+type Entity struct {
+ Id int
+ Name string
+}
+
+func main() {
+ // You may read the timeouts from some config
+ readTimeout, _ := time.ParseDuration("500ms")
+ writeTimeout, _ := time.ParseDuration("500ms")
+ maxIdleConnDuration, _ := time.ParseDuration("1h")
+ client = &fasthttp.Client{
+ ReadTimeout: readTimeout,
+ WriteTimeout: writeTimeout,
+ MaxIdleConnDuration: maxIdleConnDuration,
+ NoDefaultUserAgentHeader: true, // Don't send: User-Agent: fasthttp
+ DisableHeaderNamesNormalizing: true, // If you set the case on your headers correctly you can enable this
+ DisablePathNormalizing: true,
+ // increase DNS cache time to an hour instead of default minute
+ Dial: (&fasthttp.TCPDialer{
+ Concurrency: 4096,
+ DNSCacheDuration: time.Hour,
+ }).Dial,
+ }
+ sendGetRequest()
+ sendPostRequest()
+}
+
+func sendGetRequest() {
+ req := fasthttp.AcquireRequest()
+ req.SetRequestURI("http://localhost:8080/")
+ req.Header.SetMethod(fasthttp.MethodGet)
+ resp := fasthttp.AcquireResponse()
+ err := client.Do(req, resp)
+ fasthttp.ReleaseRequest(req)
+ if err == nil {
+ fmt.Printf("DEBUG Response: %s\n", resp.Body())
+ } else {
+ fmt.Fprintf(os.Stderr, "ERR Connection error: %s\n", err)
+ }
+ fasthttp.ReleaseResponse(resp)
+}
+
+func sendPostRequest() {
+ // per-request timeout
+ reqTimeout := time.Duration(100) * time.Millisecond
+
+ reqEntity := &Entity{
+ Name: "New entity",
+ }
+ reqEntityBytes, _ := json.Marshal(reqEntity)
+
+ req := fasthttp.AcquireRequest()
+ req.SetRequestURI("http://localhost:8080/")
+ req.Header.SetMethod(fasthttp.MethodPost)
+ req.Header.SetContentTypeBytes(headerContentTypeJson)
+ req.SetBodyRaw(reqEntityBytes)
+ resp := fasthttp.AcquireResponse()
+ err := client.DoTimeout(req, resp, reqTimeout)
+ fasthttp.ReleaseRequest(req)
+ if err == nil {
+ statusCode := resp.StatusCode()
+ respBody := resp.Body()
+ fmt.Printf("DEBUG Response: %s\n", respBody)
+ if statusCode == http.StatusOK {
+ respEntity := &Entity{}
+ err = json.Unmarshal(respBody, respEntity)
+ if err == io.EOF || err == nil {
+ fmt.Printf("DEBUG Parsed Response: %v\n", respEntity)
+ } else {
+ fmt.Fprintf(os.Stderr, "ERR failed to parse reponse: %s\n", err)
+ }
+ } else {
+ fmt.Fprintf(os.Stderr, "ERR invalid HTTP response code: %d\n", statusCode)
+ }
+ } else {
+ errName, known := httpConnError(err)
+ if known {
+ fmt.Fprintf(os.Stderr, "WARN conn error: %s\n", errName)
+ } else {
+ fmt.Fprintf(os.Stderr, "ERR conn failure: %s %s\n", errName, err)
+ }
+ }
+ fasthttp.ReleaseResponse(resp)
+}
+
+func httpConnError(err error) (string, bool) {
+ errName := ""
+ known := false
+ if err == fasthttp.ErrTimeout {
+ errName = "timeout"
+ known = true
+ } else if err == fasthttp.ErrNoFreeConns {
+ errName = "conn_limit"
+ known = true
+ } else if err == fasthttp.ErrConnectionClosed {
+ errName = "conn_close"
+ known = true
+ } else {
+ errName = reflect.TypeOf(err).String()
+ if errName == "*net.OpError" {
+ // Write and Read errors are not so often and in fact they just mean timeout problems
+ errName = "timeout"
+ known = true
+ }
+ }
+ return errName, known
+}
diff --git a/examples/host_client/.gitignore b/examples/host_client/.gitignore
new file mode 100644
index 0000000..097652f
--- /dev/null
+++ b/examples/host_client/.gitignore
@@ -0,0 +1 @@
+hostclient
diff --git a/examples/host_client/Makefile b/examples/host_client/Makefile
new file mode 100644
index 0000000..161ab44
--- /dev/null
+++ b/examples/host_client/Makefile
@@ -0,0 +1,6 @@
+host_client: clean
+ go get -u github.com/valyala/fasthttp
+ go build
+
+clean:
+ rm -f host_client
diff --git a/examples/host_client/README.md b/examples/host_client/README.md
new file mode 100644
index 0000000..e40b397
--- /dev/null
+++ b/examples/host_client/README.md
@@ -0,0 +1,13 @@
+# Host Client Example
+
+The HostClient is useful when calling an API from a single host.
+The example also shows how to use URI.
+You may create the parsed URI once and reuse it in many requests.
+The URI has a username and password for Basic Auth but you may also set other parts i.e. `SetPath()`, `SetQueryString()`.
+
+# How to build and run
+Start a web server on localhost:8080 then execute:
+
+ make
+ ./host_client
+
diff --git a/examples/host_client/hostclient.go b/examples/host_client/hostclient.go
new file mode 100644
index 0000000..fd1d691
--- /dev/null
+++ b/examples/host_client/hostclient.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/valyala/fasthttp"
+)
+
+func main() {
+ // Get URI from a pool
+ url := fasthttp.AcquireURI()
+ url.Parse(nil, []byte("http://localhost:8080/"))
+ url.SetUsername("Aladdin")
+ url.SetPassword("Open Sesame")
+
+ hc := &fasthttp.HostClient{
+ Addr: "localhost:8080", // The host address and port must be set explicitly
+ }
+
+ req := fasthttp.AcquireRequest()
+ req.SetURI(url) // copy url into request
+ fasthttp.ReleaseURI(url) // now you may release the URI
+
+ req.Header.SetMethod(fasthttp.MethodGet)
+ resp := fasthttp.AcquireResponse()
+ err := hc.Do(req, resp)
+ fasthttp.ReleaseRequest(req)
+ if err == nil {
+ fmt.Printf("Response: %s\n", resp.Body())
+ } else {
+ fmt.Fprintf(os.Stderr, "Connection error: %s\n", err)
+ }
+ fasthttp.ReleaseResponse(resp)
+}