c.IndentedJSON(http.StatusOK, result)
error: json: unsupported value: +Inf
How to fix it
The error message is saying that you're trying to serialize a value of +Infinity to JSON, which is not supported by the encoding/json package in Go.
You can handle this error by checking and replacing the +Inf value before serializing it to JSON.
Here is an example of how you might do it:
for i, val := range result {
if val == math.Inf(1) {
result[i] = math.MaxFloat64
} else if val == math.Inf(-1) {
result[i] = -math.MaxFloat64
}
}
c.IndentedJSON(http.StatusOK, result)
In this example, we're replacing positive infinity with the maximum representable float64 value and negative infinity with the minimum representable float64 value. You might want to adjust this depending on your use case.
If your result
is not a slice, but a struct, you will need to check and replace the +Inf
value in each field of the struct. If the struct is complex, you might want to write a separate function to do this.
Please note that this solution is a workaround. The correct solution would depend on your specific use case. If possible, you should avoid having +Inf
values in your data.
is there a go module for this
There is no specific Go module for handling +Inf
in JSON encoding because it's not often that such a case arises. However, you can handle this issue in your code by creating a custom JSON Marshaller.
Here's an example on how to create a custom JSON Marshaller for a struct:
type MyStruct struct {
Value float64
}
func (m MyStruct) MarshalJSON() ([]byte, error) {
if math.IsInf(m.Value, 1) {
m.Value = math.MaxFloat64
} else if math.IsInf(m.Value, -1) {
m.Value = -math.MaxFloat64
}
type Alias MyStruct
return json.Marshal(&struct {
*Alias
}{
Alias: (*Alias)(&m),
})
}
In this code, we're creating a custom MarshalJSON
method for MyStruct
. Whenever json.Marshal()
is called with a MyStruct
object, this method will be used to convert the object to JSON. We're checking if Value
is +Inf
or -Inf
, and replacing it with the max or min float64 value if it is.
This way, you can handle +Inf
values in your data and prevent them from causing errors when converting the data to JSON.
result is in this struct: type Result struct {
Data interface{} json:"data"
Errors []gqlerrors.FormattedError json:"errors,omitempty"
Extensions map[string]interface{} json:"extensions,omitempty"
}
The structure of the Result
struct makes it a bit complex to handle +Inf
values because the Data
field is of type interface{}
. This means that it can hold any type, and we don't know beforehand which fields to check for +Inf
values.
One way to handle this would be to convert Data
to a map, iterate over it, and replace any +Inf
values. But this would only work if the data is a single level deep. If you have nested fields, you would need to recursively check and replace +Inf
values.
A more robust and general solution would be to use a custom JSON Marshaller that can handle +Inf
values. This would involve replacing the encoding/json
package with a package that supports +Inf
values.
One such package is jsoniter
, which is a drop-in replacement for encoding/json
. It's more flexible and also faster than encoding/json
.
Here's how to use it:
First, install the package:
go get github.com/json-iterator/go
Then, in your code:
import (
"github.com/gin-gonic/gin"
jsoniter "github.com/json-iterator/go"
)
func someFunction(c *gin.Context) {
var json = jsoniter.ConfigCompatibleWithStandardLibrary
// ...
// result is of type `Result`
jsonBytes, err := json.Marshal(result)
if err != nil {
// Handle error
}
c.Data(http.StatusOK, "application/json; charset=utf-8", jsonBytes)
}
In this code, instead of using c.IndentedJSON()
, we're first converting the result
to JSON using jsoniter
, and then sending it as the response.
This way, +Inf
values will be converted to Infinity
in the resulting JSON, which is valid JSON. Note that not all JSON parsers can handle this value, so you should check if this solution works in your case.
This is my current code:
result := graphql.Do(params)
if len(result.Errors) > 0 {
WriteErrorResponse(c, http.StatusInternalServerError, "Failed process graphql query", graphqlbiz.GetError(result))
return
}
c.IndentedJSON(http.StatusOK, result)
Given your current code, you can replace the c.IndentedJSON(http.StatusOK, result)
line with the jsoniter
code I provided earlier. Here is how you can modify your code:
import (
"github.com/gin-gonic/gin"
jsoniter "github.com/json-iterator/go"
)
// ...
func someFunction(c *gin.Context) {
result := graphql.Do(params)
if len(result.Errors) > 0 {
WriteErrorResponse(c, http.StatusInternalServerError, "Failed process graphql query", graphqlbiz.GetError(result))
return
}
var json = jsoniter.ConfigCompatibleWithStandardLibrary
jsonBytes, err := json.Marshal(result)
if err != nil {
// Handle the error the way you want, for example:
WriteErrorResponse(c, http.StatusInternalServerError, "Failed to process JSON", err)
return
}
c.Data(http.StatusOK, "application/json; charset=utf-8", jsonBytes)
}
In this code, instead of using c.IndentedJSON()
, we're first converting the result
to JSON using jsoniter
, and then sending it as the response with c.Data()
. With jsoniter
, +Inf
values will be converted to Infinity
in the resulting JSON, which is a valid JSON value.
I see this line in your code:
// Handle the error the way you want, for example:
what kind of err might happen
The error from the json.Marshal
function can occur if the input to the function cannot be encoded to JSON.
This could happen for several reasons:
NaN
or Infinity
(although jsoniter
should be able to handle Infinity
).In your specific case, where you're encoding a GraphQL result, the most likely cause of an error would be if the GraphQL result includes a value of a type that cannot be encoded to JSON.
However, errors from json.Marshal
are relatively rare, and it's generally safe to assume that if your data can be represented as JSON, the function will not return an error. It's still good practice to handle the error, just in case something unexpected happens.