Speakeasy Logo
Skip to Content

Comparison guide: OpenAPI/Swagger C# client generation

Speakeasy produces idiomatic SDKs in various programming languages, including C#. The Speakeasy approach to SDK generation prioritizes a good developer journey to enable API providers to focus on developing a streamlined experience for users.

In this article, we’ll compare creating a C# SDK using Speakeasy to creating one using the open-source OpenAPI Generator. The table below is a summary of the comparison:

Feature/Aspect
Framework Support
Speakeasy
⚠️ Limited to .NET 5+
OpenAPI Generator
✅ Wider range (.NET Framework 4.7, .NET Standard 1.3-2.1, .NET 6+)
.NET Features
Speakeasy
✅ Full async/await support, interfaces for DI
OpenAPI Generator
⚠️ Basic async/await support
Dependencies
Speakeasy
✅ Minimal - Only Newtonsoft.Json and NodaTime
OpenAPI Generator
❌ Multiple dependencies including JsonSubTypes, Newtonsoft.Json, RestSharp, Polly, System.Web
Code Style
Speakeasy
✅ Modern, idiomatic C# with object initializers
OpenAPI Generator
⚠️ Traditional C# with constructors and property setters
HTTP client
Speakeasy
✅ Uses built-in System.Net.Http
OpenAPI Generator
❌ Relies on third-party RestSharp library
Request retry
Speakeasy
✅ Built-in configurable retry support with multiple strategies
OpenAPI Generator
❌ No built-in retry support
Model implementation
Speakeasy
✅ Modern, concise approach using nullable types and attributes
OpenAPI Generator
⚠️ Traditional approach with more verbose implementations
Serialization
Speakeasy
✅ Clean approach using JsonProperty attributes directly
OpenAPI Generator
⚠️ More complex approach using DataContract and DataMember attributes
Documentation
Speakeasy
✅ Comprehensive documentation with detailed examples and error handling
OpenAPI Generator
⚠️ Basic documentation focusing on setup and API routes
Error handling
Speakeasy
⚠️ Generic exceptions with stack traces
OpenAPI Generator
✅ More descriptive custom exceptions
Customization
Speakeasy
✅ Supports hooks and custom configurations
OpenAPI Generator
❌ Limited customization options

You can explore the Speakeasy C# SDK documentation for more information.

For a detailed technical comparison, read on!

Installing the CLIs

We’ll start by installing the Speakeasy CLI and the OpenAPI Generator CLI.

Installing the Speakeasy CLI

You can install the Speakeasy CLI by following the installation instructions here.

After installation, you can check the version to ensure the installation was successful:

If you encounter any errors, take a look at the Speakeasy SDK creation documentation.

Installing the OpenAPI Generator CLI

Install the OpenAPI Generator CLI by running the following command in a terminal:

Downloading the Swagger Petstore specification

We need an OpenAPI specification YAML file to generate SDKs. We’ll use the Swagger Petstore specification, which you can find at https://petstore3.swagger.io/api/v3/openapi.yaml .

In a terminal in your working directory, download the file and save it as petstore.yaml with the following command:

Validating the specification file

Let’s validate the spec using both the Speakeasy CLI and OpenAPI Generator.

Validating the Specification File Using Speakeasy

Validate the spec with Speakeasy using the following command:

The Speakeasy validator returns the following:

The Speakeasy CLI validation result gives us a handy tool for switching between the errors, warnings, and hints tabs with the option to navigate through the results on each tab.

In this instance, Speakeasy generated ten warnings. Let’s correct them before continuing.

Notice that some of the warnings contain a default response. For completeness, we’d like to explicitly return a 200 HTTP response. We’ll make the following modifications in the petstore.yaml file.

When the updatePetWithForm operation executes successfully, we expect an HTTP 200 response with the updated Pet object to be returned.

Insert the following after responses on line 250:

Similarly, following successful createUser and updateUser operations, we’d like to return an HTTP 200 response with a User object.

Add the following text to both operations below responses:

Now we’ll add the same response to four operations. Copy the following text:

Paste this response after responses for the following operations:

  • deletePet
  • deleteOrder
  • logoutUser
  • deleteUser

We are left with three warnings indicating potentially unused or orphaned objects and operations.

For unused objects, locate the following lines of code and delete them:

To remove the unused request bodies, locate the following lines and delete them:

Now if you validate the file with the Speakeasy CLI, you’ll notice there are no warnings:

Validating the specification file using the OpenAPI Generator

OpenAPI Generator requires Java runtime environment (JRE) version 11 or later installed. Confirm whether JRE is installed on your system by executing the following command:

If Java is installed, information about the version should be displayed similar to this:

If you get an error or the JRE version is older than version 11, you need to update or install Java .

Now you can validate the petstore.yaml specification file with OpenAPI Generator by running the following command in the terminal:

The OpenAPI Generator returns the following response, indicating no issues detected.

Now that we have made the petstore.yaml file more complete by fixing the warnings, let’s use it to create SDKs.

Creating SDKs

We’ll create C# SDKs using Speakeasy and OpenAPI Generator and then compare them.

Creating an SDK with Speakeasy

To create a C# SDK from the petstore.yaml specification file using Speakeasy, run the following command in the terminal:

The generator will return some logging results while the SDK is being created and a success indicator should appear upon completion.

Creating an SDK with OpenAPI Generator

Run the following command in the terminal to generate a C# SDK using OpenAPI Generator:

The generator returns various logs and finally a successful generation message.

SDK code compared: Project structure

Let’s compare the two project structures by printing a tree view of each SDK directory.

Run the following command to get the Speakeasy SDK structure:

The results of the project structure are displayed as follows:

The OpenAPI Generator SDK structure can be created with:

The results look like this:

The Speakeasy-created SDK contains more generated files than the SDK from OpenAPI Generator, which is partly due to the Speakeasy SDK being less dependent on third-party libraries.

Model and usage

The Speakeasy SDK follows an object-oriented approach to constructing model objects, leveraging C# support for object initializers. Here’s an example of creating and updating a Pet object:

The model classes are defined as structured and type-safe, using C# classes and properties. Object initializer syntax makes it convenient to instantiate and populate model objects.

The OpenAPI Generator SDK takes a similar approach to constructing model objects. Here’s an example of adding a new Pet object:

Model classes are defined using constructors and property setters. While this approach is more verbose, it follows a more traditional style that may be familiar to developers coming from other backgrounds. Note that modern language features in .NET allow classes to be initialized using object initializers too, as shown in the example above.

In the Speakeasy SDK, the model object is instantiated and populated using an object initializer, providing a more concise and fluent syntax. The OpenAPI Generator SDK, on the other hand, makes use of constructors and individual property setters, making the code more verbose, but also allowing the use of object initializers.

Both SDKs provide mechanisms for handling exceptions and error cases when interacting with the API.

JSON serialization and deserialization

The Speakeasy SDK uses attributes from the Newtonsoft.Json library for the JSON serialization and deserialization of objects.

The JsonProperty attribute is used to map class properties to their corresponding JSON fields. The SpeakeasyMetadata attribute is used to provide additional metadata for form encoding and other purposes.

By contrast, the OpenAPI Generator SDK uses the Newtonsoft.Json.Converters namespace for JSON serialization and deserialization:

The OpenAPI Generator SDK attempts to use default values in the constructor to handle nullable types by forcing default values.

The DataContract and DataMember annotations from the System.Runtime.Serialization namespace specify which properties of a class should be included during serialization and deserialization.

While both SDKs use the Newtonsoft.Json library, the Speakeasy SDK takes a more straightforward approach by directly using the JsonProperty attribute. The OpenAPI Generator SDK relies on DataContract and DataMember for the process.

Model implementation

The Speakeasy SDK uses a more modern approach to defining model classes. Here’s the Pet class implementation:

The Speakeasy SDK model class definitions follow a property-based approach, using properties decorated with JsonProperty attributes for JSON serialization and deserialization, and SpeakeasyMetadata attributes for additional metadata.

Null safety is ensured by the #nullable enable directive, and nullable types like long? and non-null default values like = default! help to prevent unexpected NullReferenceException issues.

By contrast, the OpenAPI Generator SDK’s Pet class has a more traditional implementation:

The OpenAPI Generator SDK uses data contracts and attributes from the System.Runtime.Serialization namespace for serialization and deserialization, and includes additional ToString(), ToJson(), and Validate() methods. The StatusEnum property is implemented as a separate enum, which adds complexity to the model class.

The Speakeasy SDK model implementation is more concise and follows a modern and idiomatic approach to defining C# classes. The OpenAPI Generator SDK model implementation is more verbose and includes traditional features like validation and string representation methods.

HTTP communication

The Speakeasy SDK handles HTTP communication using the System.Net.Http namespace, which is part of the .NET Base Class Library (BCL).

Here’s an example of the AddPetJsonAsync method from the Pet class:

The AddPetJsonAsync method constructs a HttpRequestMessage object with the appropriate method and URL. It then serializes the request body, sets the necessary headers, and applies security and hooks. It sends the request using the SendAsync method, which returns an HttpResponseMessage.

The OpenAPI Generator SDK has a more complicated approach to HTTP communication, defining several custom classes and types to manage the process. Ultimately, it relies on the RestSharp library and RestSharp.Serializers for executing the HTTP requests and handling serialization.

Here’s the AddPetAsync method from the PetApi class:

The AddPetAsync method calls the AddPetWithHttpInfoAsync method, which handles the HTTP communication details. To make the HTTP request and process the response, the SDK uses a custom AsynchronousClient class, which internally uses the third-party RestSharp library for HTTPS communication.

Both SDKs leverage async/await for asynchronous operations, but the Speakeasy SDK takes advantage of the built-in System.Net.Http namespace in .NET, providing a more integrated and efficient approach to HTTP communication. The custom HTTP communication implementation of the OpenAPI Generator SDK depends on a third-party library, which brings additional maintenance and compatibility considerations.

Retries

The Speakeasy SDK provides built-in support for automatically retrying failed requests. You can configure retries globally or on a per-request basis using the x-speakeasy-retries extension in your OpenAPI specification document.

Here’s how the AddPetJsonAsync method handles retries:

If no RetryConfig is provided, the method checks for a global RetryConfig in the SDKConfiguration. If no global RetryConfig is found, a default BackoffStrategy is created with values for initial interval, maximum interval, maximum elapsed time, and exponential backoff factor.

The retrySend function clones the original HttpRequestMessage prior to sending. This prevents it from being consumed by the SendAsync method, enabling subsequent resends.

An instance of the Retries class is created, taking the retrySend function, retryConfig, and status codes as arguments.

The retries.Run() method is then called to handle the entire retry logic and it returns the final HttpResponseMessage.

Various retry strategies, like backoff or fixed interval, are supported and most options are configurable. The x-speakeasy-retries extension can be used in an OpenAPI specification file to configure retries for specific operations or globally.

For more information on configuring retries in your SDK, take a look at the retries documentation.

The OpenAPI Generator SDK does not provide built-in support for automatic retries, and you would need to implement this functionality manually or by using a third-party library.

SDK dependencies

The Speakeasy SDK has the following external dependencies:

  • Newtonsoft.Json: A JSON framework for .NET used for JSON serialization and deserialization.
  • Noda Time: A date and time API for .NET, providing a better implementation than the built-in System.DateTime components.

The OpenAPI Generator SDK has the following external dependencies:

  • JsonSubTypes: A library used for handling JSON polymorphism, useful for dealing with inheritance hierarchies in JSON data.
  • Newtonsoft.Json: a JSON framework for .NET, which is used for JSON serialization and deserialization in the SDK.
  • RestSharp: A library for consuming RESTful web services in .NET, used for making HTTP requests and handling responses.
  • Polly: A .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe way.

The OpenAPI Generator SDK project file includes a reference to the System.Web assembly, which is part of the .NET Framework and provides classes for building web applications.

While both SDKs use the Newtonsoft.Json library for JSON handling, the Speakeasy SDK has a more minimalistic approach to dependencies and only includes the NodaTime library for date and time handling. The OpenAPI Generator SDK includes additional dependencies like RestSharp for HTTP communication, JsonSubTypes for JSON polymorphism, and Polly for resilience and fault handling.

The more dependencies an SDK has, the more prone it is to compatibility issues with new releases and internal complexity, making maintenance and enhancement more difficult.

Handling non-nullable fields

Let’s compare how the two SDKs handle non-nullable fields using the provided code snippets for the Status field and enum.

In the Speakeasy SDK the Status field is defined as follows:

The Status property is of type Models.Components.Status?, which is a nullable enum type. The ? after the type name indicates that the property can be assigned a null value.

The Status enum is defined as follows:

The enum members are decorated with the JsonProperty attribute, which specifies the JSON property name for each member.

In the OpenAPI Generator SDK, the Status field is defined as follows:

The Status property is of type StatusEnum?, which is a nullable enum type.

The StatusEnum is defined as follows:

The StatusEnum is decorated with the JsonConverter attribute, which specifies that the StringEnumConverter should be used for JSON serialization and deserialization. The enum members are decorated with the EnumMember attribute, which specifies the JSON value for each member.

Both SDKs handle non-nullable fields similarly by using nullable types (Status? and StatusEnum?), allowing the SDK to accommodate scenarios where the API response may not include a value for the Status field.

The SDKs differ in how the enums are defined and decorated with attributes for JSON serialization and deserialization:

  • The Speakeasy SDK uses the JsonProperty attribute directly on the enum members to specify the JSON property name.
  • The OpenAPI Generator SDK uses the JsonConverter and EnumMember attributes to handle JSON serialization and deserialization for the enum.

The same goal is achieved in both cases, but the Speakeasy approach is more straightforward, as it directly maps the enum members to the corresponding JSON property names.

Let’s look at how the two SDKs handle this when passing a null value to the FindPetsByStatus method.

When you run the following code from the Speakeasy SDK:

The Speakeasy SDK throws an exception with the following output:

The Speakeasy SDK throws an SDKException with the message “API error occurred” when encountering an error during the API call. It also includes the stack trace, which can be helpful for debugging purposes.

When you run the following code from the OpenAPI Generator SDK:

The OpenAPI Generator SDK throws an ApiException with the following output:

The OpenAPI Generator SDK throws an ApiException with a more descriptive error message, but it does not include the stack trace by default.

Both SDKs handle the null value scenario by throwing an exception, which is a reasonable approach to prevent invalid data from being passed to the API.

The Speakeasy SDK throws a more generic “API error occurred” exception but provides the stack trace, which can be helpful for debugging. The OpenAPI Generator SDK throws a more descriptive ApiException with a customized error message, but it does not include the stack trace by default.

Let’s see what happens when we pass an empty name field to the SDKs.

If we remove the name field from the class initialization or even set it to null, the Speakeasy SDK doesn’t throw an error and creates a pet object with empty or null values provided.

To show the details of the pet object created, let’s add a method to the Pet model class in sdks\OpenApi\Models\Components\Pet.cs:

Now if you run the following code:

You get the following result, showing that the pet object was created without a value for the Name field:

Let’s do the same with the OpenAPI Generator SDK:

The OpenAPI Generator SDK throws an ArgumentNullException error with a more descriptive error message:

It appears that the error is thrown from the model class directly, so we cannot continue with bad data.

In this case, the OpenAPI Generator SDK handled the null or empty values better than the Speakeasy SDK when creating a Pet. The Speakeasy SDK allows you to create the pet with empty name values, a small issue that can be handled in development, but worth taking note of.

Generated documentation

Both Speakeasy and OpenAPI Generator create SDK documentation for generated code.

The OpenAPI Generator README outlines the SDK dependencies and supported frameworks, provides steps for getting started (including installing dependencies and building the project in various operating systems), and describes available API routes. The Speakeasy README also provides API routes and includes more detailed getting-started examples.

OpenAPI Generator generates some documentation in a docs directory, but it is not very detailed.

Additional documentation generated by Speakeasy includes more detailed explanations of the models and operations; examples of creating, updating, and searching objects; error handling; and guidance on handling exceptions specific to the OpenAPI specification file.

Some default test cases are created for both but are only for guidance.

Supported .NET versions

The Speakeasy-generated SDK supports .NET 5.+ environments. We successfully tested it with .NET 6.

The SDK generated by OpenAPI Generator claims to support a range of versions, including .NET Framework 4.7, .NET Standard 1.3-2.1, and .NET 6 and later. We targeted .NET 6 to ensure we have the same language features available in both SDKs.

Although more versions are supported in the OpenAPI Generator, .NET 5+ is the modern stack and will be used more in new developments.

Summary

Compared to the SDK generated by OpenAPI Generator, the Speakeasy-generated SDK is lightweight, concise, and idiomatic, with a modern approach to model implementation and built-in retry support. The Speakeasy generator uses modern techniques that follow best practices, and the Speakeasy documentation makes it easy to get started.

If you are building an API that developers rely on and would like to publish full-featured SDKs that follow best practices, give the Speakeasy SDK generator a try.

Join our Slack community  to let us know how we can improve our C# SDK generator or suggest features.

Last updated on