Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Refit Client API Generator for OpenAPI

License

NotificationsYou must be signed in to change notification settings

Respawnsive/refitter

 
 

Repository files navigation

BuildSmoke TestsNuGetQuality Gate Statuscodecov

All Contributors

Refitter

Refitter is a tool for generating a C# REST API Client using theRefit library. Refitter can generate the Refit interface and contracts from OpenAPI specifications. Refitter could format the generated Refit interface to be managed byApizr (v6+) and generate some registration helpers too.

Refitter comes in 2 forms:

CLI Tool

Installation:

The tool is packaged as a .NET Tool and is published to nuget.org. You can install the latest version of this tool like this:

dotnet tool install --global Refitter

Usage:

$ refitter --help
USAGE:    refitter [URL or input file] [OPTIONS]EXAMPLES:    refitter ./openapi.json    refitter https://petstore3.swagger.io/api/v3/openapi.yaml    refitter ./openapi.json --settings-file ./openapi.refitter --output ./GeneratedCode.cs    refitter ./openapi.json --namespace "Your.Namespace.Of.Choice.GeneratedCode" --output ./GeneratedCode.cs    refitter ./openapi.json --namespace "Your.Namespace.Of.Choice.GeneratedCode" --internal    refitter ./openapi.json --output ./IGeneratedCode.cs --interface-only    refitter ./openapi.json --output ./GeneratedContracts.cs --contract-only    refitter ./openapi.json --use-api-response    refitter ./openapi.json --cancellation-tokens    refitter ./openapi.json --no-operation-headers    refitter ./openapi.json --no-accept-headers    refitter ./openapi.json --use-iso-date-format    refitter ./openapi.json --additional-namespace "Your.Additional.Namespace" --additional-namespace "Your.Other.Additional.Namespace"    refitter ./openapi.json --multiple-interfaces ByEndpoint    refitter ./openapi.json --tag Pet --tag Store --tag User    refitter ./openapi.json --match-path '^/pet/.*'    refitter ./openapi.json --trim-unused-schema    refitter ./openapi.json --trim-unused-schema  --keep-schema '^Model$' --keep-schema '^Person.+'    refitter ./openapi.json --no-deprecated-operations    refitter ./openapi.json --operation-name-template '{operationName}Async'    refitter ./openapi.json --optional-nullable-parameters    refitter ./openapi.json --use-polymorphic-serializationARGUMENTS:    [URL or input file]    URL or file path to OpenAPI Specification fileOPTIONS:                                                DEFAULT                                                                                                                                                        -h, --help                                                   Prints help information                                                                                                                       -v, --version                                                Prints version information                                                                                                                    -s, --settings-file                                          Path to .refitter settings file. Specifying this will ignore all other settings (except for --output)                                         -n, --namespace                             GeneratedCode    Default namespace to use for generated types                                                                                                      --contracts-namespace                                    Default namespace to use for generated contracts                                                                                              -o, --output                                Output.cs        Path to Output file or folder (if multiple files are generated)                                                                                   --contracts-output                                       Output path for generated contracts. Enabling this automatically enables generating multiple files                                                --no-auto-generated-header                               Don't add <auto-generated> header to output file                                                                                                  --no-accept-headers                                      Don't add <Accept> header to output file                                                                                                          --interface-only                                         Don't generate contract types                                                                                                                     --contract-only                                          Don't generate clients                                                                                                                            --use-api-response                                       Return Task<IApiResponse<T>> instead of Task<T>                                                                                                   --use-observable-response                                Return IObservable instead of Task                                                                                                                --internal                                               Set the accessibility of the generated types to 'internal'                                                                                        --cancellation-tokens                                    Use cancellation tokens                                                                                                                           --no-operation-headers                                   Don't generate operation headers                                                                                                                  --no-logging                                             Don't log errors or collect telemetry                                                                                                             --additional-namespace                                   Add additional namespace to generated types                                                                                                       --exclude-namespace                                      Exclude namespace on generated types                                                                                                              --use-iso-date-format                                    Explicitly format date query string parameters in ISO 8601 standard date format using delimiters (2023-06-15)                                     --multiple-interfaces                                    Generate a Refit interface for each endpoint. May be one of ByEndpoint, ByTag                                                                     --multiple-files                                         Generate multiple files instead of a single large file.                                                                                                                                                    The output files can be the following:                                                                                                                                                                     - RefitInterfaces.cs                                                                                                                                                                                       - DependencyInjection.cs                                                                                                                                                                                   - Contracts.cs                                                                                                                                    --match-path                                             Only include Paths that match the provided regular expression. May be set multiple times                                                          --tag                                                    Only include Endpoints that contain this tag. May be set multiple times and result in OR'ed evaluation                                            --skip-validation                                        Skip validation of the OpenAPI specification                                                                                                      --no-deprecated-operations                               Don't generate deprecated operations                                                                                                              --operation-name-template                                Generate operation names using pattern. When using --multiple-interfaces ByEndpoint, this is name of the Execute() method in the interface        --optional-nullable-parameters                           Generate nullable parameters as optional parameters                                                                                               --trim-unused-schema                                     Removes unreferenced components schema to keep the generated output to a minimum                                                                  --keep-schema                                            Force to keep matching schema, uses regular expressions. Use together with "--trim-unused-schema". Can be set multiple times                      --no-banner                                              Don't show donation banner                                                                                                                        --skip-default-additional-properties                     Set to true to skip default additional properties                                                                                                 --operation-name-generator              Default          The NSwag IOperationNameGenerator implementation to use.                                                                                                                                                   May be one of:                                                                                                                                                                                             - Default                                                                                                                                                                                                  - MultipleClientsFromOperationId                                                                                                                                                                           - MultipleClientsFromPathSegments                                                                                                                                                                          - MultipleClientsFromFirstTagAndOperationId                                                                                                                                                                - MultipleClientsFromFirstTagAndOperationName                                                                                                                                                              - MultipleClientsFromFirstTagAndPathSegments                                                                                                                                                               - SingleClientFromOperationId                                                                                                                                                                              - SingleClientFromPathSegments                                                                                                                                                                             See https://refitter.github.io/api/Refitter.Core.OperationNameGeneratorTypes.html for more information                                            --immutable-records                                      Generate contracts as immutable records instead of classes                                                                                        --use-apizr                                              Use Apizr by:                                                                                                                                                                                              - Adding a final IApizrRequestOptions options parameter to all generated methods                                                                                                                           - Providing cancellation tokens by Apizr request options instead of a dedicated parameter                                                                                                                  - Using method overloads instead of optional parameters                                                                                                                                                    See https://refitter.github.io for more information and https://www.apizr.net to get started with Apizr                                           --use-dynamic-querystring-parameters                     Enable wrapping multiple query parameters into a single complex one. Default is no wrapping.                                                                                                               See https://github.com/reactiveui/refit?tab=readme-ov-file#dynamic-querystring-parameters for more information                                    --use-polymorphic-serialization                          Use System.Text.Json polymorphic serialization

To generate code from an OpenAPI specifications file, run the following:

$ refitter [path to OpenAPI spec file] --namespace"[Your.Namespace.Of.Choice.GeneratedCode]"

This will generate a file calledOutput.cs which contains the Refit interface and contract classes generated usingNSwag

Source Generator

Refitter is available as a C# Source Generator that uses theRefitter.Core library for generating a REST API Client using theRefit library. Refitter can generate the Refit interface from OpenAPI specifications. Refitter could format the generated Refit interface to be managed byApizr and generate some registration helpers too.

The Refitter source generator is a bit untraditional in a sense that it creates a folder calledGenerated in the same location as the.refitter file and generates files to disk under theGenerated folder (can be changed with--outputFolder). The source generator output should be included in the project and committed to source control. This is done because there is no other way to trigger the Refit source generator to pickup the Refitter generated code

(Translation: I couldn't for the life of me figure how to get that to work, sorry)

Installation

The source generator is distributed as a NuGet package and should be installed to the project that will contain the generated code

dotnet add package Refitter.SourceGenerator

Usage

This source generator generates code based on any.refitter file included to the project asAdditionalFiles.

The generator can automatically detect all.refitter files inside the project that referenced theRefitter.SourceGenerator package and there is no need to include them manually asAdditionalFiles

.Refitter File format

The following is an example.refitter file

{"openApiPath":"/path/to/your/openAPI",// Required"namespace":"Org.System.Service.Api.GeneratedCode",// Optional. Default=GeneratedCode"contractsNamespace":"Org.System.Service.Api.GeneratedCode.Contracts",// Optional. Default=GeneratedCode"naming":{"useOpenApiTitle":false,// Optional. Default=true"interfaceName":"MyApiClient"// Optional. Default=ApiClient},"generateContracts":true,// Optional. Default=true"generateClients":true,// Optional. Default=true"generateXmlDocCodeComments":true,// Optional. Default=true"generateStatusCodeComments":true,// Optional. Default=true"addAutoGeneratedHeader":true,// Optional. Default=true"addAcceptHeaders":true,// Optional. Default=true"returnIApiResponse":false,// Optional. Default=false"responseTypeOverride":{// Optional. Default={}"File_Upload":"IApiResponse","File_Download":"System.Net.Http.HttpContent"},"generateOperationHeaders":true,// Optional. Default=true"typeAccessibility":"Public",// Optional. Values=Public|Internal. Default=Public"useCancellationTokens":false,// Optional. Default=false"useIsoDateFormat":false,// Optional. Default=false"multipleInterfaces":"ByEndpoint",// Optional. May be one of "ByEndpoint" or "ByTag""generateDeprecatedOperations":false,// Optional. Default=true"operationNameTemplate":"{operationName}Async",// Optional. Must contain {operationName} when multipleInterfaces != ByEndpoint"optionalParameters":false,// Optional. Default=false"outputFolder":"../CustomOutput"// Optional. Default=./Generated"outputFilename":"RefitInterface.cs",// Optional. Default=Output.cs for CLI tool"contractsOutputFolder":"../Contracts",// Optional. Default=NULL"generateMultipleFiles":false,// Optional. Default=false"additionalNamespaces":[// Optional"Namespace1","Namespace2"],"includeTags":[// Optional. OpenAPI Tag to include when generating code"Pet","Store","User"],"includePathMatches":[// Optional. Only include Paths that match the provided regular expression"^/pet/.*","^/store/.*"],"trimUnusedSchema":false,// Optional. Default=false"keepSchemaPatterns":[// Optional. Force to keep matching schema, uses regular expressions. Use together with trimUnusedSchema=true"^Model$","^Person.+"],"generateDefaultAdditionalProperties":true,// Optional. default=true"operationNameGenerator":"Default",// Optional. May be one of Default, MultipleClientsFromOperationId, MultipleClientsFromPathSegments, MultipleClientsFromFirstTagAndOperationId, MultipleClientsFromFirstTagAndOperationName, MultipleClientsFromFirstTagAndPathSegments, SingleClientFromOperationId, SingleClientFromPathSegments"immutableRecords":false,"useDynamicQuerystringParameters":true,// Optional. Default=false"usePolymorphicSerialization", false,// Optional. Default=false"dependencyInjectionSettings":{// Optional"baseUrl":"https://petstore3.swagger.io/api/v3",// Optional. Leave this blank to set the base address manually"httpMessageHandlers":[// Optional"AuthorizationMessageHandler","TelemetryMessageHandler"],"usePolly":true,// DEPRECATED - Use "transientErrorHandler": "None|Polly|HttpResilience" instead"transientErrorHandler":"HttpResilience",// Optional. Set this to configure transient error handling with a retry policy that uses a jittered backoff. May be one of None, Polly, HttpResilience"maxRetryCount":3,// Optional. Default=6"firstBackoffRetryInSeconds":0.5// Optional. Default=1.0},"apizrSettings":{// Optional"withRequestOptions":true,// Optional. Default=true"withRegistrationHelper":true,// Optional. Default=false"withCacheProvider":"InMemory",// Optional. Values=None|Akavache|MonkeyCache|InMemory|DistributedAsString|DistributedAsByteArray. Default=None"withPriority":true,// Optional. Default=false"withMediation":true,// Optional. Default=false"withOptionalMediation":true,// Optional. Default=false"withMappingProvider":"AutoMapper",// Optional. Values=None|AutoMapper|Mapster. Default=None"withFileTransfer":true// Optional. Default=false},"codeGeneratorSettings":{// Optional. Default settings are the values set in this example"requiredPropertiesMustBeDefined":true,"generateDataAnnotations":true,"anyType":"object","dateType":"System.DateTimeOffset","dateTimeType":"System.DateTimeOffset","timeType":"System.TimeSpan","timeSpanType":"System.TimeSpan","arrayType":"System.Collections.Generic.ICollection","dictionaryType":"System.Collections.Generic.IDictionary","arrayInstanceType":"System.Collections.ObjectModel.Collection","dictionaryInstanceType":"System.Collections.Generic.Dictionary","arrayBaseType":"System.Collections.ObjectModel.Collection","dictionaryBaseType":"System.Collections.Generic.Dictionary","propertySetterAccessModifier":"","generateImmutableArrayProperties":false,"generateImmutableDictionaryProperties":false,"handleReferences":false,"jsonSerializerSettingsTransformationMethod":null,"generateJsonMethods":false,"enforceFlagEnums":false,"inlineNamedDictionaries":false,"inlineNamedTuples":true,"inlineNamedArrays":false,"generateOptionalPropertiesAsNullable":false,"generateNullableReferenceTypes":false,"generateNativeRecords":false,"generateDefaultValues":true,"inlineNamedAny":false,"excludedTypeNames":["ExcludedTypeFoo","ExcludedTypeBar"]}}
  • openApiPath - points to the OpenAPI Specifications file. This can be the path to a file stored on disk, relative to the.refitter file. This can also be a URL to a remote file that will be downloaded over HTTP/HTTPS
  • namespace - the namespace used in the generated code. If not specified, this defaults toGeneratedCode
  • naming.useOpenApiTitle - a boolean indicating whether the OpenApi title should be used. Default istrue
  • naming.interfaceName - the name of the generated interface. The generated code will automatically prefix this withI so if this set toMyApiClient then the generated interface is calledIMyApiClient. Default isApiClient
  • generateContracts - a boolean indicating whether contracts should be generated. A use case for this is several API clients use the same contracts. Default istrue
  • generateClients: - a boolean indicating whether clients should be generated. A use case for this is to seperate clients and contracts in two generation
  • generateXmlDocCodeComments - a boolean indicating whether XML doc comments should be generated. Default istrue
  • generateStatusCodeComments - a boolean indicating whether the XML docs forApiException andIApiResponse contain detailed descriptions for every documented status code. Default istrue
  • addAutoGeneratedHeader - a boolean indicating whether XML doc comments should be generated. Default istrue
  • addAcceptHeaders - a boolean indicating whether to add accept headers [Headers("Accept: application/json")]. Default istrue
  • returnIApiResponse - a boolean indicating whether to returnIApiResponse<T> objects. Default isfalse
  • responseTypeOverride - a dictionary with operation ids (as specified in the OpenAPI document) and a particular return type to use. The types are wrapped in a task, but otherwise unmodified (so make sure to specify or import their namespaces). Default is{}
  • generateOperationHeaders - a boolean indicating whether to use operation headers in the generated methods. Default istrue
  • typeAccessibility - the generated type accessibility. Possible values arePublic andInternal. Default isPublic
  • useCancellationTokens - Use cancellation tokens in the generated methods. Default isfalse
  • useIsoDateFormat - Set totrue to explicitly format date query string parameters in ISO 8601 standard date format using delimiters (for example: 2023-06-15). Default isfalse
  • multipleInterfaces - Set toByEndpoint to generate an interface for each endpoint, orByTag to group Endpoints by their Tag (like SwaggerUI groups them).
  • outputFolder - a string describing a relative path to a desired output folder. Default is./Generated
  • outputFilename - Output filename. Default isOutput.cs when used from the CLI tool, otherwise its the .refitter filename. SoPetstore.refitter becomesPetstore.cs.
  • additionalNamespaces - A collection of additional namespaces to include in the generated file. A use case for this is when you want to reuse contracts from a different namespace than the generated code. Default is empty
  • includeTags - A collection of tags to use a filter for including endpoints that contain this tag.
  • includePathMatches - A collection of regular expressions used to filter paths.
  • generateDeprecatedOperations - a boolean indicating whether deprecated operations should be generated or skipped. Default istrue
  • operationNameTemplate - Generate operation names using pattern. This must contain the string {operationName}. An example usage of this could be{operationName}Async to suffix all method names with Async
  • optionalParameters - Generate non-required parameters as nullable optional parameters
  • trimUnusedSchema - Removes unreferenced components schema to keep the generated output to a minimum
  • keepSchemaPatterns: A collection of regular expressions to force to keep matching schema. This is used together withtrimUnusedSchema
  • generateDefaultAdditionalProperties: Set tofalse to skip default additional properties. Default istrue
  • operationNameGenerator: The NSwagIOperationNameGenerator implementation to use. Seehttps://refitter.github.io/api/Refitter.Core.OperationNameGeneratorTypes.html
  • immutableRecords: Set totrue to generate contracts as immutable records instead of classes. Default isfalse
  • useDynamicQuerystringParameters: Set totrue to wrap multiple query parameters into a single complex one. Default isfalse (no wrapping). Seehttps://github.com/reactiveui/refit?tab=readme-ov-file#dynamic-querystring-parameters for more information.
  • dependencyInjectionSettings - Setting this will generated extension methods toIServiceCollection for configuring Refit clients
    • baseUrl - Used as the HttpClient base address. Leave this blank to manually set the base URL
    • httpMessageHandlers - A collection ofHttpMessageHandler that is added to the HttpClient pipeline
    • usePolly - (DEPRECATED) Set this to true to configure the HttpClient to use Polly using a retry policy with a jittered backoff
    • transientErrorHandler: Set this to configure transient error handling with a retry policy that uses a jittered backoff. Seehttps://refitter.github.io/api/Refitter.Core.TransientErrorHandler.html
    • firstBackoffRetryInSeconds - This is the duration of the initial retry backoff. Default is 1 second
  • apizrSettings - Setting this will format Refit interface to be managed by Apizr. Seehttps://www.apizr.net for more information
    • withRequestOptions - Tells if the Refit interface methods should have a final IApizrRequestOptions options parameter
    • withRegistrationHelper - Tells if Refitter should generate Apizr registration helpers (extended with dependencyInjectionSettings set, otherwise static)
    • withCacheProvider - Set the cache provider to be used
    • withPriority - Tells if Apizr should handle request priority
    • withMediation - Tells if Apizr should handle request mediation (extended only)
    • withOptionalMediation - Tells if Apizr should handle optional request mediation (extended only)
    • withMappingProvider - Set the mapping provider to be used
    • withFileTransfer - Tells if Apizr should handle file transfer
  • codeGeneratorSettings - Setting this allows customization of the NSwag generated types and contracts
    • requiredPropertiesMustBeDefined - Default is true,
    • generateDataAnnotations - Default is true,
    • anyType - Default isobject,
    • dateType - Default isSystem.DateTimeOffset,
    • dateTimeType - Default isSystem.DateTimeOffset,
    • timeType - Default isSystem.TimeSpan,
    • timeSpanType - Default isSystem.TimeSpan,
    • arrayType - Default isSystem.Collections.Generic.ICollection,
    • dictionaryType - Default isSystem.Collections.Generic.IDictionary,
    • arrayInstanceType - Default isSystem.Collections.ObjectModel.Collection,
    • dictionaryInstanceType - Default isSystem.Collections.Generic.Dictionary,
    • arrayBaseType - Default isSystem.Collections.ObjectModel.Collection,
    • dictionaryBaseType - Default isSystem.Collections.Generic.Dictionary,
    • propertySetterAccessModifier - Default is ``,
    • generateImmutableArrayProperties - Default is false,
    • generateImmutableDictionaryProperties - Default is false,
    • handleReferences - Default is false,
    • jsonSerializerSettingsTransformationMethod - Default is null,
    • generateJsonMethods - Default is false,
    • enforceFlagEnums - Default is false,
    • inlineNamedDictionaries - Default is false,
    • inlineNamedTuples - Default is true,
    • inlineNamedArrays - Default is false,
    • generateOptionalPropertiesAsNullable - Default is false,
    • generateNullableReferenceTypes - Default is false,
    • generateNativeRecords - Default is false
    • generateDefaultValues - Default is true
    • inlineNamedAny - Default is false
    • excludedTypeNames - Default is empty

Using the generated code

Here's an example generated output from theSwagger Petstore example using the default settings

CLI Tool

$ refitter ./openapi.json --namespace"Your.Namespace.Of.Choice.GeneratedCode"

Source Generator.refitter file

{"openApiPath":"./openapi.json","namespace":"Your.Namespace.Of.Choice.GeneratedCode"}

Output

usingRefit;usingSystem.Collections.Generic;usingSystem.Text.Json.Serialization;usingSystem.Threading.Tasks;namespaceYour.Namespace.Of.Choice.GeneratedCode{[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceISwaggerPetstore{/// <summary>Update an existing pet</summary>/// <remarks>Update an existing pet by Id</remarks>/// <param name="body">Update an existent pet in the store</param>/// <returns>Successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Pet not found</description>/// </item>/// <item>/// <term>405</term>/// <description>Validation exception</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Put("/pet")]Task<Pet>UpdatePet([Body]Petbody);/// <summary>Add a new pet to the store</summary>/// <remarks>Add a new pet to the store</remarks>/// <param name="body">Create a new pet in the store</param>/// <returns>Successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>405</term>/// <description>Invalid input</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Post("/pet")]Task<Pet>AddPet([Body]Petbody);/// <summary>Finds Pets by status</summary>/// <remarks>Multiple status values can be provided with comma separated strings</remarks>/// <param name="status">Status values that need to be considered for filter</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid status value</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Get("/pet/findByStatus")]Task<ICollection<Pet>>FindPetsByStatus([Query]Status?status);/// <summary>Finds Pets by tags</summary>/// <remarks>Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.</remarks>/// <param name="tags">Tags to filter by</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid tag value</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Get("/pet/findByTags")]Task<ICollection<Pet>>FindPetsByTags([Query(CollectionFormat.Multi)]IEnumerable<string>tags);/// <summary>Find pet by ID</summary>/// <remarks>Returns a single pet</remarks>/// <param name="petId">ID of pet to return</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Pet not found</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Get("/pet/{petId}")]Task<Pet>GetPetById(longpetId);/// <summary>Updates a pet in the store with form data</summary>/// <param name="petId">ID of pet that needs to be updated</param>/// <param name="name">Name of pet that needs to be updated</param>/// <param name="status">Status of pet that needs to be updated</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>405</term>/// <description>Invalid input</description>/// </item>/// </list>/// </exception>[Post("/pet/{petId}")]TaskUpdatePetWithForm(longpetId,[Query]stringname,[Query]stringstatus);/// <summary>Deletes a pet</summary>/// <param name="petId">Pet id to delete</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid pet value</description>/// </item>/// </list>/// </exception>[Delete("/pet/{petId}")]TaskDeletePet(longpetId,[Header("api_key")]stringapi_key);/// <summary>uploads an image</summary>/// <param name="petId">ID of pet to update</param>/// <param name="additionalMetadata">Additional Metadata</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>successful operation</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/json")][Post("/pet/{petId}/uploadImage")]Task<ApiResponse>UploadFile(longpetId,[Query]stringadditionalMetadata,StreamPartbody);/// <summary>Returns pet inventories by status</summary>/// <remarks>Returns a map of status codes to quantities</remarks>/// <returns>successful operation</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Headers("Accept: application/json")][Get("/store/inventory")]Task<IDictionary<string,int>>GetInventory();/// <summary>Place an order for a pet</summary>/// <remarks>Place a new order in the store</remarks>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>405</term>/// <description>Invalid input</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Post("/store/order")]Task<Order>PlaceOrder([Body]Orderbody);/// <summary>Find purchase order by ID</summary>/// <remarks>For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions</remarks>/// <param name="orderId">ID of order that needs to be fetched</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Order not found</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Get("/store/order/{orderId}")]Task<Order>GetOrderById(longorderId);/// <summary>Delete purchase order by ID</summary>/// <remarks>For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors</remarks>/// <param name="orderId">ID of the order that needs to be deleted</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Order not found</description>/// </item>/// </list>/// </exception>[Delete("/store/order/{orderId}")]TaskDeleteOrder(longorderId);/// <summary>Create user</summary>/// <remarks>This can only be done by the logged in user.</remarks>/// <param name="body">Created user object</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Headers("Accept: application/json, application/xml")][Post("/user")]TaskCreateUser([Body]Userbody);/// <summary>Creates list of users with given input array</summary>/// <remarks>Creates list of users with given input array</remarks>/// <returns>Successful operation</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Headers("Accept: application/xml, application/json")][Post("/user/createWithList")]Task<User>CreateUsersWithListInput([Body]IEnumerable<User>body);/// <summary>Logs user into the system</summary>/// <param name="username">The user name for login</param>/// <param name="password">The password for login in clear text</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid username/password supplied</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Get("/user/login")]Task<string>LoginUser([Query]stringusername,[Query]stringpassword);/// <summary>Logs out current logged in user session</summary>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Get("/user/logout")]TaskLogoutUser();/// <summary>Get user by user name</summary>/// <param name="username">The name that needs to be fetched. Use user1 for testing.</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid username supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>User not found</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Get("/user/{username}")]Task<User>GetUserByName(stringusername);/// <summary>Update user</summary>/// <remarks>This can only be done by the logged in user.</remarks>/// <param name="username">name that need to be deleted</param>/// <param name="body">Update an existent user in the store</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Put("/user/{username}")]TaskUpdateUser(stringusername,[Body]Userbody);/// <summary>Delete user</summary>/// <remarks>This can only be done by the logged in user.</remarks>/// <param name="username">The name that needs to be deleted</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid username supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>User not found</description>/// </item>/// </list>/// </exception>[Delete("/user/{username}")]TaskDeleteUser(stringusername);}}

Here's an example generated output from theSwagger Petstore example configured to wrap the return type inIApiResponse<T>

CLI Tool

$ refitter ./openapi.json --namespace"Your.Namespace.Of.Choice.GeneratedCode" --use-api-response

Source Generator.refitter file

{"openApiPath":"./openapi.json","namespace":"Your.Namespace.Of.Choice.GeneratedCode","returnIApiResponse":true}

Output

usingRefit;usingSystem.Collections.Generic;usingSystem.Text.Json.Serialization;usingSystem.Threading.Tasks;namespaceYour.Namespace.Of.Choice.GeneratedCode{[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceISwaggerPetstore{/// <summary>Update an existing pet</summary>/// <remarks>Update an existing pet by Id</remarks>/// <param name="body">Update an existent pet in the store</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>Successful operation</description>/// </item>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Pet not found</description>/// </item>/// <item>/// <term>405</term>/// <description>Validation exception</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/xml, application/json")][Put("/pet")]Task<IApiResponse<Pet>>UpdatePet([Body]Petbody);/// <summary>Add a new pet to the store</summary>/// <remarks>Add a new pet to the store</remarks>/// <param name="body">Create a new pet in the store</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>Successful operation</description>/// </item>/// <item>/// <term>405</term>/// <description>Invalid input</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/xml, application/json")][Post("/pet")]Task<IApiResponse<Pet>>AddPet([Body]Petbody);/// <summary>Finds Pets by status</summary>/// <remarks>Multiple status values can be provided with comma separated strings</remarks>/// <param name="status">Status values that need to be considered for filter</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>successful operation</description>/// </item>/// <item>/// <term>400</term>/// <description>Invalid status value</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/json")][Get("/pet/findByStatus")]Task<IApiResponse<ICollection<Pet>>>FindPetsByStatus([Query]Status?status);/// <summary>Finds Pets by tags</summary>/// <remarks>Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.</remarks>/// <param name="tags">Tags to filter by</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>successful operation</description>/// </item>/// <item>/// <term>400</term>/// <description>Invalid tag value</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/json")][Get("/pet/findByTags")]Task<IApiResponse<ICollection<Pet>>>FindPetsByTags([Query(CollectionFormat.Multi)]IEnumerable<string>tags);/// <summary>Find pet by ID</summary>/// <remarks>Returns a single pet</remarks>/// <param name="petId">ID of pet to return</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>successful operation</description>/// </item>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Pet not found</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/xml, application/json")][Get("/pet/{petId}")]Task<IApiResponse<Pet>>GetPetById(longpetId);/// <summary>Updates a pet in the store with form data</summary>/// <param name="petId">ID of pet that needs to be updated</param>/// <param name="name">Name of pet that needs to be updated</param>/// <param name="status">Status of pet that needs to be updated</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>405</term>/// <description>Invalid input</description>/// </item>/// </list>/// </returns>[Post("/pet/{petId}")]Task<IApiResponse>UpdatePetWithForm(longpetId,[Query]stringname,[Query]stringstatus);/// <summary>Deletes a pet</summary>/// <param name="petId">Pet id to delete</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid pet value</description>/// </item>/// </list>/// </returns>[Delete("/pet/{petId}")]Task<IApiResponse>DeletePet(longpetId,[Header("api_key")]stringapi_key);/// <summary>uploads an image</summary>/// <param name="petId">ID of pet to update</param>/// <param name="additionalMetadata">Additional Metadata</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>successful operation</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/json")][Post("/pet/{petId}/uploadImage")]Task<IApiResponse<ApiResponse>>UploadFile(longpetId,[Query]stringadditionalMetadata,StreamPartbody);/// <summary>Returns pet inventories by status</summary>/// <remarks>Returns a map of status codes to quantities</remarks>/// <returns>successful operation</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Headers("Accept: application/json")][Get("/store/inventory")]Task<IApiResponse<IDictionary<string,int>>>GetInventory();/// <summary>Place an order for a pet</summary>/// <remarks>Place a new order in the store</remarks>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>successful operation</description>/// </item>/// <item>/// <term>405</term>/// <description>Invalid input</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/json")][Post("/store/order")]Task<IApiResponse<Order>>PlaceOrder([Body]Orderbody);/// <summary>Find purchase order by ID</summary>/// <remarks>For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions</remarks>/// <param name="orderId">ID of order that needs to be fetched</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>successful operation</description>/// </item>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Order not found</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/json")][Get("/store/order/{orderId}")]Task<IApiResponse<Order>>GetOrderById(longorderId);/// <summary>Delete purchase order by ID</summary>/// <remarks>For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors</remarks>/// <param name="orderId">ID of the order that needs to be deleted</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Order not found</description>/// </item>/// </list>/// </returns>[Delete("/store/order/{orderId}")]Task<IApiResponse>DeleteOrder(longorderId);/// <summary>Create user</summary>/// <remarks>This can only be done by the logged in user.</remarks>/// <param name="body">Created user object</param>/// <returns>A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result.</returns>[Headers("Accept: application/json, application/xml")][Post("/user")]Task<IApiResponse>CreateUser([Body]Userbody);/// <summary>Creates list of users with given input array</summary>/// <remarks>Creates list of users with given input array</remarks>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>Successful operation</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/xml, application/json")][Post("/user/createWithList")]Task<IApiResponse<User>>CreateUsersWithListInput([Body]IEnumerable<User>body);/// <summary>Logs user into the system</summary>/// <param name="username">The user name for login</param>/// <param name="password">The password for login in clear text</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>successful operation</description>/// </item>/// <item>/// <term>400</term>/// <description>Invalid username/password supplied</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/json")][Get("/user/login")]Task<IApiResponse<string>>LoginUser([Query]stringusername,[Query]stringpassword);/// <summary>Logs out current logged in user session</summary>/// <returns>A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result.</returns>[Get("/user/logout")]Task<IApiResponse>LogoutUser();/// <summary>Get user by user name</summary>/// <param name="username">The name that needs to be fetched. Use user1 for testing.</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>successful operation</description>/// </item>/// <item>/// <term>400</term>/// <description>Invalid username supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>User not found</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/json")][Get("/user/{username}")]Task<IApiResponse<User>>GetUserByName(stringusername);/// <summary>Update user</summary>/// <remarks>This can only be done by the logged in user.</remarks>/// <param name="username">name that need to be deleted</param>/// <param name="body">Update an existent user in the store</param>/// <returns>A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result.</returns>[Put("/user/{username}")]Task<IApiResponse>UpdateUser(stringusername,[Body]Userbody);/// <summary>Delete user</summary>/// <remarks>This can only be done by the logged in user.</remarks>/// <param name="username">The name that needs to be deleted</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid username supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>User not found</description>/// </item>/// </list>/// </returns>[Delete("/user/{username}")]Task<IApiResponse>DeleteUser(stringusername);}}

Here's an example generated output from theSwagger Petstore example configured to generate an interface for each endpoint

CLI Tool

$ refitter ./openapi.json --namespace"Your.Namespace.Of.Choice.GeneratedCode" --multiple-interfaces ByEndpoint

Source Generator.refitter file

{"openApiPath":"./openapi.json","namespace":"Your.Namespace.Of.Choice.GeneratedCode","multipleInterfaces":"ByEndpoint"}

Output

/// <summary>Update an existing pet</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIUpdatePetEndpoint{/// <summary>Update an existing pet</summary>/// <remarks>Update an existing pet by Id</remarks>/// <param name="body">Update an existent pet in the store</param>/// <returns>Successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Pet not found</description>/// </item>/// <item>/// <term>405</term>/// <description>Validation exception</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Put("/pet")]Task<Pet>Execute([Body]Petbody);}/// <summary>Add a new pet to the store</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIAddPetEndpoint{/// <summary>Add a new pet to the store</summary>/// <remarks>Add a new pet to the store</remarks>/// <param name="body">Create a new pet in the store</param>/// <returns>Successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>405</term>/// <description>Invalid input</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Post("/pet")]Task<Pet>Execute([Body]Petbody);}/// <summary>Finds Pets by status</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIFindPetsByStatusEndpoint{/// <summary>Finds Pets by status</summary>/// <remarks>Multiple status values can be provided with comma separated strings</remarks>/// <param name="status">Status values that need to be considered for filter</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid status value</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Get("/pet/findByStatus")]Task<ICollection<Pet>>Execute([Query]Status?status);}/// <summary>Finds Pets by tags</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIFindPetsByTagsEndpoint{/// <summary>Finds Pets by tags</summary>/// <remarks>Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.</remarks>/// <param name="tags">Tags to filter by</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid tag value</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Get("/pet/findByTags")]Task<ICollection<Pet>>Execute([Query(CollectionFormat.Multi)]IEnumerable<string>tags);}/// <summary>Find pet by ID</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIGetPetByIdEndpoint{/// <summary>Find pet by ID</summary>/// <remarks>Returns a single pet</remarks>/// <param name="petId">ID of pet to return</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Pet not found</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Get("/pet/{petId}")]Task<Pet>Execute(longpetId);}/// <summary>Updates a pet in the store with form data</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIUpdatePetWithFormEndpoint{/// <summary>Updates a pet in the store with form data</summary>/// <param name="petId">ID of pet that needs to be updated</param>/// <param name="name">Name of pet that needs to be updated</param>/// <param name="status">Status of pet that needs to be updated</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>405</term>/// <description>Invalid input</description>/// </item>/// </list>/// </exception>[Post("/pet/{petId}")]TaskExecute(longpetId,[Query]stringname,[Query]stringstatus);}/// <summary>Deletes a pet</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIDeletePetEndpoint{/// <summary>Deletes a pet</summary>/// <param name="petId">Pet id to delete</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid pet value</description>/// </item>/// </list>/// </exception>[Delete("/pet/{petId}")]TaskExecute(longpetId,[Header("api_key")]stringapi_key);}/// <summary>uploads an image</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIUploadFileEndpoint{/// <summary>uploads an image</summary>/// <param name="petId">ID of pet to update</param>/// <param name="additionalMetadata">Additional Metadata</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>successful operation</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/json")][Post("/pet/{petId}/uploadImage")]Task<ApiResponse>Execute(longpetId,[Query]stringadditionalMetadata,StreamPartbody);}/// <summary>Returns pet inventories by status</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIGetInventoryEndpoint{/// <summary>Returns pet inventories by status</summary>/// <remarks>Returns a map of status codes to quantities</remarks>/// <returns>successful operation</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Headers("Accept: application/json")][Get("/store/inventory")]Task<IDictionary<string,int>>Execute();}/// <summary>Place an order for a pet</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIPlaceOrderEndpoint{/// <summary>Place an order for a pet</summary>/// <remarks>Place a new order in the store</remarks>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>405</term>/// <description>Invalid input</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Post("/store/order")]Task<Order>Execute([Body]Orderbody);}/// <summary>Find purchase order by ID</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIGetOrderByIdEndpoint{/// <summary>Find purchase order by ID</summary>/// <remarks>For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions</remarks>/// <param name="orderId">ID of order that needs to be fetched</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Order not found</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Get("/store/order/{orderId}")]Task<Order>Execute(longorderId);}/// <summary>Delete purchase order by ID</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIDeleteOrderEndpoint{/// <summary>Delete purchase order by ID</summary>/// <remarks>For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors</remarks>/// <param name="orderId">ID of the order that needs to be deleted</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Order not found</description>/// </item>/// </list>/// </exception>[Delete("/store/order/{orderId}")]TaskExecute(longorderId);}/// <summary>Create user</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceICreateUserEndpoint{/// <summary>Create user</summary>/// <remarks>This can only be done by the logged in user.</remarks>/// <param name="body">Created user object</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Headers("Accept: application/json, application/xml")][Post("/user")]TaskExecute([Body]Userbody);}/// <summary>Creates list of users with given input array</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceICreateUsersWithListInputEndpoint{/// <summary>Creates list of users with given input array</summary>/// <remarks>Creates list of users with given input array</remarks>/// <returns>Successful operation</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Headers("Accept: application/xml, application/json")][Post("/user/createWithList")]Task<User>Execute([Body]IEnumerable<User>body);}/// <summary>Logs user into the system</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceILoginUserEndpoint{/// <summary>Logs user into the system</summary>/// <param name="username">The user name for login</param>/// <param name="password">The password for login in clear text</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid username/password supplied</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Get("/user/login")]Task<string>Execute([Query]stringusername,[Query]stringpassword);}/// <summary>Logs out current logged in user session</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceILogoutUserEndpoint{/// <summary>Logs out current logged in user session</summary>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Get("/user/logout")]TaskExecute();}/// <summary>Get user by user name</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIGetUserByNameEndpoint{/// <summary>Get user by user name</summary>/// <param name="username">The name that needs to be fetched. Use user1 for testing.</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid username supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>User not found</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Get("/user/{username}")]Task<User>Execute(stringusername);}/// <summary>Update user</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIUpdateUserEndpoint{/// <summary>Update user</summary>/// <remarks>This can only be done by the logged in user.</remarks>/// <param name="username">name that need to be deleted</param>/// <param name="body">Update an existent user in the store</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Put("/user/{username}")]TaskExecute(stringusername,[Body]Userbody);}/// <summary>Delete user</summary>[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceIDeleteUserEndpoint{/// <summary>Delete user</summary>/// <remarks>This can only be done by the logged in user.</remarks>/// <param name="username">The name that needs to be deleted</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid username supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>User not found</description>/// </item>/// </list>/// </exception>[Delete("/user/{username}")]TaskExecute(stringusername);}

Here's an example generated output from theSwagger Petstore example configured to generate an interface with dynamic querystring paremeters

CLI Tool

$ refitter ./openapi.json --namespace"Your.Namespace.Of.Choice.GeneratedCode" --use-dynamic-querystring-parameters

Output

[System.CodeDom.Compiler.GeneratedCode("Refitter","1.0.0.0")]publicpartialinterfaceISwaggerPetstoreOpenAPI30{/// <summary>Update an existing pet</summary>/// <remarks>Update an existing pet by Id</remarks>/// <param name="body">Update an existent pet in the store</param>/// <returns>Successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Pet not found</description>/// </item>/// <item>/// <term>405</term>/// <description>Validation exception</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Put("/pet")]Task<Pet>UpdatePet([Body]Petbody);/// <summary>Add a new pet to the store</summary>/// <remarks>Add a new pet to the store</remarks>/// <param name="body">Create a new pet in the store</param>/// <returns>Successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>405</term>/// <description>Invalid input</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Post("/pet")]Task<Pet>AddPet([Body]Petbody);/// <summary>Finds Pets by status</summary>/// <remarks>Multiple status values can be provided with comma separated strings</remarks>/// <param name="status">Status values that need to be considered for filter</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid status value</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Get("/pet/findByStatus")]Task<ICollection<Pet>>FindPetsByStatus([Query]Status?status);/// <summary>Finds Pets by tags</summary>/// <remarks>Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.</remarks>/// <param name="tags">Tags to filter by</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid tag value</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Get("/pet/findByTags")]Task<ICollection<Pet>>FindPetsByTags([Query(CollectionFormat.Multi)]IEnumerable<string>tags);/// <summary>Find pet by ID</summary>/// <remarks>Returns a single pet</remarks>/// <param name="petId">ID of pet to return</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Pet not found</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Get("/pet/{petId}")]Task<Pet>GetPetById(longpetId);/// <summary>Updates a pet in the store with form data</summary>/// <param name="petId">ID of pet that needs to be updated</param>/// <param name="queryParams">The dynamic querystring parameter wrapping all others.</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>405</term>/// <description>Invalid input</description>/// </item>/// </list>/// </exception>[Post("/pet/{petId}")]TaskUpdatePetWithForm(longpetId,[Query]UpdatePetWithFormQueryParamsqueryParams);/// <summary>Deletes a pet</summary>/// <param name="petId">Pet id to delete</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid pet value</description>/// </item>/// </list>/// </exception>[Delete("/pet/{petId}")]TaskDeletePet(longpetId,[Header("api_key")]stringapi_key);/// <summary>uploads an image</summary>/// <param name="petId">ID of pet to update</param>/// <param name="additionalMetadata">Additional Metadata</param>/// <returns>/// A <see cref="Task"/> representing the <see cref="IApiResponse"/> instance containing the result:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>200</term>/// <description>successful operation</description>/// </item>/// </list>/// </returns>[Headers("Accept: application/json")][Post("/pet/{petId}/uploadImage")]Task<ApiResponse>UploadFile(longpetId,[Query]stringadditionalMetadata,StreamPartbody);/// <summary>Returns pet inventories by status</summary>/// <remarks>Returns a map of status codes to quantities</remarks>/// <returns>successful operation</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Headers("Accept: application/json")][Get("/store/inventory")]Task<IDictionary<string,int>>GetInventory();/// <summary>Place an order for a pet</summary>/// <remarks>Place a new order in the store</remarks>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>405</term>/// <description>Invalid input</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/json")][Post("/store/order")]Task<Order>PlaceOrder([Body]Orderbody);/// <summary>Find purchase order by ID</summary>/// <remarks>For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.</remarks>/// <param name="orderId">ID of order that needs to be fetched</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Order not found</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Get("/store/order/{orderId}")]Task<Order>GetOrderById(longorderId);/// <summary>Delete purchase order by ID</summary>/// <remarks>For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors</remarks>/// <param name="orderId">ID of the order that needs to be deleted</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid ID supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>Order not found</description>/// </item>/// </list>/// </exception>[Delete("/store/order/{orderId}")]TaskDeleteOrder(longorderId);/// <summary>Create user</summary>/// <remarks>This can only be done by the logged in user.</remarks>/// <param name="body">Created user object</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Headers("Accept: application/json, application/xml")][Post("/user")]TaskCreateUser([Body]Userbody);/// <summary>Creates list of users with given input array</summary>/// <remarks>Creates list of users with given input array</remarks>/// <returns>Successful operation</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Headers("Accept: application/xml, application/json")][Post("/user/createWithList")]Task<User>CreateUsersWithListInput([Body]IEnumerable<User>body);/// <summary>Logs user into the system</summary>/// <param name="queryParams">The dynamic querystring parameter wrapping all others.</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid username/password supplied</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Get("/user/login")]Task<string>LoginUser([Query]LoginUserQueryParamsqueryParams);/// <summary>Logs out current logged in user session</summary>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Get("/user/logout")]TaskLogoutUser();/// <summary>Get user by user name</summary>/// <param name="username">The name that needs to be fetched. Use user1 for testing.</param>/// <returns>successful operation</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid username supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>User not found</description>/// </item>/// </list>/// </exception>[Headers("Accept: application/xml, application/json")][Get("/user/{username}")]Task<User>GetUserByName(stringusername);/// <summary>Update user</summary>/// <remarks>This can only be done by the logged in user.</remarks>/// <param name="username">name that needs to be updated</param>/// <param name="body">Update an existent user in the store</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">Thrown when the request returns a non-success status code.</exception>[Put("/user/{username}")]TaskUpdateUser(stringusername,[Body]Userbody);/// <summary>Delete user</summary>/// <remarks>This can only be done by the logged in user.</remarks>/// <param name="username">The name that needs to be deleted</param>/// <returns>A <see cref="Task"/> that completes when the request is finished.</returns>/// <exception cref="ApiException">/// Thrown when the request returns a non-success status code:/// <list type="table">/// <listheader>/// <term>Status</term>/// <description>Description</description>/// </listheader>/// <item>/// <term>400</term>/// <description>Invalid username supplied</description>/// </item>/// <item>/// <term>404</term>/// <description>User not found</description>/// </item>/// </list>/// </exception>[Delete("/user/{username}")]TaskDeleteUser(stringusername);}publicclassUpdatePetWithFormQueryParams{/// <summary>/// Name of pet that needs to be updated/// </summary>[Query]publicstringName{get;set;}/// <summary>/// Status of pet that needs to be updated/// </summary>[Query]publicstringStatus{get;set;}}publicclassLoginUserQueryParams{/// <summary>/// The user name for login/// </summary>[Query]publicstringUsername{get;set;}/// <summary>/// The password for login in clear text/// </summary>[Query]publicstringPassword{get;set;}}

RestService

Here's an example usage of the generated code above

usingRefit;usingSystem;usingSystem.Threading.Tasks;namespaceYour.Namespace.Of.Choice.GeneratedCode;internalclassProgram{privatestaticasyncTaskMain(string[]args){varclient=RestService.For<ISwaggerPetstore>("https://petstore3.swagger.io/api/v3");varpet=awaitclient.GetPetById(1);Console.WriteLine("## Using Task<T> as return type ##");Console.WriteLine($"Name:{pet.Name}");Console.WriteLine($"Category:{pet.Category.Name}");Console.WriteLine($"Status:{pet.Status}");Console.WriteLine();varclient2=RestService.For<WithApiResponse.ISwaggerPetstore>("https://petstore3.swagger.io/api/v3");varresponse=awaitclient2.GetPetById(2);Console.WriteLine("## Using Task<IApiResponse<T>> as return type ##");Console.WriteLine($"HTTP Status Code:{response.StatusCode}");Console.WriteLine($"Name:{response.Content.Name}");Console.WriteLine($"Category:{response.Content.Category.Name}");Console.WriteLine($"Status:{response.Content.Status}");}}

TheRestService class generates an implementation ofISwaggerPetstore that usesHttpClient to make its calls.

The code above when run will output something like this:

## Using Task<T> as return type ##Name: GatitotototoCategory: ChaucitoStatus: Sold## Using Task<IApiResponse<T>> as return type ##HTTP Status Code: OKName: GatitotototoCategory: ChaucitoStatus: Sold

ASP.NET Core and HttpClientFactory

Here's an example Minimal API with theRefit.HttpClientFactory library:

usingRefit;usingYour.Namespace.Of.Choice.GeneratedCode;varbuilder=WebApplication.CreateBuilder(args);builder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen();builder.Services.AddRefitClient<ISwaggerPetstore>().ConfigureHttpClient(c=>c.BaseAddress=newUri("https://petstore3.swagger.io/api/v3"));varapp=builder.Build();app.MapGet("/pet/{id:long}",async(ISwaggerPetstorepetstore,longid)=>{try{returnResults.Ok(awaitpetstore.GetPetById(id));}catch(Refit.ApiExceptione){returnResults.StatusCode((int)e.StatusCode);}}).WithName("GetPetById").WithOpenApi();app.UseHttpsRedirection();app.UseSwaggerUI();app.UseSwagger();app.Run();

.NET Core supports registering the generatedISwaggerPetstore interface viaHttpClientFactory

The following request to the API above

$ curl -X'GET''https://localhost:5001/pet/1' -H'accept: application/json'

Returns a response that looks something like this:

{"id":1,"name":"Special_char_owner_!@#$^&()`.testing","photoUrls": ["https://petstore3.swagger.io/resources/photos/623389095.jpg"  ],"tags": [],"status":"Sold"}

Dependency Injection

Refitter supports generating bootstrapping code that allows the user to conveniently configure all generated Refit interfaces by calling a single extension method toIServiceCollection.

This is enabled through the.refitter settings file like this:

{"openApiPath":"../OpenAPI/v3.0/petstore.json","namespace":"Petstore","dependencyInjectionSettings": {"baseUrl":"https://petstore3.swagger.io/api/v3","httpMessageHandlers": ["TelemetryDelegatingHandler" ],"transientErrorHandler":"Polly","maxRetryCount":3,"firstBackoffRetryInSeconds":0.5  }}

which will generate an extension method toIServiceCollection calledConfigureRefitClients(). The generated extension method depends onRefit.HttpClientFactory library and looks like this:

publicstaticIServiceCollectionConfigureRefitClients(thisIServiceCollectionservices,Action<IHttpClientBuilder>?builder=default,RefitSettings?settings=default){varclientBuilderISwaggerPetstore=services.AddRefitClient<ISwaggerPetstore>(settings).ConfigureHttpClient(c=>c.BaseAddress=newUri("https://petstore3.swagger.io/api/v3")).AddHttpMessageHandler<TelemetryDelegatingHandler>();clientBuilderISwaggerPetstore.AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(Backoff.DecorrelatedJitterBackoffV2(TimeSpan.FromSeconds(0.5),3)));builder?.Invoke(clientBuilderISwaggerPetstore);returnservices;}

This comes in handy especially when generating multiple interfaces, by tag or endpoint. For example, the following.refitter settings file

{"openApiPath":"../OpenAPI/v3.0/petstore.json","namespace":"Petstore","multipleInterfaces":"ByTag","dependencyInjectionSettings": {"baseUrl":"https://petstore3.swagger.io/api/v3","httpMessageHandlers": ["TelemetryDelegatingHandler" ],"transientErrorHandler":"Polly","maxRetryCount":3,"firstBackoffRetryInSeconds":0.5  }}

Will generate a singleConfigureRefitClients() extension methods that may contain dependency injection configuration code for multiple interfaces like this

publicstaticIServiceCollectionConfigureRefitClients(thisIServiceCollectionservices,Action<IHttpClientBuilder>?builder=default,RefitSettings?settings=default){varclientBuilderIPetApi=services.AddRefitClient<IPetApi>(settings).ConfigureHttpClient(c=>c.BaseAddress=newUri("https://petstore3.swagger.io/api/v3")).AddHttpMessageHandler<TelemetryDelegatingHandler>();clientBuilderIPetApi.AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(Backoff.DecorrelatedJitterBackoffV2(TimeSpan.FromSeconds(0.5),3)));builder?.Invoke(clientBuilderIPetApi);varclientBuilderIStoreApi=services.AddRefitClient<IStoreApi>(settings).ConfigureHttpClient(c=>c.BaseAddress=newUri("https://petstore3.swagger.io/api/v3")).AddHttpMessageHandler<TelemetryDelegatingHandler>();clientBuilderIStoreApi.AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(Backoff.DecorrelatedJitterBackoffV2(TimeSpan.FromSeconds(0.5),3)));builder?.Invoke(clientBuilderIStoreApi);varclientBuilderIUserApi=services.AddRefitClient<IUserApi>(settings).ConfigureHttpClient(c=>c.BaseAddress=newUri("https://petstore3.swagger.io/api/v3")).AddHttpMessageHandler<TelemetryDelegatingHandler>();clientBuilderIUserApi.AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(Backoff.DecorrelatedJitterBackoffV2(TimeSpan.FromSeconds(0.5),3)));builder?.Invoke(clientBuilderIUserApi);returnservices;}

Personally, they I use Refitter is to generate an interface per endpoint, so when generating code for a large and complex API, I might have several interfaces.

Apizr

Apizr is a Refit client manager that provides a set of features to enhance requesting experience with resilience, caching, priority, mediation, mapping, logging, authentication, file transfer capabilities and many more...

Generating the interfaces

Refitter supports generating Apizr formatted Refit interfaces that can be managed then by Apizr (v6+).

You can enable Apizr formatted Refit interface generation either:

  • With the--use-apizr command line argument
  • By setting theapizrSettings section in the.refitter settings file

Note that--use-apizr uses default Apizr settings withwithRequestOptions set totrue as recommended, while the.refitter settings file allows you to configure it deeper.

In both cases, it will format the generated Refit interfaces to be Apizr ready by:

  • Adding a final IApizrRequestOptions options parameter to all generated methods (ifwithRequestOptions is set totrue)
  • Providing cancellation tokens by Apizr request options instead of a dedicated parameter (ifwithRequestOptions is set totrue)
  • Using method overloads instead of optional parameters (note that settinguseDynamicQuerystringParameters totrue improve overloading experience)

From here, you're definitly free to use the formatted interface with Apizr by registering, configuring and using it following theApizr documentation. But Refitter can go further by generating some helpers to make the configuration easier.

Generating the helpers

Refitter supports generating Apizr (v6+) bootstrapping code that allows the user to conveniently configure all generated Apizr formatted Refit interfaces by calling a single method.It could be either an extension method toIServiceCollection if DependencyInjectionSettings are set, or a static builder method if not.

To enable Apizr registration code generation forIServiceCollection, you need at least to set thewithRegistrationHelper property totrue and configure theDependencyInjectionSettings section in the.refitter settings file.This is what the.refitter settings file may look like, depending on you configuration:

{"openApiPath":"../OpenAPI/v3.0/petstore.json","namespace":"Petstore","useDynamicQuerystringParameters":true,"dependencyInjectionSettings": {"baseUrl":"https://petstore3.swagger.io/api/v3","httpMessageHandlers": ["MyDelegatingHandler" ],"transientErrorHandler":"HttpResilience","maxRetryCount":3,"firstBackoffRetryInSeconds":0.5  },"apizrSettings": {"withRequestOptions":true,// Recommended to include an Apizr request options parameter to Refit interface methods"withRegistrationHelper":true,// Mandatory to actually generate the Apizr registration extended method"withCacheProvider":"InMemory",// Optional, default is None"withPriority":true,// Optional, default is false"withMediation":true,// Optional, default is false"withOptionalMediation":true,// Optional, default is false"withMappingProvider":"AutoMapper",// Optional, default is None"withFileTransfer":true// Optional, default is false  }}

which will generate an extension method toIServiceCollection calledConfigurePetstoreApiApizrManager(). The generated extension method depends onApizr.Extensions.Microsoft.DependencyInjection library and looks like this:

publicstaticIServiceCollectionConfigurePetstoreApiApizrManager(thisIServiceCollectionservices,Action<IApizrExtendedManagerOptionsBuilder>?optionsBuilder=null){optionsBuilder??= _=>{};// Default empty options if nulloptionsBuilder+= options=>options.WithBaseAddress("https://petstore3.swagger.io/api/v3",ApizrDuplicateStrategy.Ignore).WithDelegatingHandler<MyDelegatingHandler>().ConfigureHttpClientBuilder(builder=>builder.AddStandardResilienceHandler(config=>{config.Retry=newHttpRetryStrategyOptions{UseJitter=true,MaxRetryAttempts=3,Delay=TimeSpan.FromSeconds(0.5)};})).WithInMemoryCacheHandler().WithAutoMapperMappingHandler().WithPriority().WithOptionalMediation().WithFileTransferOptionalMediation();returnservices.AddApizrManagerFor<IPetstoreApi>(optionsBuilder);}

This comes in handy especially when generating multiple interfaces, by tag or endpoint. For example, the following.refitter settings file

{"openApiPath":"../OpenAPI/v3.0/petstore.json","namespace":"Petstore","useDynamicQuerystringParameters":true,"multipleInterfaces":"ByTag","naming": {"useOpenApiTitle":false,"interfaceName":"Petstore"  },"dependencyInjectionSettings": {"baseUrl":"https://petstore3.swagger.io/api/v3","httpMessageHandlers": ["MyDelegatingHandler" ],"transientErrorHandler":"HttpResilience","maxRetryCount":3,"firstBackoffRetryInSeconds":0.5  },"apizrSettings": {"withRequestOptions":true,// Recommended to include an Apizr request options parameter to Refit interface methods"withRegistrationHelper":true,// Mandatory to actually generate the Apizr registration extended method"withCacheProvider":"InMemory",// Optional, default is None"withPriority":true,// Optional, default is false"withMediation":true,// Optional, default is false"withOptionalMediation":true,// Optional, default is false"withMappingProvider":"AutoMapper",// Optional, default is None"withFileTransfer":true// Optional, default is false  }}

Will generate a singleConfigurePetstoreApizrManagers() extension method that may contain dependency injection configuration code for multiple interfaces like this

publicstaticIServiceCollectionConfigurePetstoreApizrManagers(thisIServiceCollectionservices,Action<IApizrExtendedCommonOptionsBuilder>?optionsBuilder=null){optionsBuilder??= _=>{};// Default empty options if nulloptionsBuilder+= options=>options.WithBaseAddress("https://petstore3.swagger.io/api/v3",ApizrDuplicateStrategy.Ignore).WithDelegatingHandler<MyDelegatingHandler>().ConfigureHttpClientBuilder(builder=>builder.AddStandardResilienceHandler(config=>{config.Retry=newHttpRetryStrategyOptions{UseJitter=true,MaxRetryAttempts=3,Delay=TimeSpan.FromSeconds(0.5)};})).WithInMemoryCacheHandler().WithAutoMapperMappingHandler().WithPriority().WithOptionalMediation().WithFileTransferOptionalMediation();returnservices.AddApizr(        registry=>registry.AddManagerFor<IPetApi>().AddManagerFor<IStoreApi>().AddManagerFor<IUserApi>(),optionsBuilder);}

Here,IPetApi,IStoreApi andIUserApi are the generated interfaces which share the same common configuration defined from the.refitter file.

To enable Apizr static builder code generation, you need at least to set thewithRegistrationHelper property totrue and leave theDependencyInjectionSettings section to null in the.refitter settings file.This is what the.refitter settings file may look like, depending on you configuration:

{"openApiPath":"../OpenAPI/v3.0/petstore.json","namespace":"Petstore","useDynamicQuerystringParameters":true,"apizrSettings": {"withRequestOptions":true,// Recommended to include an Apizr request options parameter to Refit interface methods"withRegistrationHelper":true,// Mandatory to actually generate the Apizr registration extended method"withCacheProvider":"Akavache",// Optional, default is None"withPriority":true,// Optional, default is false"withMappingProvider":"AutoMapper",// Optional, default is None"withFileTransfer":true// Optional, default is false  }}

which will generate a static builder method calledBuildPetstore30ApizrManager(). The generated builder method depends onApizr library and looks like this:

publicstaticIApizrManager<ISwaggerPetstoreOpenAPI30>BuildPetstore30ApizrManager(Action<IApizrManagerOptionsBuilder>optionsBuilder){optionsBuilder??= _=>{};// Default empty options if nulloptionsBuilder+= options=>options.WithAkavacheCacheHandler().WithAutoMapperMappingHandler(newMapperConfiguration(config=>{/* YOUR_MAPPINGS_HERE */})).WithPriority();returnApizrBuilder.Current.CreateManagerFor<ISwaggerPetstoreOpenAPI30>(optionsBuilder);}

This comes in handy especially when generating multiple interfaces, by tag or endpoint. For example, the following.refitter settings file

{"openApiPath":"../OpenAPI/v3.0/petstore.json","namespace":"Petstore","useDynamicQuerystringParameters":true,"multipleInterfaces":"ByTag","naming": {"useOpenApiTitle":false,"interfaceName":"Petstore"  },"dependencyInjectionSettings": {"baseUrl":"https://petstore3.swagger.io/api/v3","httpMessageHandlers": ["MyDelegatingHandler" ],"transientErrorHandler":"HttpResilience","maxRetryCount":3,"firstBackoffRetryInSeconds":0.5  },"apizrSettings": {"withRequestOptions":true,// Recommended to include an Apizr request options parameter to Refit interface methods"withRegistrationHelper":true,// Mandatory to actually generate the Apizr registration extended method"withCacheProvider":"InMemory",// Optional, default is None"withPriority":true,// Optional, default is false"withMediation":true,// Optional, default is false"withOptionalMediation":true,// Optional, default is false"withMappingProvider":"AutoMapper",// Optional, default is None"withFileTransfer":true// Optional, default is false  }}

Will generate a singleBuildPetstoreApizrManagers() builder method that may contain configuration code for multiple interfaces like this

publicstaticIApizrRegistryBuildPetstoreApizrManagers(Action<IApizrCommonOptionsBuilder>optionsBuilder){optionsBuilder??= _=>{};// Default empty options if nulloptionsBuilder+= options=>options.WithAkavacheCacheHandler().WithAutoMapperMappingHandler(newMapperConfiguration(config=>{/* YOUR_MAPPINGS_HERE */})).WithPriority();returnApizrBuilder.Current.CreateRegistry(        registry=>registry.AddManagerFor<IPetApi>().AddManagerFor<IStoreApi>().AddManagerFor<IUserApi>(),optionsBuilder);}

Here,IPetApi,IStoreApi andIUserApi are the generated interfaces which share the same common configuration defined from the.refitter file.


Customizing the configuration

You may want to adjust apis configuration, for example, to add a custom header to requests. This can be done using theAction<TApizrOptionsBuilder> parameter while calling the generated method.To know how to make Apizr fit your needs, please refer to theApizr documentation.

Using the managers

Once you called the generated method, you will get anIApizrManager<T> instance that you can use to make requests to the API. Here's an example of how to use it:

varresult=awaitpetstoreManager.ExecuteAsync((api,opt)=>api.GetPetById(1,opt),     options=>options// Whatever final request options you want to apply.WithPriority(Priority.Background).WithHeaders(["HeaderKey1: HeaderValue1"]).WithRequestTimeout("00:00:10").WithCancellation(cts.Token));

Please head to theApizr documentation to get more.

System requirements

.NET 8.0

Contributors

Philip Cox
Philip Cox

💻
Cameron MacFarland
Cameron MacFarland

💻
kgame
kgame

💻
Thomas Pettersen / Yrki
Thomas Pettersen / Yrki

💻
Artem
Artem

🐛
m7clarke
m7clarke

🐛
kirides
kirides

🐛💻
guillaumeserale
guillaumeserale

💻🐛
Dennis Brentjes
Dennis Brentjes

💻🤔
Damian Hickey
Damian Hickey

🐛
richardhu-lmg
richardhu-lmg

🐛
brease-colin
brease-colin

🐛
angelofb
angelofb

💻
Dim Nogro
Dim Nogro

💻
yadanilov19
yadanilov19

🤔💻
Daniel Powell
Daniel Powell

🐛
Ekkeir
Ekkeir

📖🐛
Waylon Martinez
Waylon Martinez

🐛
vkmadupa
vkmadupa

🐛
Noblix
Noblix

💻🤔
Attila Hajdrik
Attila Hajdrik

🤔
bielik01
bielik01

🐛🤔
naaeef
naaeef

🤔
Alireza Habibi
Alireza Habibi

🐛
Jeff Parker, PE
Jeff Parker, PE

🐛
jods
jods

🤔🐛
Edimarquez Medeiros
Edimarquez Medeiros

💻
safakkesikci
safakkesikci

🐛
folbrecht
folbrecht

🐛
mortenlaursen
mortenlaursen

💻
manuel-fernandez-rodriguez
manuel-fernandez-rodriguez

🐛
Eli Yammine
Eli Yammine

🐛
kami-poi
kami-poi

🤔
Xeevis
Xeevis

🐛
DJ4ddi
DJ4ddi

💻🤔
direncancatalkaya
direncancatalkaya

💻
Robert Palmqvist
Robert Palmqvist

🤔💻
Tim M
Tim M

📖
janfolbrecht
janfolbrecht

🤔💻
Nick Seguin
Nick Seguin

💻
David Brink
David Brink

🐛💻
Stu Wilson
Stu Wilson

🤔💻
sharpzilla
sharpzilla

🤔
Tatu
Tatu

🐛
Jérémy BRUN-PICARD
Jérémy BRUN-PICARD

🤔💻📖
Ed Barnard
Ed Barnard

🤔
bastien.noel
bastien.noel

🐛
Meikel Philipp
Meikel Philipp

🤔
Berk Selvi
Berk Selvi

🤔💻
Joshua Ozeri
Joshua Ozeri

🐛
Ryan Heath
Ryan Heath

🤔💻
Brian Brunner
Brian Brunner

🤔
Frank Samiec
Frank Samiec

💻
Fabio Loreggian
Fabio Loreggian

🐛
geometrikal
geometrikal

🐛

For tips and tricks on software development, check outmy blog

If you find this useful and feel a bit generous then feel free tobuy me a coffee ☕

About

Refit Client API Generator for OpenAPI

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C#96.2%
  • Liquid2.3%
  • PowerShell1.5%

[8]ページ先頭

©2009-2025 Movatter.jp