Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Have I found a bug in BodyParser, or am I an idiot? #2918

Closed
3 tasks done
lachdoug opened this issue Mar 12, 2024 · 4 comments
Closed
3 tasks done

Have I found a bug in BodyParser, or am I an idiot? #2918

lachdoug opened this issue Mar 12, 2024 · 4 comments

Comments

@lachdoug
Copy link

Question Description

I am new to Fiber so please forgive me is this is a noob issue, but I can't understand what is going wrong with my Fiber app code.

I am trying to achieve the following:

  1. De-serialize a request body to a struct
  2. Add the new struct to a collection
  3. Repeat
package main

import (
	"fmt"
	"log"

	"github.com/gofiber/fiber/v2"
)

type Record struct {
	Value string
}

func main() {
	records := []Record{}

	router := fiber.New(fiber.Config{})

	router.Post("/", func(ctx *fiber.Ctx) error {
		var record Record
		if err := ctx.BodyParser(&record); err != nil {
			return err
		}

		records = append(records, record)

		return ctx.SendString(fmt.Sprintf("%+v\n", records))
	})

	log.Fatal(router.Listen(":8080"))
}

When I add the first record things work as expected:

$ curl localhost:8080 --request POST --data value=1
[{Value:1}]

When I add a second record, the value in the first record is changed/corrupted.

$ curl localhost:8080 --request POST --data value=2
[{Value:2} {Value:2}]

I didn't expect that. I expected the first item to have a value of 1 and the second record to have a value of 2..

Here's what happens when more items are added.

$ curl localhost:8080 --request POST --data value=3
[{Value:3} {Value:3} {Value:3}]
$ curl localhost:8080 --request POST --data value=abc
[{Value:a} {Value:a} {Value:a} {Value:abc}]

At this point the collection should be [{Value:1} {Value:2} {Value:3} {Value:abc}]

What am I doing wrong?

Code Snippet (optional)

No response

Checklist:

  • I agree to follow Fiber's Code of Conduct.
  • I have checked for existing issues that describe my questions prior to opening this one.
  • I understand that improperly formatted questions may be closed without explanation.
Copy link

welcome bot commented Mar 12, 2024

Thanks for opening your first issue here! 🎉 Be sure to follow the issue template! If you need help or want to chat with us, join us on Discord https://gofiber.io/discord

@nickajacks1
Copy link
Member

This is because by default, you cannot keep references to request data beyond the scope of the handler. What you're seeing is that the underlying buffer of the string is reused between requests.
See the fine print at the end of the BodyParser section: https://docs.gofiber.io/api/ctx#bodyparser
Please note that other methods have this same behavior.

You can get around this two ways:

  • Use the Immutable config setting https://docs.gofiber.io/api/fiber#config . You most likely will never notice the performance hit from enabling this (depending on what you're doing, of course).
  • Make a copy of the data, eg record.Value = strings.Clone(record.Value). Unfortunately, there isn't a super simple way to make a deep copy of a struct. You'd need to manually copy each string field in your struct.

@gaby
Copy link
Member

gaby commented Mar 13, 2024

@lachdoug
Copy link
Author

Thank you @nickajacks1 and @gaby
That explains it. Much appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants