github.com/thetreep/go-swagger@v0.0.0-20240223100711-35af64f14f01/examples/stream-client/README.md (about) 1 # Streaming client 2 3 This example demonstrates how to build a client from the generated client 4 to work against a streaming server. 5 6 Thanks to @nelz9999, who raised this in issue #883. 7 8 9 This example calls `https://jigsaw.w3c.org/` so as to contentrate on the client 10 side. For an example mixing the generated server and a client, see [here](../streaming-server/README.md). 11 12 The URL called by the API returns a blob of ASCII digits (1000 lines). 13 14 ## Try it 15 16 ### Blocking client 17 18 The client sends a request and blocks until the server has finished sending the response. 19 20 ``` 21 SWAGGER_DEBUG=1 go run jigsaw.go 22 23 2021/01/17 17:09:59 asking jigsaw server with blockingMode: true, chunkingMode: true 24 GET /HTTP/ChunkedScript HTTP/1.1 25 Host: jigsaw.w3.org 26 User-Agent: Go-http-client/1.1 27 Accept: application/json 28 Accept-Encoding: gzip 29 30 31 HTTP/1.1 200 OK 32 Transfer-Encoding: chunked 33 Cache-Control: max-age=0 34 Content-Type: text/plain 35 ... 36 Server: Jigsaw/2.3.0-beta2 37 Strict-Transport-Security: max-age=15552015; includeSubDomains; preload 38 X-Frame-Options: deny 39 X-Xss-Protection: 1; mode=block 40 41 2021/01/17 17:10:00 result: This output will be chunked encoded by the server, if your client is HTTP/1.1 42 Below this line, is 1000 repeated lines of 0-9. 43 ------------------------------------------------------------------------- 44 01234567890123456789012345678901234567890123456789012345678901234567890 45 ... 46 01234567890123456789012345678901234567890123456789012345678901234567890 47 ``` 48 49 ``` 50 # http2 client is detected by jigsaw: response is not chunked 51 SWAGGER_DEBUG=1 go run jigsaw.go nochunking 52 53 2021/01/17 17:10:12 asking jigsaw server with blockingMode: true, chunkingMode: false 54 GET /HTTP/ChunkedScript HTTP/1.1 55 Host: jigsaw.w3.org 56 User-Agent: Go-http-client/1.1 57 Accept: application/json 58 Accept-Encoding: gzip 59 60 61 HTTP/2.0 200 OK 62 Connection: close 63 Cache-Control: max-age=0 64 Content-Type: text/plain 65 ... 66 Server: Jigsaw/2.3.0-beta3 67 Strict-Transport-Security: max-age=15552015; includeSubDomains; preload 68 X-Frame-Options: deny 69 X-Xss-Protection: 1; mode=block 70 ... 71 72 2021/01/17 17:10:12 result: This output will be chunked encoded by the server, if your client is HTTP/1.1 73 Below this line, is 1000 repeated lines of 0-9. 74 ------------------------------------------------------------------------- 75 01234567890123456789012345678901234567890123456789012345678901234567890 76 ... 77 01234567890123456789012345678901234567890123456789012345678901234567890 78 ``` 79 80 ### Non-blocking client 81 82 The client sends a request and consumes the chunks as they are produced. 83 84 ``` 85 SWAGGER_DEBUG=1 go run jigsaw.go nonblocking 86 87 2021/01/17 17:09:23 asking jigsaw server with blockingMode: false, chunkingMode: true 88 GET /HTTP/ChunkedScript HTTP/1.1 89 Host: jigsaw.w3.org 90 User-Agent: Go-http-client/1.1 91 Accept: application/json 92 Accept-Encoding: gzip 93 94 HTTP/1.1 200 OK 95 Transfer-Encoding: chunked 96 Cache-Control: max-age=0 97 Content-Type: text/plain 98 ... 99 Server: Jigsaw/2.3.0-beta4 100 Strict-Transport-Security: max-age=15552015; includeSubDomains; preload 101 X-Frame-Options: deny 102 X-Xss-Protection: 1; mode=block 103 104 2021/01/17 17:09:23 line[1]: This output will be chunked encoded by the server, if your client is HTTP/1.1 105 2021/01/17 17:09:23 line[2]: Below this line, is 1000 repeated lines of 0-9. 106 2021/01/17 17:09:23 line[3]: ------------------------------------------------------------------------- 107 2021/01/17 17:09:23 line[4]: 01234567890123456789012345678901234567890123456789012345678901234567890 108 2021/01/17 17:09:23 line[5]: 01234567890123456789012345678901234567890123456789012345678901234567890 109 ... 110 2021/01/17 17:09:23 line[1003]: 01234567890123456789012345678901234567890123456789012345678901234567890 111 2021/01/17 17:09:23 EOF 112 ``` 113 114 ``` 115 SWAGGER_DEBUG=1 go run jigsaw.go nonblocking nochunking 116 117 2021/01/17 17:09:39 asking jigsaw server with blockingMode: false, chunkingMode: false 118 GET /HTTP/ChunkedScript HTTP/1.1 119 Host: jigsaw.w3.org 120 User-Agent: Go-http-client/1.1 121 Accept: application/json 122 Accept-Encoding: gzip 123 124 HTTP/2.0 200 OK 125 Connection: close 126 Cache-Control: max-age=0 127 Content-Type: text/plain 128 ... 129 Server: Jigsaw/2.3.0-beta3 130 Strict-Transport-Security: max-age=15552015; includeSubDomains; preload 131 X-Frame-Options: deny 132 X-Xss-Protection: 1; mode=block 133 134 2021/01/17 17:09:39 line[1]: This output will be chunked encoded by the server, if your client is HTTP/1.1 135 2021/01/17 17:09:39 line[2]: Below this line, is 1000 repeated lines of 0-9. 136 2021/01/17 17:09:39 line[3]: ------------------------------------------------------------------------- 137 2021/01/17 17:09:39 line[4]: 01234567890123456789012345678901234567890123456789012345678901234567890 138 2021/01/17 17:09:39 line[5]: 01234567890123456789012345678901234567890123456789012345678901234567890 139 ... 140 2021/01/17 17:09:39 line[1002]: 01234567890123456789012345678901234567890123456789012345678901234567890 141 2021/01/17 17:09:39 line[1003]: 01234567890123456789012345678901234567890123456789012345678901234567890 142 2021/01/17 17:09:39 EOF 143 ``` 144 145 ## How does it work? 146 147 ### Blocking: customizing the `io.Writer` 148 149 We have specified a `binary` format for the response (instead of, say, `[]string`). 150 151 We need to provide the runtime consumer with some means to unmarshal `text/plain` in this buffer. 152 153 The simplest way is to equip the destination buffer with a `UnmarshalText()` method. Like so: 154 ```go 155 type Buffer struct { 156 *bytes.Buffer 157 } 158 159 // UnmarshalText handles text/plain 160 func (b *Buffer) UnmarshalText(text []byte) error { 161 _, err := b.Write(text) 162 return err 163 } 164 165 buf := NewBuffer() 166 _, err := c.Chunked(operations.NewChunkedParams(), buf) 167 ``` 168 169 ### Non-blocking: customizing the consumer 170 171 We need to instruct the runtime client to use a `ByteStreamConsumer` when the response is `text/plain`. 172 Like so: 173 174 ```go 175 transport.Consumers[runtime.TextMime] = runtime.ByteStreamConsumer() 176 ``` 177 178 #### Non-blocking: unmarshalling the stream 179 180 The response is just a stream of byte, so the client has to unmarshal the messages received unitarily. 181 In this example, the stream is separated by line feed, so we can use a `bufio.Scanner` to do the job. 182 183 Notice the use of the `cancel()` method to interrupt the ongoing request if the go routine fails.