'How to parse images from FormData typescript frontend to golang backend using gorilla websocket?
Summary
Typescript Frontend:
I defined a ´formData´ constant which is appending a collection of images on submit. Code fragment is shown below:
onSubmit={async ({ title, price, category, state, description, availability, brand, labels, sku, images }) => {
console.log("Submitting")
const formData = new FormData();
Object.values(images).map((val:any) => {
formData.append("myImage", val, val.name);
})
const d = { title, price, category, state, description, availability, brand, labels, sku, formData };
const resp = await conn.mutation.createMarketplacePublication(d);
}}
createMarketplacePublication: (data: {
title: string;
price: number;
category: string;
state: string;
description: string;
availability: string;
brand: string;
labels: string;
sku: string;
formData: FormData; //Also tried with Object and Blob types
}): Promise<{ error: string } | { room: Room }> =>
connection.fetch("create_marketplace_publication", data)
Golang Backend:
For testing purposes, I'm just trying to print the ´formData´ variable to check how it is structured, but it shows an empty map formData:map[] which according to docs is just an empty slice.
Relevant code fragment flow are shown below (gorilla websocket package is being used)
Client:
package websocket
import (
"fmt"
"runtime/debug"
"github.com/gorilla/websocket"
)
...
type Client struct {
Addr string
Socket *websocket.Conn
Send chan []byte
AppId uint32
UserId string
FirstTime uint64
HeartbeatTime uint64
LoginTime uint64
}
func NewClient(addr string, socket *websocket.Conn, firstTime uint64) (client *Client) {
client = &Client{
Addr: addr,
Socket: socket,
Send: make(chan []byte, 100),
FirstTime: firstTime,
HeartbeatTime: firstTime,
}
return
}
...
func (c *Client) Read() {
defer func() {
if r := recover(); r != nil {
fmt.Println("write stop", string(debug.Stack()), r)
}
}()
defer func() {
fmt.Println("send", c)
close(c.Send)
}()
for {
_, message, err := c.Socket.ReadMessage()
if err != nil {
fmt.Println("message error", c.Addr, err)
return
}
ProcessData2(c, message)
}
}
func (c *Client) Write() {
defer func() {
if r := recover(); r != nil {
fmt.Println("write stop", string(debug.Stack()), r)
}
}()
for {
select {
case message, ok := <-c.Send:
if !ok {
fmt.Println("Client", c.Addr, "ok", ok)
return
}
c.Socket.WriteMessage(websocket.TextMessage, message)
}
}
}
func (c *Client) SendMsg(msg []byte) {
if c == nil {
return
}
defer func() {
if r := recover(); r != nil {
fmt.Println("SendMsg stop:", r, string(debug.Stack()))
}
}()
c.Send <- msg
}
func (c *Client) close() {
close(c.Send)
}
...
Process:
package websocket
import (
"encoding/json"
"fmt"
"log"
"sync"
"../common"
"../models"
)
type DisposeFunc func(client *Client, seq string, icmd string, message []byte) (code uint32, msg string, ocmd string, data interface{}, voice bool)
var (
handlers = make(map[string]DisposeFunc)
handlersRWMutex sync.RWMutex
)
// 注册
func Register(key string, value DisposeFunc) {
handlersRWMutex.Lock()
defer handlersRWMutex.Unlock()
handlers[key] = value
return
}
func getHandlers(key string) (value DisposeFunc, ok bool) {
handlersRWMutex.RLock()
defer handlersRWMutex.RUnlock()
value, ok = handlers[key]
return
}
func ProcessData(client *Client, message []byte) {
defer func() {
if r := recover(); r != nil {
fmt.Println("Procesamiento de datos stop ->", r)
}
}()
request := &models.Request{}
if string(message) == "ping" {
_ = client.Socket.WriteJSON("pong")
log.Printf("Message sent: %s", "pong")
return
}
err := json.Unmarshal(message, request)
if err != nil {
fmt.Println("Error en Procesamiento de datos json Unmarshal(message, request)", err)
client.SendMsg([]byte("数据不合法"))
return
}
requestData, err := json.Marshal(request.Data)
if err != nil {
fmt.Println("Error en Procesamiento de datos json Marshal(request.Data)", err)
client.SendMsg([]byte("No se pudieron procesar los datos"))
return
}
seq := request.Seq
cmd := request.Cmd
// ref := request.Ref
fetchId := request.FetchId
var (
code uint32
msg string
data interface{}
voice bool
)
if value, ok := getHandlers(cmd); ok {
code, msg, cmd, data, voice = value(client, seq, cmd, requestData)
} else {
code = common.RoutingNotExist
fmt.Println("El enrutamiento de datos de procesamiento no existe", client.Addr, "cmd", cmd)
}
msg = common.GetErrorMessage(code, msg)
responseHead := models.NewResponseHead(seq, cmd, fetchId, code, msg, data)
headByte, err := json.Marshal(responseHead)
if err != nil {
fmt.Println("error json Marshal", err)
return
}
client.SendMsg(headByte)
if voice == true {
msg = common.GetErrorMessage(code, msg)
responseHead := models.NewResponseHead(seq, cmd, fetchId, code, msg, data)
headByte, err := json.Marshal(responseHead)
if err != nil {
fmt.Println("error json Marshal", err)
return
}
client.SendMsg(headByte)
}
return
}
Routes:
package routers
import (
"../websocket"
)
// Websocket
func WebsocketInit() {
...
websocket.Register("create_marketplace_publication", websocket.CreateMarketplacePublicationController)
}
Controller:
package websocket
import (
"encoding/json"
"fmt"
"path/filepath"
"time"
"../../database"
"../common"
"../models"
"../repository/crud"
"../utils/console"
)
...
go
func CreateMarketplacePublicationController(client *Client, seq string, icmd string, message []byte) (code uint32, msg string, cmd string, data interface{}, voice bool) {
request := map[string]interface{}{
"title": "",
"price": "",
"category": "",
"state": "",
"description": "",
"availability": "",
"brand": "",
"labels": "",
"sku": "",
"formData": "",
}
if err := json.Unmarshal(message, &request); err != nil {
code = common.ParameterIllegal
return
}
form := request["formData"]
//p, err := ioutil.ReadFile(form)
//if err != nil {
// fmt.Println("Error on reading file", err)
//}
fmt.Println("post publication content: ", request["formData"])
...
}
Issue:
I can't use ioutil package due to the Type assertion issue: cannot use form (type interface {}) as type string in argument to ioutil.ReadFile: need type assertion.
I already checked similar questions and answers from this forum and other website regarding passing file data to server and handling multipart data in golang but couldn't find any solution.
Tried this:
fmt.Println("check request: ", request["formData"])
md, _ := request["formData"].(map[string]interface{})
fmt.Println(md)
if md == nil {
fmt.Println("empty")
}
fmt.Println(len(md))
Got this:
check request: map[]
map[]
0
If I change the FormData type to either Object or Blob, I get this:
check request: map[blob:http://localhost:3000/33afc417-6577-43d9-ac35-6f5ac626c7ea:map[]]
1
What should I do in this particular case?
Similar cases use the httprequest.MultiformData function not websockets.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
