Search code examples
apigoswaggergo-swagger

How to implement new media types in swagger backend


I have created a swagger specification which produces "application/zip"

/config:
  get:
    produces:
      - application/zip
    responses:
        200: # OK
          description: All config files
          schema:
            type: string
            format: binary

I have implemented the handlers for this endpoint but I get this error

http: panic serving 127.0.0.1:20366: applicationZip producer has not yet been implemented

This error is coming from this code

func NewSampleAPI(spec *loads.Document) *SampleAPI {
    return &SampleAPI{
    ...
        ApplicationZipProducer: runtime.ProducerFunc(func(w io.Writer, data interface{}) error {
            return errors.NotImplemented("applicationZip producer has not yet been implemented")
        }),

After investigating this error my findings are that we need to implement something like this

api := operations.NewSampleAPI(swaggerSpec)
api.ApplicationZipProducer = func(w io.Writer, data interface{}) error {
    ...
}

So my question is that

  1. what should we put in this Producer and why is it necessary to implement this because there is no implementation for "application/json" ?

  2. Is "application/json" Producer is implemented by default and we need to implement other producers?

Note: I am using swagger "2.0" spec


Solution

  • Since you have used "application/zip" as response content then you might have implemented the backend code which might be returning io.ReadCloser. Then your Producer will look like this

    api.ApplicationZipProducer = runtime.ProducerFunc(func(w io.Writer, data interface{}) error {
            if w == nil {
                return errors.New("ApplicationZipProducer requires a writer") // early exit
            }
    
            if data == nil {
                return errors.New("no data given to produce zip from")
            }
            if zp, ok := data.(io.ReadCloser); ok {
                b, err := ioutil.ReadAll(zp)
                if err != nil {
                    return fmt.Errorf("application zip producer: %v", err)
                }
                _, err = w.Write(b)
                return nil
            }
            return fmt.Errorf("%v (%T) is not supported by the ApplicationZipProducer, %s", data, data)
        })
    

    This will parse the data interface into io.ReadCloser and read data from it and then it will fill into the io.Writer

    Note: If your main purpose is just send file as attachment then you should use "application/octet-stream" and its producer is implemented by default