Coder Social home page Coder Social logo

Comments (6)

ggicci avatar ggicci commented on August 16, 2024 1

While there's a tricky apprach, let's create a custom type and implement the Stringable interface:

Online demo: https://go.dev/play/p/4IiRYr8n7zg

type CommaSeparatedIntegerArray struct {
	Values []int
}

func (a CommaSeparatedIntegerArray) ToString() (string, error) {
	var res = make([]string, len(a.Values))
	for i := range a.Values {
		res[i] = strconv.Itoa(a.Values[i])
	}
	return strings.Join(res, ","), nil
}

func (pa *CommaSeparatedIntegerArray) FromString(value string) error {
	a := CommaSeparatedIntegerArray{}
	values := strings.Split(value, ",")
	a.Values = make([]int, len(values))
	for i := range values {
		if value, err := strconv.Atoi(values[i]); err != nil {
			return err
		} else {
			a.Values[i] = value
		}
	}
	*pa = a
	return nil
}

type ListUsersInput struct {
	IdList CommaSeparatedIntegerArray `in:"query=id"`
}

from httpin.

ggicci avatar ggicci commented on August 16, 2024 1

@krispetkov your idea looks good to me. I think rewriting the query from ids=1,2,3 to ids=1&ids=2&ids=3 is a better way for this case. As httpin does support parsing the latter format of query. And you can use type []int as well.

from httpin.

krispetkov avatar krispetkov commented on August 16, 2024

Actually I tried to modify the provided example in custom directive, but it seems to not be working at all. The functions are not being called at all 🤔 I don't know if it has something to do that I'm using:

httpIn "github.com/ggicci/httpin"

if err = httpIn.Decode(r, &filters); err != nil {
	http.Error(w, err.Error(), http.StatusBadRequest)
	return
}

And here what implementation I tried

type DirectiveCaseFormatter struct {
	Transform func(string) []int
}

func (f *DirectiveCaseFormatter) Decode(rtm *httpInCore.DirectiveRuntime) error {
	if rtm.Value.Type().Elem().Kind() != reflect.String {
		return errors.New("not a string")
	}

	currentValue := rtm.Value.Elem().String()
	newValue := f.Transform(currentValue)
	slice := reflect.MakeSlice(reflect.TypeOf([]int{}), len(newValue), len(newValue))
	for i, num := range newValue {
		slice.Index(i).SetInt(int64(num))
	}
	rtm.Value.Elem().Set(slice)
	return nil
}

func (f *DirectiveCaseFormatter) Encode(rtm *httpInCore.DirectiveRuntime) error {
	if rtm.Value.Type().Kind() != reflect.String {
		return errors.New("not a string")
	}

	currentValue := rtm.Value.String()
	newValue := f.Transform(currentValue)
	slice := reflect.MakeSlice(reflect.TypeOf([]int{}), len(newValue), len(newValue))
	for i, num := range newValue {
		slice.Index(i).SetInt(int64(num))
	}
	rtm.Value.Elem().Set(slice)
	return nil
}

httpInCore.RegisterDirective("to_array", &DirectiveCaseFormatter{
	Transform: func(s string) []int {
		pieces := strings.Split(s, ",")
		ints := make([]int, len(pieces))
		for i, piece := range pieces {
			num, err := strconv.Atoi(piece)
			if err != nil {
				log.Printf("Could not convert piece to integer: %v", err)
				continue
			}
			ints[i] = num
		}
		return ints
	},
})

from httpin.

ggicci avatar ggicci commented on August 16, 2024

Hi @krispetkov, currently httpin doesn't support your use case. In httpin, a value of a single key in the request (id=1,2,3) is treated as a scalar value and won't be converted/mapped to an array. i.e.

?id=1,2,3  ---> only can be mapped to type T(string, int, time.Time, MyDate, etc),
                          but not []T ([]int, []string, etc)

from httpin.

krispetkov avatar krispetkov commented on August 16, 2024

Hey @ggicci, thanks for the proposed solution. I also came up with something, but by using the custom directive. It's just a sample and can be further improved (the logic, the usage of hardcoded ids name, etc.), but I think something like this may also do the work:

import (
    httpInCore "github.com/ggicci/httpin/core"
    httpInIntegration "github.com/ggicci/httpin/integration"
)

func init() {
	httpInCore.RegisterDirective("toArray", &ToArrayFormatter{})
}

type ToArrayFormatter struct {
}

func (f *ToArrayFormatter) Decode(rtm *httpInCore.DirectiveRuntime) error {
	req := rtm.GetRequest()
	params, err := url.ParseQuery(req.URL.RawQuery)
	if err != nil {
		return fmt.Errorf("could not parse query: %v", err)
	}

	if len(params["ids"]) == 1 { // it was passed as a list of ids (eg. ?ids=1,2,3)
		ids, ok := params["ids"]
		if ok {
			// Try to split the string by comma
			idStrings := strings.Split(ids[0], ",")
			if len(idStrings) == 0 {
				// Try to split the string by semicolon
				idStrings = strings.Split(ids[0], ";")
			}
			params.Del("ids")
			for _, id := range idStrings {
				params.Add("ids", id)
			}
		}

		req.URL.RawQuery = params.Encode()
	} else {
		// Check if any of the passed ids is a valid number
		for _, id := range params["ids"] {
			_, err := strconv.ParseFloat(id, 64)
			if err != nil {
				return fmt.Errorf("arg %s is not a valid number", id)
			}
		}
	}

	return nil
}

func (f *ToArrayFormatter) Encode(rtm *httpInCore.DirectiveRuntime) error {
	// Your code here ...
	return nil
}

type Filters struct {
	Ids []int `in:"toArray;query=ids"` // query param (eg. ?ids=1,2,3)
}

from httpin.

krispetkov avatar krispetkov commented on August 16, 2024

Thanks for the help and the info! I will close the issue, and I hope it will help someone in future 🙌

from httpin.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.