1

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)
}
  • take a look at https://stackoverflow.com/questions/20205796/post-data-using-the-content-type-multipart-form-data and https://stackoverflow.com/questions/7223616/http-post-file-multipart – Vlad Vladov Mar 20 '23 at 13:20
  • 1
    Thanks, I was able to find the answer in the first link, I'll attach it below – Danila Derzhavin Mar 20 '23 at 14:02

1 Answers1

1

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)
}