Skip to content

Commit 5e1ff77

Browse files
taisho6339casualjim
authored andcommitted
Add CSV Support
Signed-off-by: Hiroki Sakamoto <taisho6339@gmail.com>
1 parent cdfa0fc commit 5e1ff77

5 files changed

Lines changed: 198 additions & 1 deletion

File tree

client/runtime.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,13 +207,15 @@ func New(host, basePath string, schemes []string) *Runtime {
207207
runtime.XMLMime: runtime.XMLConsumer(),
208208
runtime.TextMime: runtime.TextConsumer(),
209209
runtime.HTMLMime: runtime.TextConsumer(),
210+
runtime.CSVMime: runtime.CSVConsumer(),
210211
runtime.DefaultMime: runtime.ByteStreamConsumer(),
211212
}
212213
rt.Producers = map[string]runtime.Producer{
213214
runtime.JSONMime: runtime.JSONProducer(),
214215
runtime.XMLMime: runtime.XMLProducer(),
215216
runtime.TextMime: runtime.TextProducer(),
216217
runtime.HTMLMime: runtime.TextProducer(),
218+
runtime.CSVMime: runtime.CSVProducer(),
217219
runtime.DefaultMime: runtime.ByteStreamProducer(),
218220
}
219221
rt.Transport = http.DefaultTransport

client/runtime_test.go

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ import (
3939

4040
// task This describes a task. Tasks require a content property to be set.
4141
type task struct {
42-
4342
// Completed
4443
Completed bool `json:"completed" xml:"completed"`
4544

@@ -366,6 +365,50 @@ func TestRuntime_TextCanary(t *testing.T) {
366365
}
367366
}
368367

368+
func TestRuntime_CSVCanary(t *testing.T) {
369+
// test that it can make a simple csv request
370+
// and get the response for it.
371+
result := `task,content,result
372+
1,task1,ok
373+
2,task2,fail
374+
`
375+
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
376+
rw.Header().Add(runtime.HeaderContentType, runtime.CSVMime)
377+
rw.WriteHeader(http.StatusOK)
378+
_, _ = rw.Write([]byte(result))
379+
}))
380+
defer server.Close()
381+
382+
rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
383+
return nil
384+
})
385+
386+
hu, _ := url.Parse(server.URL)
387+
rt := New(hu.Host, "/", []string{"http"})
388+
res, err := rt.Submit(&runtime.ClientOperation{
389+
ID: "getTasks",
390+
Method: "GET",
391+
PathPattern: "/",
392+
Params: rwrtr,
393+
Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
394+
if response.Code() == 200 {
395+
var result bytes.Buffer
396+
if err := consumer.Consume(response.Body(), &result); err != nil {
397+
return nil, err
398+
}
399+
return result, nil
400+
}
401+
return nil, errors.New("Generic error")
402+
}),
403+
})
404+
405+
if assert.NoError(t, err) {
406+
assert.IsType(t, bytes.Buffer{}, res)
407+
actual := res.(bytes.Buffer)
408+
assert.EqualValues(t, result, actual.String())
409+
}
410+
}
411+
369412
type roundTripperFunc func(*http.Request) (*http.Response, error)
370413

371414
func (fn roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {

constants.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ const (
3838
TextMime = "text/plain"
3939
// HTMLMime the html mime type
4040
HTMLMime = "text/html"
41+
// CSVMime the csv mime type
42+
CSVMime = "text/csv"
4143
// MultipartFormMime the multipart form mime type
4244
MultipartFormMime = "multipart/form-data"
4345
// URLencodedFormMime the url encoded form mime type

csv.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2015 go-swagger maintainers
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package runtime
16+
17+
import (
18+
"bytes"
19+
"encoding/csv"
20+
"errors"
21+
"io"
22+
)
23+
24+
// CSVConsumer creates a new CSV consumer
25+
func CSVConsumer() Consumer {
26+
return ConsumerFunc(func(reader io.Reader, data interface{}) error {
27+
if reader == nil {
28+
return errors.New("CSVConsumer requires a reader")
29+
}
30+
31+
csvReader := csv.NewReader(reader)
32+
writer, ok := data.(io.Writer)
33+
if !ok {
34+
return errors.New("data type must be io.Writer")
35+
}
36+
csvWriter := csv.NewWriter(writer)
37+
records, err := csvReader.ReadAll()
38+
if err != nil {
39+
return err
40+
}
41+
for _, r := range records {
42+
if err := csvWriter.Write(r); err != nil {
43+
return err
44+
}
45+
}
46+
csvWriter.Flush()
47+
return nil
48+
})
49+
}
50+
51+
// CSVProducer creates a new CSV producer
52+
func CSVProducer() Producer {
53+
return ProducerFunc(func(writer io.Writer, data interface{}) error {
54+
if writer == nil {
55+
return errors.New("CSVProducer requires a writer")
56+
}
57+
58+
dataBytes, ok := data.([]byte)
59+
if !ok {
60+
return errors.New("data type must be byte array")
61+
}
62+
63+
csvReader := csv.NewReader(bytes.NewBuffer(dataBytes))
64+
records, err := csvReader.ReadAll()
65+
if err != nil {
66+
return err
67+
}
68+
csvWriter := csv.NewWriter(writer)
69+
for _, r := range records {
70+
if err := csvWriter.Write(r); err != nil {
71+
return err
72+
}
73+
}
74+
csvWriter.Flush()
75+
return nil
76+
})
77+
}

csv_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2015 go-swagger maintainers
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package runtime
16+
17+
import (
18+
"bytes"
19+
"github.com/stretchr/testify/assert"
20+
"io"
21+
"net/http/httptest"
22+
"testing"
23+
)
24+
25+
const consProdCSV = `name,country,age
26+
John,US,19
27+
Mike,US,20
28+
`
29+
30+
type csvEmptyReader struct{}
31+
32+
func (r *csvEmptyReader) Read(d []byte) (int, error) {
33+
return 0, io.EOF
34+
}
35+
36+
func TestCSVConsumer(t *testing.T) {
37+
cons := CSVConsumer()
38+
reader := bytes.NewBuffer([]byte(consProdCSV))
39+
40+
outBuf := new(bytes.Buffer)
41+
err := cons.Consume(reader, outBuf)
42+
assert.NoError(t, err)
43+
assert.Equal(t, consProdCSV, outBuf.String())
44+
45+
outBuf2 := new(bytes.Buffer)
46+
err = cons.Consume(nil, outBuf2)
47+
assert.Error(t, err)
48+
49+
err = cons.Consume(reader, struct{}{})
50+
assert.Error(t, err)
51+
52+
emptyOutBuf := new(bytes.Buffer)
53+
err = cons.Consume(&csvEmptyReader{}, emptyOutBuf)
54+
assert.NoError(t, err)
55+
assert.Equal(t, "", emptyOutBuf.String())
56+
}
57+
58+
func TestCSVProducer(t *testing.T) {
59+
prod := CSVProducer()
60+
data := []byte(consProdCSV)
61+
62+
rw := httptest.NewRecorder()
63+
err := prod.Produce(rw, data)
64+
assert.NoError(t, err)
65+
assert.Equal(t, consProdCSV, rw.Body.String())
66+
67+
rw2 := httptest.NewRecorder()
68+
err = prod.Produce(rw2, struct{}{})
69+
assert.Error(t, err)
70+
71+
err = prod.Produce(nil, data)
72+
assert.Error(t, err)
73+
}

0 commit comments

Comments
 (0)