Skip to content

Commit

Permalink
Merge pull request #72 from ArtisanCloud/feature/httpRequest
Browse files Browse the repository at this point in the history
Feature/http request
  • Loading branch information
Matrix-X authored Jan 8, 2023
2 parents 269c1d0 + bf9353d commit 605693d
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 0 deletions.
16 changes: 16 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,17 @@ type ResponseHelper interface {
GetBodyBytes() ([]byte, error)
GetBodyJsonAsMap() (map[string]interface{}, error)
}

type MultipartDfInterface interface {
Boundary(b string) MultipartDfInterface
FileByPath(fieldName string, filePath string) MultipartDfInterface
FileMem(fieldName string, fileName string, reader io.Reader) MultipartDfInterface
Part(header textproto.MIMEHeader, reader io.Reader) MultipartDfInterface
FieldValue(fieldName string, value string) MultipartDfInterface
Field(fieldName string, reader io.Reader) MultipartDfInterface
Close() error
GetBoundary() string
GetReader() io.Reader
GetContentType() string
Err() error
}
18 changes: 18 additions & 0 deletions http/dataflow/dataflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,24 @@ 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.Close()
if err != nil {
d.err = append(d.err, err)
return d
}
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())
}
}
145 changes: 145 additions & 0 deletions http/dataflow/mutlipart.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
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) FileMem(fieldName string, fileName string, reader io.Reader) contract.MultipartDfInterface {
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(reader)
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) Close() error {
return m.mWriter.Close()
}

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 605693d

Please sign in to comment.