Nullable vs. Non-Required Fields in Typespecs #7
Replies: 9 comments 5 replies
-
Hi @feynmanliang, this occurs because the property is not set as I chose to represent this state (a missing key in the API response) as
I think this means a missing |
Beta Was this translation helpful? Give feedback.
-
That makes sense, thanks for the explanation. Could we do something like |
Beta Was this translation helpful? Give feedback.
-
I'm open to using After typing the above, I tested to see if Dialyzer would accept defmodule Test do
@type t :: %{
required(:a) => String.t() | nil,
optional(:b) => String.t()
}
@spec thing :: t
def thing do
%{
a: "Hello",
b: nil
}
end
end Unfortunately, Dialyzer catches this with the following error:
So even if we use |
Beta Was this translation helpful? Give feedback.
-
Got it, thanks. I don't have a good solution in mind, but here's where this issue is coming up. The non-required non-nullable field: https://github.com/feynmanliang/text-generation-inference/blob/d700ad6e9f1920a433e41b3915b93d8e5ea27b2e/docs/openapi.json#L388-L391 The nullable generated typespec: https://github.com/fmops/text_generation_inference.ex/blob/521142be9b0068143ace13cc9412ec5d43cfc39d/lib/text_generation_inference/compat_generate_request.ex#L10 |
Beta Was this translation helpful? Give feedback.
-
Decided to convert this into a discussion so we can revisit the topic periodically. In general, I'm interested if there are better ways to represent both nullable and non-required fields in structs. It's similar to the difference between |
Beta Was this translation helpful? Give feedback.
-
Something I thought of, though it is a bit ugly, is to use a coproduct type eg: @type t :: %__MODULE__{
inputs: String.t(),
options: TextGenerationInference.CompatGenerateOptions.t() | nil,
parameters: TextGenerationInference.GenerateParameters.t() | nil,
stream: boolean
} | %__MODULE__{
inputs: String.t(),
options: TextGenerationInference.CompatGenerateOptions.t() | nil,
parameters: TextGenerationInference.GenerateParameters.t() | nil,
} Not very scalable though; for this |
Beta Was this translation helpful? Give feedback.
-
Ran into this issue again and thought to save us a repro Using https://github.com/fmops/oapi_oai/tree/0.2.1, I expect the following to succeed Dreamcatcher.OpenAIAPI.create_chat_completion(
%OpenAI.CreateChatCompletionRequest{
model: "gpt-3.5-turbo",
messages: [
%OpenAI.ChatCompletionRequestMessage{
role: "system",
content: "tell me a joke"
},
]
},
api_key: System.get_env("OPENAI_API_KEY")
) Instead, I am receiving the following error response body from OpenAI %{"error" => %{"code" => nil, "message" => "None is not of type 'string' - 'messages.0.name'", "param" => nil, "type" => "invalid_request_error"}} Digging deeper, it seems like the root cause is because
The aforementioned OpenAPI spec (https://github.com/openai/openai-openapi/blob/master/openapi.yaml#L2299-L2304) marks the I understand that Elixir structs don't have a good way to distinguish between missing vs null fields, but is there any way we can make this case work without resorting to just using maps and foregoing type-safety? |
Beta Was this translation helpful? Give feedback.
-
Ran into this issue again on https://github.com/fmops/text_generation_inference.ex/blob/main/lib/text_generation_inference/generate_parameters.ex#L9 with huggingface's TGI API responding
https://github.com/huggingface/text-generation-inference/blob/main/docs/openapi.json#L467-L470 suggests this field is non-nullable but a |
Beta Was this translation helpful? Give feedback.
-
What is the best way to handle this in a generic way? Consider the classic example of PATCH-ing a rest resource: how do you handle the case of nil fields in the body request when the schema is rendered as a struct? If you have a nil field it could be interpreted both as a request to set the field to NULL, or to just avoid updating that field. Is there a way to force render that payload with a map or typed map instead of a struct? |
Beta Was this translation helpful? Give feedback.
-
In decoded data from an API,
nil
currently represents bothnull
values and missing keys (non-required fields). Is there a better way to represent these states that would make them more distinguishable?This discussion was converted from issue #3. Original issue text below:
When I mark a field as non-nullable in my OAI spec
I expect both the
__fields__
and the module typespec to reflect it.Instead, it seems that the generated module typespec remains nullable while the fields are non-nullable.
Beta Was this translation helpful? Give feedback.
All reactions