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

How to parse string to mail.Address #2743

Open
apuatcfbd opened this issue Feb 5, 2025 · 4 comments
Open

How to parse string to mail.Address #2743

apuatcfbd opened this issue Feb 5, 2025 · 4 comments

Comments

@apuatcfbd
Copy link

apuatcfbd commented Feb 5, 2025

I am trying to parse the following

type NewEmail struct {
	From        mail.Address                 `form:"from"`
	// ...
}

with

// In handler
if err := c.Bind(dtoPtr); err != nil { // dtoPtr is *NewEmail
	errResponse = c.JSON(http.StatusBadRequest, Res(ResData{
		Msg: "Review your input",
		D:   err, // here's the error
	}))
	return
}

Getting following error unknown type

{
  "d": {
    "message": "unknown type"
  },
  "msg": "Review your input",
  "status": false
}

I've checked that it works if I make NewEmail structs From field to string from mail.Address. It is beneficial for me if I can parse to mail.Address based on my use case. How this can be done?

@aldas
Copy link
Contributor

aldas commented Feb 5, 2025

Could you provide how mail.Address is declared? Is is struct or alias or ?

@apuatcfbd
Copy link
Author

apuatcfbd commented Feb 6, 2025

The type mail.Address is from net/mail of StdLib
That struct looks like the following

type Address struct {
    Name    string
    Address string
}

Echo version github.com/labstack/echo/v4 v4.13.3

@aldas
Copy link
Contributor

aldas commented Feb 6, 2025

This

package main

import (
	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
	"log/slog"
	"net/http"
	"net/mail"
)

func main() {
	e := echo.New()
	e.Use(middleware.Logger())

	e.POST("/", func(c echo.Context) error {
		type NewEmail struct {
			From mail.Address `form:"from"`
		}
		dto := &NewEmail{}
		if err := c.Bind(dto); err != nil { // dto is *NewEmail
			return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": err.Error()})
		}
		return c.JSON(http.StatusOK, dto)
	})

	if err := e.Start(":8080"); err != nil {
		slog.Error("failed to start server")
	}
}

does not work because you can only bind forms to (struct) fields that are explicitly marked with struct tags. But currently the target is struct with additional fields - this is not supported.

You could create your own address type and add tags

	e.POST("/", func(c echo.Context) error {
		type Address struct {
			Name    string `form:"name"`
			Address string `form:"address"`
		}

		type NewEmail struct {
			From Address
		}
		dto := &NewEmail{}
		if err := c.Bind(dto); err != nil { // dto is *NewEmail
			return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": err.Error()})
		}
		return c.JSON(http.StatusOK, dto)
	})

test with

curl --form name=testName --form address=testAddress http://localhost:8080/

@aldas
Copy link
Contributor

aldas commented Feb 6, 2025

note:
curl -H "Content-Type: application/json" --data '{"from":{"name":"test","address":"address"}}' http://localhost:8080/ would work with

	e.POST("/", func(c echo.Context) error {
		type NewEmail struct {
			From mail.Address
		}
		dto := &NewEmail{}
		if err := c.Bind(dto); err != nil { // dto is *NewEmail
			return c.JSON(http.StatusBadRequest, map[string]interface{}{"error": err.Error()})
		}
		return c.JSON(http.StatusOK, dto)
	})

but this is because standard library JSON unmarshalling supports this

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

No branches or pull requests

2 participants