Kiota AnyOf Int/String Validation Failure: A Deep Dive
Hey guys,
Let's dive into an interesting issue encountered while using Kiota to generate a TypeScript SDK. Specifically, it revolves around the anyOf
schema construct when dealing with integer and string types. This article will walk you through the problem, the expected behavior, how to reproduce it, and some potential workarounds. So, buckle up and let's get started!
Understanding the Issue
The core problem lies in how Kiota handles the anyOf
keyword in OpenAPI schemas, especially when it involves a mix of integer and string types. In the reported scenario, the ssh_key_identifier
parameter is defined as either an integer (representing an SSH key ID) or a string (representing an SSH key fingerprint). However, Kiota seems to be defaulting to generating only the integer type, which prevents developers from accessing queries that require the string (fingerprint) format.
The OpenAPI Schema Snippet
To better illustrate the problem, let's take a look at the relevant snippet from the OpenAPI schema:
ssh_key_identifier:
in: path
name: ssh_key_identifier
required: true
description: Either the ID or the fingerprint of an existing SSH key.
schema:
anyOf:
- $ref: '#/components/schemas/ssh_key_id' # This is a number
- $ref: '#/components/schemas/ssh_key_fingerprint' # This is a string
example: 123456
ssh_key_id:
type: integer
description: >-
A unique identification number for this key. Can be used to embed a
specific SSH key into a Droplet.
readOnly: true
example: 512189
ssh_key_fingerprint:
type: string
description: >-
A unique identifier that differentiates this key from other keys using
a format that SSH recognizes. The fingerprint is created when the key is
added to your account.
readOnly: true
example: 3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa
As you can see, the ssh_key_identifier
can be either an ssh_key_id
(integer) or an ssh_key_fingerprint
(string). The expectation is that Kiota should generate a TypeScript type that reflects this anyOf
condition, allowing both types to be used.
The Bug Manifestation
Instead of generating a function signature like this:
ssh_key_identifier(body: number | string)
Kiota is generating:
ssh_key_identifier(body: number)
This means that developers are unable to utilize the string (fingerprint) queries, effectively limiting the functionality of the generated SDK.
Expected Behavior
The ideal behavior here is for Kiota to correctly interpret the anyOf
schema and generate a TypeScript type that supports both the integer and string types. This would typically involve creating a union type (number | string
) in the generated code. By doing so, developers can seamlessly use either the SSH key ID or the fingerprint when making API calls, providing the flexibility intended by the OpenAPI schema.
Why is This Important?
Supporting anyOf
with mixed types is crucial for several reasons:
- Flexibility: It allows APIs to accept different types of identifiers or parameters, making them more versatile.
- Adherence to OpenAPI Standards: The
anyOf
keyword is a standard part of the OpenAPI specification, and tools like Kiota should handle it correctly. - Developer Experience: Generating accurate types improves the developer experience by reducing the need for manual type coercion or workarounds.
How to Reproduce the Issue
Reproducing this issue is straightforward. All you need is an OpenAPI schema that uses anyOf
to define a parameter as either an integer or a string. Here’s a step-by-step guide:
- Create an OpenAPI Schema: Use the YAML snippet provided earlier, or create a similar schema that defines a parameter with
anyOf
including integer and string types. - Generate the SDK with Kiota: Use the Kiota CLI to generate a TypeScript SDK from the schema. For example:
kiota generate --openapi <your-schema>.yaml --language TypeScript --output <output-directory>
- Inspect the Generated Code: Look at the generated function signature for the parameter defined with
anyOf
. You’ll likely find that it only includes the integer type, and not the union type (number | string
).
By following these steps, you can easily reproduce the issue and confirm that Kiota is not correctly handling the anyOf
construct in this scenario.
Known Workarounds and Potential Solutions
As of the current version (1.27.0) of Kiota, there isn’t a straightforward workaround for this issue. However, here are a few potential approaches and considerations:
1. Manual Type Assertion
One temporary workaround is to use manual type assertions in your code. This involves casting the value to the correct type when calling the generated function. For example:
const identifier: number | string =