labstack / echo

High performance, minimalist Go web framework
https://echo.labstack.com
MIT License
29.61k stars 2.22k forks source link

Binding into a pointer to a slice returns an error "unknown type" #2381

Closed maticmeznar closed 6 months ago

maticmeznar commented 1 year ago

Issue Description

When binding input data into a struct with a field with a pointer to a slice, *[]string for example, Bind method returns "unknown type" error.

Checklist

Expected behaviour

Successfully bind input data into the provided struct

Actual behaviour

Bind method returns "unknown type" error

Steps to reproduce

package echotest

import (
    "net/http"
    "net/http/httptest"
    "net/url"
    "testing"

    "github.com/davecgh/go-spew/spew"
    "github.com/labstack/echo/v4"
    "github.com/stretchr/testify/assert"
)

type (
    InputData struct {
        Tags *[]string `json:"tags" query:"tags"`
    }

    handler struct{}
)

func (h *handler) testHandler1(c echo.Context) error {
    data := new(InputData)
    if err := c.Bind(data); err != nil {
        return err
    }

    spew.Dump(data)

    return c.JSON(http.StatusOK, data)
}

func TestTest(t *testing.T) {
    e := echo.New()

    q := make(url.Values)
    q.Add("tags", "testing")
    q.Add("tags", "server")

    req := httptest.NewRequest(http.MethodGet, "/?"+q.Encode(), nil)
    // req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
    rec := httptest.NewRecorder()
    c := e.NewContext(req, rec)

    h := &handler{}
    if assert.NoError(t, h.testHandler1(c)) {
        assert.Equal(t, http.StatusOK, rec.Code)
    }
}

Version/commit

v4.9.1

aldas commented 1 year ago

Changing that field from *[]string to []string should do the trick. At the moment binder knows to only to handle pointers to common types ala string,bool, structs etc and not their slice variants.

InputData struct {
        Tags []string `json:"tags" query:"tags"`
    }

Anyway, I think you are overthinking here with pointers. Unitilialized slice is nil. So if that testcase would have no tags query params this would be after bind:

image

Couple of articles about empty slices:

maticmeznar commented 1 year ago

Thank you for the reply. The problem is that the struct is automatically generated by oapi-codegen and it creates a pointer unless I set the field as required in the OpenAPI spec.

I was hoping this was a bug since binding into a pointer to a slice works with JSON in the request body.

aldas commented 1 year ago

I'll take a look we probably can do something with binder.

for history sake: pointer to slice related issue https://github.com/deepmap/oapi-codegen/issues/266