Skip to content

Commit

Permalink
Merge pull request #70 from northseadl/feature/httpRequest
Browse files Browse the repository at this point in the history
multipart dataflow
  • Loading branch information
Matrix-X authored Jan 7, 2023
2 parents 330325d + 91252d2 commit b87f2cb
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 0 deletions.
14 changes: 14 additions & 0 deletions http/contract/dataflowInterface.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"io"
"net/http"
"net/textproto"
)

// RequestDataflowInterface 是一个 Http 请求构建器, 建议将注释中的私有方法实现到内部
Expand All @@ -24,6 +25,7 @@ type RequestDataflowInterface interface {
Body(body io.Reader) RequestDataflowInterface
Any(data BodyEncoder) RequestDataflowInterface
Xml(xmlAny interface{}) RequestDataflowInterface
Multipart(multipartDf func(multipart MultipartDfInterface)) RequestDataflowInterface

Err() error

Expand All @@ -46,3 +48,15 @@ type ResponseHelper interface {
GetBodyBytes() ([]byte, error)
GetBodyJsonAsMap() (map[string]interface{}, error)
}

type MultipartDfInterface interface {
Boundary(b string) MultipartDfInterface
FileByPath(fieldName string, filePath string) MultipartDfInterface
Part(header textproto.MIMEHeader, reader io.Reader) MultipartDfInterface
FieldValue(fieldName string, value string) MultipartDfInterface
Field(fieldName string, reader io.Reader) MultipartDfInterface
GetBoundary() string
GetReader() io.Reader
GetContentType() string
Err() error
}
13 changes: 13 additions & 0 deletions http/dataflow/dataflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,19 @@ func (d *Dataflow) Xml(xmlAny interface{}) contract.RequestDataflowInterface {
return d
}

func (d *Dataflow) Multipart(multipartDf func(multipart contract.MultipartDfInterface)) contract.RequestDataflowInterface {
multipart := NewMultipartHelper()
multipartDf(multipart)
err := multipart.Err()
if err != nil {
d.err = append(d.err, err)
return d
}
d.Header("content-type", multipart.GetContentType())
d.Body(multipart.GetReader())
return d
}

func (d *Dataflow) Err() error {
if len(d.err) > 0 {
return d.err[0]
Expand Down
19 changes: 19 additions & 0 deletions http/dataflow/dataflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,22 @@ func TestDataflow_Xml(t *testing.T) {
t.Error("xml body failed")
}
}

func TestDataflow_Multipart(t *testing.T) {
df := InitBaseDataflow()

df.Multipart(func(multipart contract.MultipartDfInterface) {
mpDataflow := NewMultipartHelper()
mpDataflow.Boundary("test-boundary")
mpDataflow.FieldValue("param1", "value1")
data := strings.NewReader("it's a string reader")
mpDataflow.Field("data", data)
if mpDataflow.Err() != nil {
t.Error(mpDataflow.Err())
}
})

if df.Err() != nil {
t.Error(df.Err())
}
}
124 changes: 124 additions & 0 deletions http/dataflow/mutlipart.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package dataflow

import (
"bytes"
"github.com/ArtisanCloud/PowerLibs/v3/http/contract"
"github.com/pkg/errors"
"io"
"mime/multipart"
"net/textproto"
"os"
"path"
)

type MultipartDf struct {
buf bytes.Buffer
mWriter *multipart.Writer
errs []error
}

func NewMultipartHelper() contract.MultipartDfInterface {
df := MultipartDf{}
mWriter := multipart.NewWriter(&df.buf)
df.mWriter = mWriter
return &df
}

func (m *MultipartDf) Boundary(b string) contract.MultipartDfInterface {
err := m.mWriter.SetBoundary(b)
if err != nil {
m.errs = append(m.errs, errors.Wrap(err, "set boundary failed"))
}
return m
}

func (m *MultipartDf) FileByPath(fieldName string, filePath string) contract.MultipartDfInterface {
file, err := os.OpenFile(filePath, os.O_RDONLY, 0644)
if err != nil {
m.errs = append(m.errs, errors.Wrap(err, "create file part failed"))
}
_, fileName := path.Split(filePath)

writer, err := m.mWriter.CreateFormFile(fieldName, fileName)
if err != nil {
m.errs = append(m.errs, errors.Wrap(err, "create file part failed"))
}
var buf bytes.Buffer
_, err = buf.ReadFrom(file)
if err != nil {
m.errs = append(m.errs, errors.Wrap(err, "create file part failed"))
}
_, err = buf.WriteTo(writer)
if err != nil {
m.errs = append(m.errs, errors.Wrap(err, "create file part failed"))
}
return m
}

func (m *MultipartDf) Part(header textproto.MIMEHeader, reader io.Reader) contract.MultipartDfInterface {
writer, err := m.mWriter.CreatePart(header)
if err != nil {
m.errs = append(m.errs, errors.Wrap(err, "create part failed"))
return m
}
var buf bytes.Buffer
_, err = buf.ReadFrom(reader)
if err != nil {
m.errs = append(m.errs, errors.Wrap(err, "create part read failed"))
return m
}
_, err = buf.WriteTo(writer)
if err != nil {
m.errs = append(m.errs, errors.Wrap(err, "create part write failed"))
return m
}
return m
}

func (m *MultipartDf) FieldValue(fieldName string, value string) contract.MultipartDfInterface {
err := m.mWriter.WriteField(fieldName, value)
if err != nil {
m.errs = append(m.errs, errors.Wrap(err, "set field failed"))
}
return m
}

func (m *MultipartDf) Field(fieldName string, reader io.Reader) contract.MultipartDfInterface {
writer, err := m.mWriter.CreateFormField(fieldName)
if err != nil {
m.errs = append(m.errs, errors.Wrap(err, "create field failed"))
return m
}
var buf bytes.Buffer
_, err = buf.ReadFrom(reader)
if err != nil {
m.errs = append(m.errs, errors.Wrap(err, "create field read failed"))
return m
}
_, err = buf.WriteTo(writer)
if err != nil {
m.errs = append(m.errs, errors.Wrap(err, "create field write failed"))
return m
}
return m
}

func (m *MultipartDf) GetBoundary() string {
return m.mWriter.Boundary()
}

func (m *MultipartDf) GetReader() io.Reader {
return &m.buf
}

func (m *MultipartDf) GetContentType() string {
return m.mWriter.FormDataContentType()
}

func (m *MultipartDf) Err() error {
if len(m.errs) == 0 {
return nil
} else {
return m.errs[0]
}
}
24 changes: 24 additions & 0 deletions http/helper/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"github.com/ArtisanCloud/PowerLibs/v3/http/contract"
"log"
"net/http"
"strings"
"testing"
)

func ExampleRequestHelper_WithMiddleware() {
Expand Down Expand Up @@ -160,3 +162,25 @@ func ExampleHttpDebugMiddleware() {
// "status": "success"
//}
}

func TestRequestHelper_Df_Multipart(t *testing.T) {
helper, err := NewRequestHelper(&Config{})
if err != nil {
t.Error(err)
}

_, err = helper.Df().Method(http.MethodPost).
Url("https://typedwebhook.tools/webhook").
Multipart(func(multipart contract.MultipartDfInterface) {
data := strings.NewReader("test data")
multipart.Boundary("test-boundary").
//FileByPath("file", "README.md").
FieldValue("param1", "value1").
FieldValue("param2", "value2").
Field("data", data)
}).Request()

if err != nil {
t.Error(err)
}
}

0 comments on commit b87f2cb

Please sign in to comment.