How to serialize and deserialize errors string in go

huangapple go评论77阅读模式
英文:

How to serialize and deserialize errors string in go

问题

在两个Go服务共享相同类型的情况下,一个客户端向服务器发送一个JSON:

type Message struct {
   Error string `json:"error"`
}

客户端应该将一个error序列化为一个字符串。

服务器应该将该字符串反序列化为一个error,以便我可以使用errors.Aserrors.Is来检查包装错误等。

我如何序列化嵌套错误?

英文:

In the context of two go services sharing the same types, one client post a json to a server:

type Message struct {
   Error string `json:"error"`
}

The client should serialize an error into a string.

The server should deserialize that string into an error on which I can use errors.As or errors.Is to check for wrapped errors and such.

How may I serialize nested errors ?

答案1

得分: 1

让我与你分享一些思考,也许可以指导你朝正确的方向前进。

errors.Iserrors.As

这两个操作符用于处理 error 类型。它们通常用于处理函数返回的 error,并根据错误类型采取相应的操作。如果你的函数只返回一个字符串,那么几乎不可能使用 errors.Iserrors.As,除非你进行额外的逻辑处理字符串。

一个简单的解决方法

如果你想保留错误的层次结构而不必将其展平,可以采用以下方法:

package main

import (
	"encoding/json"
	"fmt"
)

type RecursiveErr struct {
	Message string `json:"Message"`
	Err     error  `json:"error"`
}

func (r RecursiveErr) Error() string {
	return r.Message
}

func main() {
	// 递归 - 编组
	childErr := RecursiveErr{Message: "leaf-child error"}
	parentErr := RecursiveErr{Message: "root error", Err: &childErr}
	data, _ := json.MarshalIndent(&parentErr, "", "\t")
	fmt.Println(string(data))

	// 递归 - 解组
	var parsedParentErr RecursiveErr
	json.Unmarshal(data, &parsedParentErr)
	fmt.Println(parsedParentErr.Message)
}

这个解决方案有以下好处:

  1. 你可以保留错误的层次结构(父子关系)。
  2. 你可以在 Err 字段上调用 errors.Iserrors.As

由于这对我来说是一个不常见的场景,希望我的回答没有偏离你的问题,如果有其他需要,请告诉我!

英文:

Let me share with you some thoughts that maybe can guide you in the right direction.

errors.Is and errors.As

These two operators deal with the error type. The common scenario they are used when you've to deal with an error returned by a function and, based on which type of error it is, take some actions. If you're returning just a string from a function, it's almost impossible to invoke errors.Is and errors.As unless you do some extra logic to handle the string.

A simple workaround

If you wanna preserve a hierarchical structure for your errors without having to flatten them, you could follow this approach:

package main

import (
	"encoding/json"
	"fmt"
)

type RecursiveErr struct {
	Message string `json:"Message"`
	Err     error  `json:"error"`
}

func (r RecursiveErr) Error() string {
	return r.Message
}

func main() {
	// recursive - marshal
	childErr := RecursiveErr{Message: "leaf-child error"}
	parentErr := RecursiveErr{Message: "root error", Err: &childErr}
	data, _ := json.MarshalIndent(&parentErr, "", "\t")
	fmt.Println(string(data))

	// recursive - unmarshal
	var parsedParentErr RecursiveErr
	json.Unmarshal(data, &parsedParentErr)
	fmt.Println(parsedParentErr.Message)
}

This solution has the following benefits:

  1. You can preserve the hierarchical structure of your errors (parent-child relationship)
  2. You can invoke the errors.Is and errors.As on the Err field.

As it's an uncommon scenario for me, I hope to not be off-topic with your request, let me know!

huangapple
  • 本文由 发表于 2023年1月20日 17:53:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75182353.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定