I use echo framework for building REST API. I receive file via http request and i need to send it to the next API service by post request. How i can do this without storing file?
I've tried this way, but it doesn't feel right, because i have an error in response "Could not parse content as FormData"
func (h *Handler) UploadFile(c echo.Context) error {
formFile, err := c.FormFile("file")
if err != nil {
return err
}
file, err := formFile.Open()
if err != nil {
return err
}
defer file.Close()
cid, err := h.s.Upload(context.Background(), file)
if err != nil {
return err
}
return c.String(http.StatusOK, "Ok")
}
func (s *Storage) Upload(ctx context.Context, file io.Reader) (cid.Cid, error) {
req, err := http.NewRequest(http.MethodPost, s.config.endpoint+"/upload", file)
if err != nil {
return cid.Undef, err
}
req.Header.Set("accept", "application/json")
req.Header.Set("Content-Type", "multipart/form-data")
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", s.config.token))
res, err := s.config.hc.Do(req)
if err != nil {
return cid.Undef, err
}
d := json.NewDecoder(res.Body)
if res.StatusCode != 200 {
return cid.Undef, fmt.Errorf("unexpected response status: %d", res.StatusCode)
}
var out struct {
Cid string `json:"cid"`
}
err = d.Decode(&out)
if err != nil {
return cid.Undef, err
}
return cid.Parse(out.Cid)
}
Here is the solution. Thanks Vlad Vladov.
func (s *Storage) Upload(ctx context.Context, file multipart.File, fileHeader *multipart.FileHeader) (cid.Cid, error) {
rCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
buf := new(bytes.Buffer)
writer := multipart.NewWriter(buf)
part, err := writer.CreateFormFile("file", fileHeader.Filename)
if err != nil {
return cid.Undef, err
}
b, err := ioutil.ReadAll(file)
if err != nil {
return cid.Undef, err
}
part.Write(b)
writer.Close()
req, err := http.NewRequestWithContext(rCtx, http.MethodPost, s.config.endpoint+"/upload", buf)
if err != nil {
return cid.Undef, err
}
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", s.config.token))
req.Header.Set("X-Client", "web3.storage/go")
res, err := s.config.hc.Do(req)
if err != nil {
return cid.Undef, err
}
d := json.NewDecoder(res.Body)
if res.StatusCode != 200 {
var out responseError
d.Decode(&out)
log.Error(out)
return cid.Undef, fmt.Errorf("unexpected response status: %d", res.StatusCode)
}
var out struct {
Cid string `json:"cid"`
}
err = d.Decode(&out)
if err != nil {
return cid.Undef, err
}
return cid.Parse(out.Cid)
}