I have an endpoint that receives a CSV file through HTTP. To generate the server code I use oapi-codegen with net/http go 1.22.2
in strict-server mode.
The endpoint OpenAPI definition looks like this:
paths:
/api/v1/shipments:
post:
summary: Add new shipments
operationId: AddShipments
tags:
- Shipments
requestBody:
required: true
content:
text/csv:
schema:
description: Shipments encoded as a CSV file
type: string
example: |-
'Delivery Place', 'Pickup Place', 'Size', 'Pallete', 'Pickup Times', 'Delivery Times'
'eb256bda-217d-4ae8-8559-f806abd92aca', 'ddb8a0f5-7f40-4cf9-92b3-6dc61fe5bf6a', 1, euro1, '{[2024-03-16 18:50+02, 2024-03-23 10:00+02:00], [2024-03-26 10:00-3, 2024-03-28 17:00-03]}', '{}'
...
And the generated interface looks like this:
type AddShipmentsRequestObject struct {
Body io.Reader
}
type StrictServerInterface interface {
// Add new shipments
// (POST /api/v1/shipments)
AddShipments(ctx context.Context, request AddShipmentsRequestObject) (AddShipmentsResponseObject, error)
}
The problem I face and I don’t understand how to resolve is that lines in the CSV (delimited by n
) are not correctly parsed by the csv.NewReader(request.Body)
reader, resulting in something of the following:
Example CSV:
Header1,Header2,Header3
Field1Line1,Field2Line1,Field3Line1
Field1Line2,Field2Line2,Field3Line2
Request:
curl -X 'POST'
'http://172.23.0.4:10000/api/v1/shipments'
-H 'Content-Type: text/csv'
-d @test.csv
Printed results in logs:
Records: [[Header1 Header2 Header3Field1Line1 Field2Line1 Field3Line1Field1Line2 Field2Line2 Field3Line2]]
instead of the expected output:
Records: [[Header1 Header2 Header3] [Field1Line1 Field2Line1 Field3Line1] [Field1Line2 Field2Line2 Field3Line2]]
Finally, my simple implementation is this:
func (impl *ServerImpl) AddShipments(ctx context.Context, request server.AddShipmentsRequestObject) (server.AddShipmentsResponseObject, error) {
impl.mux.Lock()
defer impl.mux.Unlock()
tx, err := impl.pool.Begin(ctx)
if err != nil {
return server.AddShipments500Response{}, err
}
defer tx.Rollback(ctx)
qtx := impl.db.WithTx(tx)
if request.Body == nil {
return server.AddShipments422Response{}, fmt.Errorf("request body is nil")
}
r := csv.NewReader(request.Body)
if r == nil {
return server.AddShipments500Response{}, fmt.Errorf("csv reader is nil")
}
records, err := r.ReadAll()
if err != nil && err != io.EOF {
return server.AddShipments500Response{}, err
}
fmt.Printf("Records: %vn", records)
return nil, nil
}
I also tried using gocsv (which I intend to use in the end to decode the CSV into structs), but faced the exact same issue. This happens with every CSV file I have tried, either handwritten or generated.
epnotdounalive is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.