Subject
For the errors, the api is returning two kinds of results, one has the field error
and for some error_code
, and an api can return both kinds based on parameters so can't really branch there.
Deserialize datamember multiple names (C#)
JSON 1
{
"error_code": "234",
"message": "Api Key is required"
}
JSON 2
{
"code": "NotFound",
"message": "Could not find the resource"
}
Code
[<DataContract>]
type Error = {
[<field: DataMemberAttribute(Name="code",Name="error_code")>]
code: string
[<field: DataMemberAttribute(Name="message")>]
message: string
}
Error
A named argument has been assigned more than one value
Expected Solution
If same Error type can handle both types of JSON output.
Edit based on the given answer.
[<DataContract>]
type Error = {
[<field: DataMemberAttribute(Name="code")>]
code: string
[<field: DataMemberAttribute(Name="error_code")>]
error_code: string
[<field: DataMemberAttribute(Name="message")>]
Message: string
}
with member this.Code : string =
if not (String.IsNullOrEmpty(this.code)) then this.code
else if not (String.IsNullOrEmpty(this.error_code)) then this.error_code
else ""
I don't think this is directly possible with F# record types, but depending on the deserializer behavior, you may be able to something like this:
[<DataContract>]
type Error = {
[<field: DataMemberAttribute(Name="error_code")>]
numericCode: string
[<field: DataMemberAttribute(Name="code")>]
textCode: string
[<field: DataMemberAttribute(Name="message")>]
message: string
}
with member this.code =
if not (String.IsNullOrEmpty(this.numericCode)) then Some this.numericCode
else if not (String.IsNullOrEmpty(this.textCode)) then Some this.textCode
else None
This way you still have to explicitly handle the different cases in your type, but it allows you to just call error.code
from your code and not worry about the two separate fields.
Depending on which deserializer library you use, you may be able to play around with access modifiers to hide the two fields (but that may be impractical with records) or make their types Option<string>
so that the type consumers know they should handle missing values.
This is also what FSharp.Data's JsonProvider does if you specify multiple examples with different fields: it merges them together to create a single type able to represent all the examples, with optional fields for values not present in all the examples. Then it's up to you to write helper functions or type extensions for application specific mapping.