[![Build](https://github.com/christianhelle/refitter/actions/workflows/build.yml/badge.svg)](https://github.com/christianhelle/refitter/actions/workflows/build.yml)
[![Smoke Tests](https://github.com/christianhelle/refitter/actions/workflows/smoke-tests.yml/badge.svg)](https://github.com/christianhelle/refitter/actions/workflows/smoke-tests.yml)
[![NuGet](https://img.shields.io/nuget/v/refitter?color=blue)](https://www.nuget.org/packages/refitter)
[![Docker Image Version](https://img.shields.io/docker/v/christianhelle/refitter?label=docker)](https://hub.docker.com/r/christianhelle/refitter)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=christianhelle_refitter&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=christianhelle_refitter)
[![codecov](https://codecov.io/gh/christianhelle/refitter/graph/badge.svg?token=242YT1N6T2)](https://codecov.io/gh/christianhelle/refitter)

<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-101-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->

# Refitter

Refitter is a tool for generating a C# REST API Client using the [Refit](https://github.com/reactiveui/refit) library. Refitter can generate the Refit interface and contracts from OpenAPI specifications. Refitter could format the generated Refit interface to be managed by [Apizr](https://www.apizr.net) (v6+) and generate some registration helpers too.

> **Upgrading to v2.0.0?** Review the [Breaking Changes (v2.0.0)](docs/docfx_project/articles/breaking-changes-v2-0-0.md) guide. Source-generator projects may now need an explicit `Refit` reference, and the OpenAPI parser upgrade should be treated as a regenerate-review-test migration step rather than a fully proven behavioral no-op.

Refitter comes in 3 forms:

- A [.NET CLI Tool](#cli-tool) distributed via [nuget.org](http://www.nuget.org/packages/refitter) that outputs a single C# file on disk
- An [MSBuild Task](#msbuild) via the [Refitter.MSBuild](http://www.nuget.org/packages/refitter.msbuild) package that integrates seamlessly into your build pipeline and automatically generates code at build time based on [.refitter](#.refitter-file-format) files within the project directory
- A [C# Source Generator](#source-generator) via the [Refitter.SourceGenerator](http://www.nuget.org/packages/refitter.sourcegenerator) package that generates code on compile time based on a [.refitter](#.refitter-file-format) within the project directory

## 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:

```shell
dotnet tool install --global Refitter
```

Alternatively, you can use the Docker image:

```shell
docker pull christianhelle/refitter
```

Or run it directly:

```shell
docker run --rm -v $(pwd):/src christianhelle/refitter ./openapi.json --output ./GeneratedCode.cs
```

### Usage

```shell
refitter --help
```

```text
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 --ignored-operation-headers "header-one" --ignored-operation-headers "Header-Two"
    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 --property-naming-policy PreserveOriginal
    refitter ./openapi.json --multiple-interfaces ByEndpoint
    refitter ./openapi.json --multiple-files --output ./Generated
    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-serialization
    refitter ./openapi.json --collection-format Csv
    refitter ./openapi.json --simple-output
    refitter ./openapi.json --no-inline-json-converters
    refitter ./openapi.json --json-library-version 9.0

ARGUMENTS:
    [URL or input file]    URL or file path to OpenAPI Specification file

OPTIONS:
                                                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
        --property-naming-policy                PascalCase       Controls how generated contract properties are named. May be one of PascalCase, PreserveOriginal
    -o, --output                                Output.cs        Path to the generated file in single-file mode, or the output directory in multiple-file mode
        --contracts-output                                       Output directory 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
        --no-xml-doc-comments                                    Don't generate XML doc comments for interfaces and operations
        --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
        --ignored-operation-headers                              A collection of headers to omit from operation signatures. May be set multiple times
        --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.
                                                                 In this mode, --output and --contracts-output must be directory paths.
                                                                 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 where all instances of the string '{operationName}' is replaced with 'Execute'
        --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
        --include-inheritance-hierarchy                          Keep all possible inherited types/union types even if they are not directly used
        --no-banner                                              Don't show donation banner
        --simple-output                                          Generate simple, plain-text console output without ASCII art, tables, emojis, or color formatting (suitable for IDE output windows)
        --skip-default-additional-properties                     Set to true to skip default additional properties
        --allow-remote-refs                                      Resolve remote (http/https) $ref references inside the document. Disabled by default to prevent generation-time SSRF
        --collection-format                      Multi           Determines the format of collection parameters. May be one of Multi, Csv, Ssv, Tsv, Pipes
        --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.
                                                                 Replaces NSwag JsonInheritanceConverter attributes with System.Text.Json JsonPolymorphicAttributes.
                                                                 To have the native support of inheritance (de)serialization and fallback to base types when
                                                                 payloads with (yet) unknown types are offered by newer versions of an API
                                                                 See https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism for more information
        --disposable                                             Generate refit clients that implement IDisposable
        --json-serializer-context                                Generate JsonSerializerContext for AOT compilation support
        --no-inline-json-converters                              Don't inline JsonConverter attributes for enum types. When disabled, no [JsonConverter(typeof(JsonStringEnumConverter))] attributes are emitted. By default (enabled), the attribute is placed on the enum type declaration (not on properties), allowing custom converters to be registered via JsonSerializerOptions.Converters
        --integer-type                           int             The .NET type to use for OpenAPI integer types without a format specifier. Common values: 'int' (default), 'long'
        --json-library-version                                     JSON library version for System.Text.Json (default: 8.0). When set to 9.0 or higher, enables .NET 9+ JsonStringEnumMemberName support for custom enum value names. Cannot be used with a settings file that also specifies a non-default value
        --custom-template-directory                              Custom directory with NSwag fluid templates for code generation. Default is null which uses the default NSwag templates. See <https://github.com/RicoSuter/NSwag/wiki/Templates>
        --telemetry-source                                       Report the telemetry source of this invocation. Used internally by the MSBuild integration.
        --telemetry-file-count                                   Report the total number of settings files in the current workload. Used internally by the MSBuild integration.
        --telemetry-runtime                                      Report the bundled runtime selected for this invocation. Used internally by the MSBuild integration.
        --generate-authentication-header [STYLE]                  Controls generation of Authorization header support.
                                                                   Options: None (no authentication code is generated),
                                                                   Parameter (adds method parameters for authentication),
                                                                   Method (generates a Refit [Headers] attribute for bearer token authentication).
                                                                   Legacy boolean forms (true/false) and omitting the value are also accepted for compatibility.
        --security-scheme                                        Generate Authorization header for a specific security scheme. When omitted, authentication headers will be generated for all security schemes
```

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

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

This will generate a file called `Output.cs` which contains the Refit interface and contract classes generated using [NSwag](https://github.com/RicoSuter/NSwag)

### CLI Tool Output Example

Here's what the console output looks like when running the Refitter CLI tool:

![Console Output](images/console-output.png)

### Simple Output Mode

For integration with IDEs and build tools that don't support rich console formatting, Refitter provides a `--simple-output` option:

```shell
refitter ./openapi.json --simple-output
```

This mode generates plain text output without:

- ASCII art and banners
- Colored text and rich formatting
- Unicode characters and emojis
- Tables and panels

This is particularly useful when:

- Running Refitter from Visual Studio extensions
- Integrating with build systems that capture console output
- Using tools that don't support ANSI escape sequences
- Running in environments with limited console capabilities

### Property Naming Policy

Generated contract properties default to `PascalCase`. To preserve valid OpenAPI field names such as `payMethod_SumBank`, use `--property-naming-policy PreserveOriginal` or set `"propertyNamingPolicy": "PreserveOriginal"` in a `.refitter` file.

Refitter still emits `[JsonPropertyName]` attributes for serialization, escapes reserved C# keywords with `@`, and minimally sanitizes invalid identifiers into compilable names (for example `class` → `@class`, `123-value` → `_123_value`).

## Telemetry

Refitter collects anonymous usage telemetry and error reports to improve the tool. Telemetry can be disabled with `--no-logging`.

The following options are advanced/internal and are used by the MSBuild integration to tag telemetry with provenance:

- `--telemetry-source <value>` — reports the source of the invocation, e.g. `msbuild`. When set to `msbuild` (case-insensitive) a dedicated `msbuild-invocation` event is emitted.
- `--telemetry-file-count <n>` — reports the total number of settings files in the current workload.
- `--telemetry-runtime <tfm>` — reports the bundled runtime selected for this invocation, e.g. `net9.0`.

These values are self-reported and advisory because they are user-controlled CLI options: `--telemetry-source=msbuild` indicates the caller claims an MSBuild origin, not that one is proven. A caller that requires reliable attribution should hand off provenance through a protected, non-user-controlled channel instead of relying on these flags.

## .Refitter File format

The following is an example `.refitter` file using a single OpenAPI specification

```js
{
  "openApiPath": "/path/to/your/openAPI", // Required if openApiPaths is not specified
  "namespace": "Org.System.Service.Api.GeneratedCode", // Optional. Default=GeneratedCode
  "contractsNamespace": "Org.System.Service.Api.GeneratedCode.Contracts", // Optional. Default=GeneratedCode
  "propertyNamingPolicy": "PascalCase", // Optional. Values=PascalCase|PreserveOriginal. Default=PascalCase
  "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
  "generateJsonSerializerContext": false, // Optional. Default=false. Generate JsonSerializerContext for AOT compilation support
  "generateStatusCodeComments": true, // Optional. Default=true
  "addAutoGeneratedHeader": true, // Optional. Default=true
  "addAcceptHeaders": true, // Optional. Default=true
  "addContentTypeHeaders": true, // Optional. Default=true
  "returnIApiResponse": false, // Optional. Default=false
  "returnIObservable": false, // Optional. Default=false. Return IObservable instead of Task
  "responseTypeOverride": { // Optional. Default={}
    "File_Upload": "IApiResponse",
    "File_Download": "System.Net.Http.HttpContent"
  },
  "generateOperationHeaders": true, // Optional. Default=true
  "ignoredOperationHeaders": ["apiKey"], // Optional. Default=[]
  "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", this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute'
  "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.+"
  ],
  "includeInheritanceHierarchy": false, // Optional. Default=false. Set to true to keep all possible type-instances of inheritance/union types. This works in conjunction with trimUnusedSchema.
  "generateDefaultAdditionalProperties": true, // Optional. default=true
  "allowRemoteReferences": false, // Optional. Default=false. When true, remote http/https $ref references inside the document are resolved
  "operationNameGenerator": "Default", // Optional. May be one of Default, MultipleClientsFromOperationId, MultipleClientsFromPathSegments, MultipleClientsFromFirstTagAndOperationId, MultipleClientsFromFirstTagAndOperationName, MultipleClientsFromFirstTagAndPathSegments, SingleClientFromOperationId, SingleClientFromPathSegments
  "immutableRecords": false,
  "useDynamicQuerystringParameters": true, // Optional. Default=false
  "usePolymorphicSerialization": true, // Optional. Default=false
  "collectionFormat": "Multi", // Optional. Default=Multi. The collection format for array query parameters. Possible values: Multi, Csv, Ssv, Tsv, Pipes
  "contractTypeSuffix": null, // Optional. Default=null. Suffix to append to all generated contract type names (e.g., "Dto" would rename Pet to PetDto)
  "generateDisposableClients": true, // 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
    "useWindowsAuthentication": true, // Optional. Default=false
    "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",
    "integerType": "Int32", // Optional. Default="Int32". The .NET type for OpenAPI integers without a format. Possible values: "Int32", "Int64"
    "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,
    "inlineJsonConverters": true, // Optional. Default=true. Set to false to not generate JsonConverter attributes for enum properties
    "dateFormat": "yyyy-MM-dd",
    "dateTimeFormat": "yyyy-MM-dd",
    "excludedTypeNames": [
      "ExcludedTypeFoo",
      "ExcludedTypeBar"
    ],
    "customTemplateDirectory": "./path/to/directory/" // Optional. See <https://github.com/RicoSuter/NSwag/wiki/Templates>
    "jsonLibraryVersion": 8.0 // Optional. Default=8.0. JSON library version for System.Text.Json. When set to 9.0 or higher, enables .NET 9+ JsonStringEnumMemberName support for custom enum value names
  }
}
```

The following is an example `.refitter` file using multiple OpenAPI specifications that are merged into a single client

```js
{
  "openApiPaths": [ // Required if openApiPath is not specified. Documents are merged; first spec wins on duplicates
    "/path/to/your/openAPI/v1",
    "/path/to/your/openAPI/v2"
  ],
  "namespace": "Org.System.Service.Api.GeneratedCode"
}
```

- `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. Required if `openApiPaths` is not specified.
- `openApiPaths` - an array of paths to multiple OpenAPI Specifications files. When specified, the documents are merged into a single client. The first document in the array serves as the base; paths, component schemas, definitions (OpenAPI 2.x), and tags from subsequent documents are merged in. When duplicates exist (same path key or schema name), the first document's entry is preserved. Use this instead of `openApiPath` when you want to generate a single client from multiple API versions. Required if `openApiPath` is not specified.
- `namespace` - the namespace used in the generated code. If not specified, this defaults to `GeneratedCode`
- `propertyNamingPolicy` - controls how generated contract properties are named. Possible values are `PascalCase` (default) and `PreserveOriginal`. `PreserveOriginal` keeps valid identifiers as-is, escapes reserved C# keywords with `@`, and minimally sanitizes invalid names into compilable identifiers while still emitting `[JsonPropertyName]`
- `naming.useOpenApiTitle` - a boolean indicating whether the OpenApi title should be used. Default is `true`
- `naming.interfaceName` - the name of the generated interface. The generated code will automatically prefix this with `I` so if this set to `MyApiClient` then the generated interface is called `IMyApiClient`. Default is `ApiClient`
- `generateContracts` - a boolean indicating whether contracts should be generated. A use case for this is several API clients use the same contracts. Default is `true`
- `generateClients` - a boolean indicating whether clients should be generated. A use case for this is to separate clients and contracts into two separate generation runs. Default is `true`
- `generateDisposableClients` - a boolean indicating whether to generate clients that implement `IDisposable`. Default is `false`
- `generateXmlDocCodeComments` - a boolean indicating whether XML doc comments should be generated. Default is `true`
- `generateJsonSerializerContext` - a boolean indicating whether to generate a `JsonSerializerContext` for AOT compilation support. Default is `false`. The context is emitted in the contracts namespace and, in multi-file mode, is written to its own `*SerializerContext.cs` file
- `generateStatusCodeComments` - a boolean indicating whether the XML docs for `ApiException` and `IApiResponse` contain detailed descriptions for every documented status code. Default is `true`
- `addAutoGeneratedHeader` - a boolean indicating whether XML doc comments should be generated. Default is `true`
- `addAcceptHeaders` -  a boolean indicating whether to add accept headers [Headers("Accept: application/json")]. Default is `true`
- `addContentTypeHeaders` - a boolean indicating whether to add content type headers [Headers("Content-Type: application/json")]. Default is `true`
- `returnIApiResponse` - a boolean indicating whether to return `IApiResponse<T>` objects. Default is `false`
- `returnIObservable` - a boolean indicating whether to return `IObservable<T>` instead of `Task<T>`. Default is `false`
- `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 is `true`
- `ignoredOperationHeaders` - A collection of headers to omit from operation signatures. Default is `[]`
- `typeAccessibility` - the generated type accessibility. Possible values are `Public` and `Internal`. Default is `Public`
- `useCancellationTokens` - Use cancellation tokens in the generated methods. Default is `false`
- `useIsoDateFormat` - Set to `true` to explicitly format date query string parameters in ISO 8601 standard date format using delimiters (for example: 2023-06-15). Default is `false`
- `multipleInterfaces` - Set to `ByEndpoint` to generate an interface for each endpoint, or `ByTag` to group Endpoints by their Tag (like SwaggerUI groups them).
- `outputFolder` - a string describing a relative path to a desired output folder. In multi-file mode, this must be a directory path. Default is `./Generated`
- `outputFilename` - Output filename. Default is `Output.cs` when used from the CLI tool, otherwise its the .refitter filename. So `Petstore.refitter` becomes `Petstore.cs`.
- `contractsOutputFolder` - a string describing a relative path to the folder where contract files are generated. Enabling this automatically enables generating multiple files. This must be a directory path. Default is `NULL`
- `generateMultipleFiles` - a boolean indicating whether to generate multiple files instead of a single large file. Refit interface(s) are written to `RefitInterfaces.cs`, contracts to `Contracts.cs`, and dependency injection to `DependencyInjection.cs`. When using the CLI `--output` in this mode, provide a directory path. Default is `false`
- `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 is `true`
- `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. When using multiple interfaces with `ByEndpoint`, this is name of the Execute() method in the interface where all instances of the string '{operationName}' is replaced with 'Execute'
- `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 with `trimUnusedSchema`
- `includeInheritanceHierarchy`: Set to true to keep all possible type-instances of inheritance/union types. If this is false only directly referenced types will be kept. This works in conjunction with `trimUnusedSchema`
- `allowRemoteReferences` - a boolean controlling whether remote (`http`/`https`) `$ref` references inside the OpenAPI document are resolved. Disabled by default to prevent generation-time SSRF and remote file inclusion. Local `$ref` references are always confined to the input document's directory tree. Top-level remote document URLs remain allowed. Default is `false`
- `generateDefaultAdditionalProperties`: Set to `false` to skip default additional properties. Default is `true`
- `operationNameGenerator`: The NSwag `IOperationNameGenerator` implementation to use. See <https://refitter.github.io/api/Refitter.Core.OperationNameGeneratorTypes.html>
- `immutableRecords`: Set to `true` to generate contracts as immutable records instead of classes. Default is `false`
- `useDynamicQuerystringParameters`: Set to `true` to wrap multiple query parameters into a single complex one. Default is `false` (no wrapping). See <https://github.com/reactiveui/refit?tab=readme-ov-file#dynamic-querystring-parameters> for more information.
- `usePolymorphicSerialization`: Set to `true` to use System.Text.Json polymorphic serialization. Replaces NSwag `JsonInheritanceConverter` attributes with `System.Text.Json` `JsonPolymorphicAttributes`. Default is `false`. See <https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism>
- `collectionFormat` - The collection format for array query parameters. Possible values: `Multi`, `Csv`, `Ssv`, `Tsv`, `Pipes`. Default is `Multi`
- `contractTypeSuffix` - An optional suffix to append to all generated contract type names. For example, setting this to `Dto` would rename `Pet` to `PetDto`. Default is `null` (no suffix)
- `dependencyInjectionSettings` - Setting this will generated extension methods to `IServiceCollection` for configuring Refit clients, including optional Windows Authentication support
  - `baseUrl` - Used as the HttpClient base address. Leave this blank to manually set the base URL
  - `httpMessageHandlers` - A collection of `HttpMessageHandler` that is added to the HttpClient pipeline
  - `usePolly` - Set this to `true` to configure the HttpClient to use Polly using a retry policy with a jittered backoff.  This is **DEPRECATED**, use `transientErrorHandler` instead
  - `transientErrorHandler`: Set this to configure transient error handling with a retry policy that uses a jittered backoff. See <https://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. See <https://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 is `object`,
  - `dateType` - Default is `System.DateTimeOffset`,
  - `dateTimeType` - Default is `System.DateTimeOffset`,
  - `timeType` - Default is `System.TimeSpan`,
  - `timeSpanType` - Default is `System.TimeSpan`,
  - `arrayType` - Default is `System.Collections.Generic.ICollection`,
  - `dictionaryType` - Default is `System.Collections.Generic.IDictionary`,
  - `arrayInstanceType` - Default is `System.Collections.ObjectModel.Collection`,
  - `dictionaryInstanceType` - Default is `System.Collections.Generic.Dictionary`,
  - `arrayBaseType` - Default is `System.Collections.ObjectModel.Collection`,
  - `dictionaryBaseType` - Default is `System.Collections.Generic.Dictionary`,
  - `integerType` - Default is `Int32`. The .NET type to use for OpenAPI integer types without a format specifier. Possible values: `Int32`, `Int64`
  - `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. Set this explicitly when you want optional contract properties to become nullable
  - `generateNullableReferenceTypes` - Default is false. This does not implicitly enable `generateOptionalPropertiesAsNullable`
  - `generateNativeRecords` - Default is false
  - `generateDefaultValues` - Default is true
  - `inlineNamedAny` - Default is false
  - `inlineJsonConverters` - Default is true. When set to false, enum properties will not have `[JsonConverter(typeof(JsonStringEnumConverter))]` attributes
  - `dateFormat` - Default is null
  - `dateTimeFormat` - Default is null
  - `excludedTypeNames` - Default is empty
  - `jsonLibraryVersion` - Default is `8.0`. JSON library version for System.Text.Json. When set to `9.0` or higher, enables .NET 9+ `JsonStringEnumMemberName` support for custom enum value names

## MSBuild

This is the recommended approach for generating code from OpenAPI specifications at build time. The MSBuild approach integrates seamlessly into your build pipeline, automatically generates code at build time

### Why Choose MSBuild over Source Generator?

The MSBuild task offers several advantages over the Source Generator:

- **Build-time Generation**: Code is generated during the pre-build process, which ensures that the Refit source generator will work without needing to rebuild a second time.
- **No Manual Commits**: Generated files are created automatically during build, eliminating the need to commit generated code to source control
- **No Additional Tools Required**: Works out of the box without requiring separate CLI tool installation

### Installation

The MSBuild task is distributed as a NuGet package:

```shell
dotnet add package Refitter.MSBuild
```

### Usage

Once installed, the MSBuild task will automatically scan your project for `.refitter` files and generate code during build. Simply create a `.refitter` file in your project directory with your OpenAPI specification settings.

The MSBuild package includes a custom `.target` file which executes the `RefitterGenerateTask` custom task:

```xml
<UsingTask TaskName="RefitterGenerateTask"
           AssemblyFile="$(MSBuildThisFileDirectory)Refitter.MSBuild.dll"
           Condition="Exists('$(MSBuildThisFileDirectory)Refitter.MSBuild.dll')" />
<Target Name="RefitterGenerate" BeforeTargets="BeforeCompile">
    <RefitterGenerateTask ProjectFileDirectory="$(MSBuildProjectDirectory)"
                          DisableLogging="$(RefitterNoLogging)"
                          SkipValidation="$(RefitterSkipValidation)">
        <Output TaskParameter="GeneratedFiles" ItemName="RefitterGeneratedFiles" />
    </RefitterGenerateTask>
    <ItemGroup>
        <Compile Include="@(RefitterGeneratedFiles)" />
    </ItemGroup>
</Target>
```

The `RefitterGenerateTask` task will scan the project folder for `.refitter` files and execute them all.

### Configuration

By default, telemetry collection is enabled. To opt-out, add the following to your `.csproj` file:

```xml
<PropertyGroup>
  <RefitterNoLogging>true</RefitterNoLogging>
</PropertyGroup>
```

You can also skip OpenAPI validation by setting:

```xml
<PropertyGroup>
  <RefitterSkipValidation>true</RefitterSkipValidation>
</PropertyGroup>
```

To limit MSBuild generation to specific `.refitter` files, set `RefitterIncludePatterns` to a semicolon-separated list of exact file names, exact project-relative paths, or exact full paths:

```xml
<PropertyGroup>
  <RefitterIncludePatterns>petstore.refitter;apis\admin.refitter</RefitterIncludePatterns>
</PropertyGroup>
```

`RefitterIncludePatterns` uses exact matching only against the file name, project-relative path, or full path. It does not do substring matching or wildcard matching, so `petstore` will not match `petstore.refitter`.

### Example

Create a `.refitter` file in your project:

```json
{
  "openApiPath": "https://petstore3.swagger.io/api/v3/openapi.json",
  "namespace": "Petstore.Api",
  "outputFolder": "./Generated"
}
```

Now, every time you build your project, Refitter will automatically generate the API client code based on your OpenAPI specification.

### Alternative: Using CLI with MSBuild Exec Task

If you prefer more control or need to use the CLI tool directly, you can invoke the Refitter CLI from MSBuild pre-build events:

```xml
<Target Name="Refitter" AfterTargets="PreBuildEvent">
    <Exec WorkingDirectory="$(ProjectDir)" Command="dotnet tool restore" />
    <Exec WorkingDirectory="$(ProjectDir)" Command="refitter --settings-file .refitter --skip-validation" />
</Target>
```

This approach requires that Refitter is installed as a local tool using a manifest file, as described in [this tutorial](https://learn.microsoft.com/en-us/dotnet/core/tools/local-tools-how-to-use?WT.mc_id=DT-MVP-5004822).

## Source Generator

> **Note:** We recommend using the [MSBuild](#msbuild) approach instead of the Source Generator because the code is generated at pre-compile, ensuring that the Refit source generator will generated code from the Refit interfaces added to the compilation

Refitter is available as a C# Source Generator that uses the [Refitter.Core](https://github.com/christianhelle/refitter/tree/main/src/Refitter.Core) library for generating a REST API Client using the [Refit](https://github.com/reactiveui/refit) library. Refitter can generate the Refit interface from OpenAPI specifications. Refitter could format the generated Refit interface to be managed by [Apizr](https://www.apizr.net) and generate some registration helpers too.

### Installation

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

```shell
dotnet add package Refitter.SourceGenerator
dotnet add package Refit
```

`Refitter.SourceGenerator` keeps its `Refit` dependency private, so consuming projects must add their own direct package reference to `Refit`. If you use generated dependency-injection helpers such as `ConfigureRefitClients()`, also add `Refit.HttpClientFactory` explicitly.

### Usage

After installing the package, add one or more `.refitter` files to your project.

`Refitter.SourceGenerator` automatically includes `**/*.refitter` as Roslyn `AdditionalFiles` via its package props, so you do not need to add manual `<AdditionalFiles Include="..." />` entries unless you intentionally override that default behavior.

# Using the generated code

Here's an example generated output from the [Swagger Petstore example](https://petstore3.swagger.io) using the default settings

**CLI Tool**

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

**Source Generator ***.refitter*** file**

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

**Output (Snippet)**

Full output is available [here](docs/DefaultOutput.cs)

```cs
using Refit;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace Your.Namespace.Of.Choice.GeneratedCode
{
    [System.CodeDom.Compiler.GeneratedCode("Refitter", "1.0.0.0")]
    public partial interface ISwaggerPetstore
    {
        /// <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] Pet body);

        ...
    }
}
```

Here's an example generated output from the [Swagger Petstore example](https://petstore3.swagger.io) configured to wrap the return type in `IApiResponse<T>`

**CLI Tool**

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

**Source Generator ***.refitter*** file**

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

**Output (Snippet)**

Full output is available [here](docs/IApiResponseOutput.cs)

```cs
using Refit;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace Your.Namespace.Of.Choice.GeneratedCode
{
    [System.CodeDom.Compiler.GeneratedCode("Refitter", "1.0.0.0")]
    public partial interface ISwaggerPetstore
    {
        /// <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] Pet body);

        ...
    }
}
```

Here's an example generated output from the [Swagger Petstore example](https://petstore3.swagger.io) configured to generate an interface for each endpoint

**CLI Tool**

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

**Source Generator ***.refitter*** file**

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

**Output (Snippet)**

Full output is available [here](docs/IApiResponseOutput.cs)

```cs
/// <summary>Update an existing pet</summary>
[System.CodeDom.Compiler.GeneratedCode("Refitter", "1.0.0.0")]
public partial interface IUpdatePetEndpoint
{
    /// <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] Pet body);
}
```

Here's an example generated output from the [Swagger Petstore example](https://petstore3.swagger.io) configured to generate an interface with dynamic querystring parameters

**CLI Tool**

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

**Output (Snippet)**

Full output is available [here](docs/DynamicQueryStringParameters.cs)

```cs
[System.CodeDom.Compiler.GeneratedCode("Refitter", "1.0.0.0")]
public partial interface ISwaggerPetstoreOpenAPI30
{
    /// <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}")]
    Task UpdatePetWithForm(long petId, [Query] UpdatePetWithFormQueryParams queryParams);
}

public class UpdatePetWithFormQueryParams
{
    /// <summary>
    /// Name of pet that needs to be updated
    /// </summary>
    [Query]
    public string Name { get; set; }

    /// <summary>
    /// Status of pet that needs to be updated
    /// </summary>
    [Query]
    public string Status { get; set; }
}
```

## RestService

Here's an example usage of the generated code above

```cs
using Refit;
using System;
using System.Threading.Tasks;

namespace Your.Namespace.Of.Choice.GeneratedCode;

internal class Program
{
    private static async Task Main(string[] args)
    {
        var client = RestService.For<ISwaggerPetstore>("https://petstore3.swagger.io/api/v3");
        var pet = await client.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();

        var client2 = RestService.For<WithApiResponse.ISwaggerPetstore>("https://petstore3.swagger.io/api/v3");
        var response = await client2.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}");
    }
}
```

The `RestService` class generates an implementation of `ISwaggerPetstore` that uses `HttpClient` to make its calls.

The code above when run will output something like this:

```
## Using Task<T> as return type ##
Name: Gatitotototo
Category: Chaucito
Status: Sold

## Using Task<IApiResponse<T>> as return type ##
HTTP Status Code: OK
Name: Gatitotototo
Category: Chaucito
Status: Sold
```

## ASP.NET Core and HttpClientFactory

Here's an example Minimal API with the [`Refit.HttpClientFactory`](https://www.nuget.org/packages/Refit.HttpClientFactory) library:

```cs
using Refit;
using Your.Namespace.Of.Choice.GeneratedCode;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services
    .AddRefitClient<ISwaggerPetstore>()
    .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://petstore3.swagger.io/api/v3"));

var app = builder.Build();
app.MapGet(
        "/pet/{id:long}",
        async (ISwaggerPetstore petstore, long id) =>
        {
            try
            {
                return Results.Ok(await petstore.GetPetById(id));
            }
            catch (Refit.ApiException e)
            {
                return Results.StatusCode((int)e.StatusCode);
            }
        })
    .WithName("GetPetById")
    .WithOpenApi();

app.UseHttpsRedirection();
app.UseSwaggerUI();
app.UseSwagger();
app.Run();
```

.NET Core supports registering the generated `ISwaggerPetstore` interface via `HttpClientFactory`

The following request to the API above

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

Returns a response that looks something like this:

```json
{
  "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 to `IServiceCollection`.

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

```json
{
  "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 to `IServiceCollection` called `ConfigureRefitClients()`. The generated extension method depends on [`Refit.HttpClientFactory`](https://www.nuget.org/packages/Refit.HttpClientFactory) library and looks like this:

```cs
public static IServiceCollection ConfigureRefitClients(
    this IServiceCollection services,
    Action<IHttpClientBuilder>? builder = default,
    RefitSettings? settings = default)
{
    var clientBuilderISwaggerPetstore = services
        .AddRefitClient<ISwaggerPetstore>(settings)
        .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://petstore3.swagger.io/api/v3"))
        .AddHttpMessageHandler<TelemetryDelegatingHandler>();

    clientBuilderISwaggerPetstore
        .AddPolicyHandler(
            HttpPolicyExtensions
                .HandleTransientHttpError()
                .WaitAndRetryAsync(
                    Backoff.DecorrelatedJitterBackoffV2(
                        TimeSpan.FromSeconds(0.5),
                        3)));

    builder?.Invoke(clientBuilderISwaggerPetstore);

    return services;
}
```

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

```json
{
  "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 single `ConfigureRefitClients()` extension methods that may contain dependency injection configuration code for multiple interfaces like this

```csharp
public static IServiceCollection ConfigureRefitClients(
    this IServiceCollection services,
    Action<IHttpClientBuilder>? builder = default,
    RefitSettings? settings = default)
{
    var clientBuilderIPetApi = services
        .AddRefitClient<IPetApi>(settings)
        .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://petstore3.swagger.io/api/v3"))
        .AddHttpMessageHandler<TelemetryDelegatingHandler>();

    clientBuilderIPetApi
        .AddPolicyHandler(
            HttpPolicyExtensions
                .HandleTransientHttpError()
                .WaitAndRetryAsync(
                    Backoff.DecorrelatedJitterBackoffV2(
                        TimeSpan.FromSeconds(0.5),
                        3)));

    builder?.Invoke(clientBuilderIPetApi);

    var clientBuilderIStoreApi = services
        .AddRefitClient<IStoreApi>(settings)
        .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://petstore3.swagger.io/api/v3"))
        .AddHttpMessageHandler<TelemetryDelegatingHandler>();

    clientBuilderIStoreApi
        .AddPolicyHandler(
            HttpPolicyExtensions
                .HandleTransientHttpError()
                .WaitAndRetryAsync(
                    Backoff.DecorrelatedJitterBackoffV2(
                        TimeSpan.FromSeconds(0.5),
                        3)));

    builder?.Invoke(clientBuilderIStoreApi);

    var clientBuilderIUserApi = services
        .AddRefitClient<IUserApi>(settings)
        .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://petstore3.swagger.io/api/v3"))
        .AddHttpMessageHandler<TelemetryDelegatingHandler>();

    clientBuilderIUserApi
        .AddPolicyHandler(
            HttpPolicyExtensions
                .HandleTransientHttpError()
                .WaitAndRetryAsync(
                    Backoff.DecorrelatedJitterBackoffV2(
                        TimeSpan.FromSeconds(0.5),
                        3)));

    builder?.Invoke(clientBuilderIUserApi);

    return services;
}
```

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](https://www.apizr.net) 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 the `apizrSettings` section in the `.refitter` settings file

Note that `--use-apizr` uses default Apizr settings with `withRequestOptions` set to `true` 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 (if `withRequestOptions` is set to `true`)
- Providing cancellation tokens by Apizr request options instead of a dedicated parameter (if `withRequestOptions` is set to `true`)
- Using method overloads instead of optional parameters (note that setting `useDynamicQuerystringParameters` to `true` improve overloading experience)

From here, you're definitely free to use the formatted interface with Apizr by registering, configuring and using it following the [Apizr documentation](https://www.apizr.net). 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 to `IServiceCollection` if DependencyInjectionSettings are set, or a static builder method if not.

### [Extended](#tab/tabid-extended)

To enable Apizr registration code generation for `IServiceCollection`, you need at least to set the `withRegistrationHelper` property to `true` and configure the `DependencyInjectionSettings` section in the `.refitter` settings file.
This is what the `.refitter` settings file may look like, depending on you configuration:

```json
{
  "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 to `IServiceCollection` called `ConfigurePetstoreApiApizrManager()`. The generated extension method depends on [`Apizr.Extensions.Microsoft.DependencyInjection`](https://www.nuget.org/packages/Apizr.Extensions.Microsoft.DependencyInjection) library and looks like this:

```cs
public static IServiceCollection ConfigurePetstoreApiApizrManager(
    this IServiceCollection services,
    Action<IApizrExtendedManagerOptionsBuilder>? optionsBuilder = null)
{
    optionsBuilder ??= _ => { }; // Default empty options if null
    optionsBuilder += options => options
        .WithBaseAddress("https://petstore3.swagger.io/api/v3", ApizrDuplicateStrategy.Ignore)
        .WithDelegatingHandler<MyDelegatingHandler>()
        .ConfigureHttpClientBuilder(builder => builder
            .AddStandardResilienceHandler(config =>
            {
                config.Retry = new HttpRetryStrategyOptions
                {
                    UseJitter = true,
                    MaxRetryAttempts = 3,
                    Delay = TimeSpan.FromSeconds(0.5)
                };
            }))
        .WithInMemoryCacheHandler()
        .WithAutoMapperMappingHandler()
        .WithPriority()
        .WithOptionalMediation()
        .WithFileTransferOptionalMediation();

    return services.AddApizrManagerFor<IPetstoreApi>(optionsBuilder);
}
```

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

```json
{
  "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 single `ConfigurePetstoreApizrManagers()` extension method that may contain dependency injection configuration code for multiple interfaces like this

```csharp
public static IServiceCollection ConfigurePetstoreApizrManagers(
    this IServiceCollection services,
    Action<IApizrExtendedCommonOptionsBuilder>? optionsBuilder = null)
{
    optionsBuilder ??= _ => { }; // Default empty options if null
    optionsBuilder += options => options
        .WithBaseAddress("https://petstore3.swagger.io/api/v3", ApizrDuplicateStrategy.Ignore)
        .WithDelegatingHandler<MyDelegatingHandler>()
        .ConfigureHttpClientBuilder(builder => builder
            .AddStandardResilienceHandler(config =>
            {
                config.Retry = new HttpRetryStrategyOptions
                {
                    UseJitter = true,
                    MaxRetryAttempts = 3,
                    Delay = TimeSpan.FromSeconds(0.5)
                };
            }))
        .WithInMemoryCacheHandler()
        .WithAutoMapperMappingHandler()
        .WithPriority()
        .WithOptionalMediation()
        .WithFileTransferOptionalMediation();

    return services.AddApizr(
        registry => registry
            .AddManagerFor<IPetApi>()
            .AddManagerFor<IStoreApi>()
            .AddManagerFor<IUserApi>(),
        optionsBuilder);

}
```

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

### [Static](#tab/tabid-static)

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

```json
{
  "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 called `BuildPetstore30ApizrManager()`. The generated builder method depends on [`Apizr`](https://www.nuget.org/packages/Apizr) library and looks like this:

```cs
public static IApizrManager<ISwaggerPetstoreOpenAPI30> BuildPetstore30ApizrManager(Action<IApizrManagerOptionsBuilder> optionsBuilder)
{
    optionsBuilder ??= _ => { }; // Default empty options if null
    optionsBuilder += options => options
        .WithAkavacheCacheHandler()
        .WithAutoMapperMappingHandler(new MapperConfiguration(config => { /* YOUR_MAPPINGS_HERE */ }))
        .WithPriority();

    return ApizrBuilder.Current.CreateManagerFor<ISwaggerPetstoreOpenAPI30>(optionsBuilder);
}
```

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

```json
{
  "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 single `BuildPetstoreApizrManagers()` builder method that may contain configuration code for multiple interfaces like this

```csharp
public static IApizrRegistry BuildPetstoreApizrManagers(Action<IApizrCommonOptionsBuilder> optionsBuilder)
{
    optionsBuilder ??= _ => { }; // Default empty options if null
    optionsBuilder += options => options
        .WithAkavacheCacheHandler()
        .WithAutoMapperMappingHandler(new MapperConfiguration(config => { /* YOUR_MAPPINGS_HERE */ }))
        .WithPriority();

    return ApizrBuilder.Current.CreateRegistry(
        registry => registry
            .AddManagerFor<IPetApi>()
            .AddManagerFor<IStoreApi>()
            .AddManagerFor<IUserApi>(),
        optionsBuilder);
}
```

Here, `IPetApi`, `IStoreApi` and `IUserApi` 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 the `Action<TApizrOptionsBuilder>` parameter while calling the generated method.
To know how to make Apizr fit your needs, please refer to the [Apizr documentation](https://www.apizr.net).

### Using the managers

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

```csharp
var result = await petstoreManager.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 the [Apizr documentation](https://www.apizr.net) to get more.

## System requirements

.NET 8.0 or .NET 9.0

## Testing

Refitter uses [TUnit](https://github.com/thomhurst/TUnit) as its testing framework instead of xUnit. TUnit was chosen for its superior performance, providing 3x faster test execution compared to xUnit. This significantly improves the developer experience when running the test suite locally and in CI/CD pipelines.

To run the tests:

```bash
dotnet test --solution src/Refitter.slnx -c Release
```

## Contributing

Please read our [contribution guidelines](CONTRIBUTING.md) if you'd like to contribute to the project.

## Contributors

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
  <tbody>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/neoGeneva"><img src="https://avatars.githubusercontent.com/u/804724?v=4?s=100" width="100px;" alt="Philip Cox"/><br /><sub><b>Philip Cox</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=neoGeneva" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://cam.macfar.land/"><img src="https://avatars.githubusercontent.com/u/1298847?v=4?s=100" width="100px;" alt="Cameron MacFarland"/><br /><sub><b>Cameron MacFarland</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=distantcam" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://kgame.tw"><img src="https://avatars.githubusercontent.com/u/3646532?v=4?s=100" width="100px;" alt="kgame"/><br /><sub><b>kgame</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=kgamecarter" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://yrki.no"><img src="https://avatars.githubusercontent.com/u/11573601?v=4?s=100" width="100px;" alt="Thomas Pettersen / Yrki"/><br /><sub><b>Thomas Pettersen / Yrki</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/1kvin"><img src="https://avatars.githubusercontent.com/u/46425980?v=4?s=100" width="100px;" alt="Artem"/><br /><sub><b>Artem</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3A1kvin" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/m7clarke"><img src="https://avatars.githubusercontent.com/u/47439144?v=4?s=100" width="100px;" alt="m7clarke"/><br /><sub><b>m7clarke</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Am7clarke" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/kirides"><img src="https://avatars.githubusercontent.com/u/13602143?v=4?s=100" width="100px;" alt="kirides"/><br /><sub><b>kirides</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Akirides" title="Bug reports">🐛</a> <a href="https://github.com/christianhelle/refitter/commits?author=kirides" title="Code">💻</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/guillaumeserale"><img src="https://avatars.githubusercontent.com/u/6672406?v=4?s=100" width="100px;" alt="guillaumeserale"/><br /><sub><b>guillaumeserale</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=guillaumeserale" title="Code">💻</a> <a href="https://github.com/christianhelle/refitter/issues?q=author%3Aguillaumeserale" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Roflincopter"><img src="https://avatars.githubusercontent.com/u/1690243?v=4?s=100" width="100px;" alt="Dennis Brentjes"/><br /><sub><b>Dennis Brentjes</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=Roflincopter" title="Code">💻</a> <a href="#ideas-Roflincopter" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/hickeydamian/"><img src="https://avatars.githubusercontent.com/u/57436?v=4?s=100" width="100px;" alt="Damian Hickey"/><br /><sub><b>Damian Hickey</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Adamianh" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/richardhu-lmg"><img src="https://avatars.githubusercontent.com/u/126430787?v=4?s=100" width="100px;" alt="richardhu-lmg"/><br /><sub><b>richardhu-lmg</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Arichardhu-lmg" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/brease-colin"><img src="https://avatars.githubusercontent.com/u/47358935?v=4?s=100" width="100px;" alt="brease-colin"/><br /><sub><b>brease-colin</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Abrease-colin" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/angelofb"><img src="https://avatars.githubusercontent.com/u/2032257?v=4?s=100" width="100px;" alt="angelofb"/><br /><sub><b>angelofb</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=angelofb" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/NoGRo"><img src="https://avatars.githubusercontent.com/u/5665273?v=4?s=100" width="100px;" alt="Dim Nogro"/><br /><sub><b>Dim Nogro</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=NoGRo" title="Code">💻</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/yadanilov19"><img src="https://avatars.githubusercontent.com/u/17161065?v=4?s=100" width="100px;" alt="yadanilov19"/><br /><sub><b>yadanilov19</b></sub></a><br /><a href="#ideas-yadanilov19" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/christianhelle/refitter/commits?author=yadanilov19" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/danpowell88"><img src="https://avatars.githubusercontent.com/u/1100397?v=4?s=100" width="100px;" alt="Daniel Powell"/><br /><sub><b>Daniel Powell</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Adanpowell88" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Ekkeir"><img src="https://avatars.githubusercontent.com/u/36194685?v=4?s=100" width="100px;" alt="Ekkeir"/><br /><sub><b>Ekkeir</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=Ekkeir" title="Documentation">📖</a> <a href="https://github.com/christianhelle/refitter/issues?q=author%3AEkkeir" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/waylonmtz"><img src="https://avatars.githubusercontent.com/u/4604579?v=4?s=100" width="100px;" alt="Waylon Martinez"/><br /><sub><b>Waylon Martinez</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Awaylonmtz" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/vinaymadupathi"><img src="https://avatars.githubusercontent.com/u/38102900?v=4?s=100" width="100px;" alt="vkmadupa"/><br /><sub><b>vkmadupa</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Avinaymadupathi" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Noblix"><img src="https://avatars.githubusercontent.com/u/22076883?v=4?s=100" width="100px;" alt="Noblix"/><br /><sub><b>Noblix</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=Noblix" title="Code">💻</a> <a href="#ideas-Noblix" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://www.veezla.io"><img src="https://avatars.githubusercontent.com/u/230432?v=4?s=100" width="100px;" alt="Attila Hajdrik"/><br /><sub><b>Attila Hajdrik</b></sub></a><br /><a href="#ideas-attilah" title="Ideas, Planning, & Feedback">🤔</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/bielik01"><img src="https://avatars.githubusercontent.com/u/920950?v=4?s=100" width="100px;" alt="bielik01"/><br /><sub><b>bielik01</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Abielik01" title="Bug reports">🐛</a> <a href="#ideas-bielik01" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/naaeef"><img src="https://avatars.githubusercontent.com/u/43339071?v=4?s=100" width="100px;" alt="naaeef"/><br /><sub><b>naaeef</b></sub></a><br /><a href="#ideas-naaeef" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/alrz"><img src="https://avatars.githubusercontent.com/u/3105979?v=4?s=100" width="100px;" alt="Alireza Habibi"/><br /><sub><b>Alireza Habibi</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Aalrz" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/EEParker"><img src="https://avatars.githubusercontent.com/u/15874076?v=4?s=100" width="100px;" alt="Jeff Parker, PE"/><br /><sub><b>Jeff Parker, PE</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3AEEParker" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/jods4"><img src="https://avatars.githubusercontent.com/u/3832820?v=4?s=100" width="100px;" alt="jods"/><br /><sub><b>jods</b></sub></a><br /><a href="#ideas-jods4" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/christianhelle/refitter/issues?q=author%3Ajods4" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/edimarquez"><img src="https://avatars.githubusercontent.com/u/41791719?v=4?s=100" width="100px;" alt="Edimarquez Medeiros"/><br /><sub><b>Edimarquez Medeiros</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=edimarquez" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/safakkesikci"><img src="https://avatars.githubusercontent.com/u/7067252?v=4?s=100" width="100px;" alt="safakkesikci"/><br /><sub><b>safakkesikci</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Asafakkesikci" title="Bug reports">🐛</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/folbrecht"><img src="https://avatars.githubusercontent.com/u/145537846?v=4?s=100" width="100px;" alt="folbrecht"/><br /><sub><b>folbrecht</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Afolbrecht" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/mortenlaursen"><img src="https://avatars.githubusercontent.com/u/28759737?v=4?s=100" width="100px;" alt="mortenlaursen"/><br /><sub><b>mortenlaursen</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=mortenlaursen" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/manuel-fernandez-rodriguez"><img src="https://avatars.githubusercontent.com/u/48520205?v=4?s=100" width="100px;" alt="manuel-fernandez-rodriguez"/><br /><sub><b>manuel-fernandez-rodriguez</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Amanuel-fernandez-rodriguez" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/eliyammine"><img src="https://avatars.githubusercontent.com/u/6644807?v=4?s=100" width="100px;" alt="Eli Yammine"/><br /><sub><b>Eli Yammine</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Aeliyammine" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/kami-poi"><img src="https://avatars.githubusercontent.com/u/47322691?v=4?s=100" width="100px;" alt="kami-poi"/><br /><sub><b>kami-poi</b></sub></a><br /><a href="#ideas-kami-poi" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Xeevis"><img src="https://avatars.githubusercontent.com/u/5835044?v=4?s=100" width="100px;" alt="Xeevis"/><br /><sub><b>Xeevis</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3AXeevis" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/DJ4ddi"><img src="https://avatars.githubusercontent.com/u/1696102?v=4?s=100" width="100px;" alt="DJ4ddi"/><br /><sub><b>DJ4ddi</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=DJ4ddi" title="Code">💻</a> <a href="#ideas-DJ4ddi" title="Ideas, Planning, & Feedback">🤔</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/direncancatalkaya"><img src="https://avatars.githubusercontent.com/u/57223732?v=4?s=100" width="100px;" alt="direncancatalkaya"/><br /><sub><b>direncancatalkaya</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=direncancatalkaya" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/robpalm"><img src="https://avatars.githubusercontent.com/u/14939530?v=4?s=100" width="100px;" alt="Robert Palmqvist"/><br /><sub><b>Robert Palmqvist</b></sub></a><br /><a href="#ideas-robpalm" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/christianhelle/refitter/commits?author=robpalm" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/TimothyMakkison"><img src="https://avatars.githubusercontent.com/u/49349513?v=4?s=100" width="100px;" alt="Tim M"/><br /><sub><b>Tim M</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=TimothyMakkison" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/janfolbrecht"><img src="https://avatars.githubusercontent.com/u/42186604?v=4?s=100" width="100px;" alt="janfolbrecht"/><br /><sub><b>janfolbrecht</b></sub></a><br /><a href="#ideas-janfolbrecht" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/christianhelle/refitter/commits?author=janfolbrecht" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/osc-nseguin"><img src="https://avatars.githubusercontent.com/u/133910309?v=4?s=100" width="100px;" alt="Nick Seguin"/><br /><sub><b>Nick Seguin</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=osc-nseguin" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/david-brink-talogy"><img src="https://avatars.githubusercontent.com/u/43828739?v=4?s=100" width="100px;" alt="David Brink"/><br /><sub><b>David Brink</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Adavid-brink-talogy" title="Bug reports">🐛</a> <a href="https://github.com/christianhelle/refitter/commits?author=david-brink-talogy" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/dammitjanet"><img src="https://avatars.githubusercontent.com/u/952723?v=4?s=100" width="100px;" alt="Stu Wilson"/><br /><sub><b>Stu Wilson</b></sub></a><br /><a href="#ideas-dammitjanet" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/christianhelle/refitter/commits?author=dammitjanet" title="Code">💻</a> <a href="https://github.com/christianhelle/refitter/issues?q=author%3Adammitjanet" title="Bug reports">🐛</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/sharpzilla"><img src="https://avatars.githubusercontent.com/u/16763634?v=4?s=100" width="100px;" alt="sharpzilla"/><br /><sub><b>sharpzilla</b></sub></a><br /><a href="#ideas-sharpzilla" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Jappinen"><img src="https://avatars.githubusercontent.com/u/44408497?v=4?s=100" width="100px;" alt="Tatu"/><br /><sub><b>Tatu</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3AJappinen" title="Bug reports">🐛</a> <a href="#ideas-Jappinen" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://www.respawnsive.com"><img src="https://avatars.githubusercontent.com/u/4272307?v=4?s=100" width="100px;" alt="Jérémy BRUN-PICARD"/><br /><sub><b>Jérémy BRUN-PICARD</b></sub></a><br /><a href="#ideas-JeremyBP" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/christianhelle/refitter/commits?author=JeremyBP" title="Code">💻</a> <a href="https://github.com/christianhelle/refitter/commits?author=JeremyBP" title="Documentation">📖</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/ebarnard"><img src="https://avatars.githubusercontent.com/u/1059683?v=4?s=100" width="100px;" alt="Ed Barnard"/><br /><sub><b>Ed Barnard</b></sub></a><br /><a href="#ideas-ebarnard" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/bastiennoel93"><img src="https://avatars.githubusercontent.com/u/18250350?v=4?s=100" width="100px;" alt="bastien.noel"/><br /><sub><b>bastien.noel</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Abastiennoel93" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/MeikelLP"><img src="https://avatars.githubusercontent.com/u/11669846?v=4?s=100" width="100px;" alt="Meikel Philipp"/><br /><sub><b>Meikel Philipp</b></sub></a><br /><a href="#ideas-MeikelLP" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://berkselvi.dev"><img src="https://avatars.githubusercontent.com/u/54676516?v=4?s=100" width="100px;" alt="Berk Selvi"/><br /><sub><b>Berk Selvi</b></sub></a><br /><a href="#ideas-berkslv" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/christianhelle/refitter/commits?author=berkslv" title="Code">💻</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://www.thebuildsheet.com/"><img src="https://avatars.githubusercontent.com/u/9909564?v=4?s=100" width="100px;" alt="Joshua Ozeri"/><br /><sub><b>Joshua Ozeri</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3AXeClutch" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://kancane.nl/"><img src="https://avatars.githubusercontent.com/u/701534?v=4?s=100" width="100px;" alt="Ryan Heath"/><br /><sub><b>Ryan Heath</b></sub></a><br /><a href="#ideas-ryanheath" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/christianhelle/refitter/commits?author=ryanheath" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Briaoeuidhtns"><img src="https://avatars.githubusercontent.com/u/7530156?v=4?s=100" width="100px;" alt="Brian Brunner"/><br /><sub><b>Brian Brunner</b></sub></a><br /><a href="#ideas-Briaoeuidhtns" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/fsamiec"><img src="https://avatars.githubusercontent.com/u/13166020?v=4?s=100" width="100px;" alt="Frank Samiec"/><br /><sub><b>Frank Samiec</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=fsamiec" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/fabioloreggian"><img src="https://avatars.githubusercontent.com/u/31480768?v=4?s=100" width="100px;" alt="Fabio Loreggian"/><br /><sub><b>Fabio Loreggian</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Afabioloreggian" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/geometrikal"><img src="https://avatars.githubusercontent.com/u/1187528?v=4?s=100" width="100px;" alt="geometrikal"/><br /><sub><b>geometrikal</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Ageometrikal" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/shubinp"><img src="https://avatars.githubusercontent.com/u/25763776?v=4?s=100" width="100px;" alt="Shubin Pavel"/><br /><sub><b>Shubin Pavel</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=shubinp" title="Code">💻</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://www.netindustry.nl"><img src="https://avatars.githubusercontent.com/u/303034?v=4?s=100" width="100px;" alt="Wiebe Tijsma"/><br /><sub><b>Wiebe Tijsma</b></sub></a><br /><a href="#ideas-zidad" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/hgdemers"><img src="https://avatars.githubusercontent.com/u/169190876?v=4?s=100" width="100px;" alt="Henri Demers"/><br /><sub><b>Henri Demers</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Ahgdemers" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Fargekritt"><img src="https://avatars.githubusercontent.com/u/11448941?v=4?s=100" width="100px;" alt="Amund"/><br /><sub><b>Amund</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=Fargekritt" title="Code">💻</a> <a href="https://github.com/christianhelle/refitter/issues?q=author%3AFargekritt" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/velvolue"><img src="https://avatars.githubusercontent.com/u/155445968?v=4?s=100" width="100px;" alt="Vegard Løkken"/><br /><sub><b>Vegard Løkken</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=velvolue" title="Code">💻</a> <a href="https://github.com/christianhelle/refitter/issues?q=author%3Avelvolue" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/brad-technologik"><img src="https://avatars.githubusercontent.com/u/159975063?v=4?s=100" width="100px;" alt="brad-technologik"/><br /><sub><b>brad-technologik</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Abrad-technologik" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/jaroslaw-dutka"><img src="https://avatars.githubusercontent.com/u/40070136?v=4?s=100" width="100px;" alt="Jarosław Dutka"/><br /><sub><b>Jarosław Dutka</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=jaroslaw-dutka" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/maksionkin"><img src="https://avatars.githubusercontent.com/u/11482043?v=4?s=100" width="100px;" alt="maksionkin"/><br /><sub><b>maksionkin</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Amaksionkin" title="Bug reports">🐛</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/wocasella"><img src="https://avatars.githubusercontent.com/u/37601504?v=4?s=100" width="100px;" alt="wocasella"/><br /><sub><b>wocasella</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Awocasella" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Metziell"><img src="https://avatars.githubusercontent.com/u/33788844?v=4?s=100" width="100px;" alt="Petr Zika"/><br /><sub><b>Petr Zika</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3AMetziell" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/sebastian-wachsmuth"><img src="https://avatars.githubusercontent.com/u/87482207?v=4?s=100" width="100px;" alt="Sebastian Wachsmuth"/><br /><sub><b>Sebastian Wachsmuth</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=sebastian-wachsmuth" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/qrzychu"><img src="https://avatars.githubusercontent.com/u/4633810?v=4?s=100" width="100px;" alt="qrzychu"/><br /><sub><b>qrzychu</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Aqrzychu" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://stbl.com"><img src="https://avatars.githubusercontent.com/u/43214081?v=4?s=100" width="100px;" alt="Александр"/><br /><sub><b>Александр</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Alowern1ght" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/AragornHL"><img src="https://avatars.githubusercontent.com/u/18478623?v=4?s=100" width="100px;" alt="AragornHL"/><br /><sub><b>AragornHL</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=AragornHL" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/kmfd3s"><img src="https://avatars.githubusercontent.com/u/5180898?v=4?s=100" width="100px;" alt="kmfd3s"/><br /><sub><b>kmfd3s</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=kmfd3s" title="Code">💻</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/pfeigl"><img src="https://avatars.githubusercontent.com/u/237891?v=4?s=100" width="100px;" alt="Philipp Feigl"/><br /><sub><b>Philipp Feigl</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Apfeigl" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://tommihaapa.fi/"><img src="https://avatars.githubusercontent.com/u/47896768?v=4?s=100" width="100px;" alt="Tommi Haapa"/><br /><sub><b>Tommi Haapa</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Atommieemeli" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/MrScottyTay"><img src="https://avatars.githubusercontent.com/u/24463321?v=4?s=100" width="100px;" alt="Scott Taylor"/><br /><sub><b>Scott Taylor</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3AMrScottyTay" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/sb-chericks"><img src="https://avatars.githubusercontent.com/u/160796564?v=4?s=100" width="100px;" alt="sb-chericks"/><br /><sub><b>sb-chericks</b></sub></a><br /><a href="#ideas-sb-chericks" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/christianhelle/refitter/issues?q=author%3Asb-chericks" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/SWarnberg"><img src="https://avatars.githubusercontent.com/u/26246346?v=4?s=100" width="100px;" alt="Staffan Wärnberg"/><br /><sub><b>Staffan Wärnberg</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3ASWarnberg" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/lilinus"><img src="https://avatars.githubusercontent.com/u/78953007?v=4?s=100" width="100px;" alt="Linus Hamlin"/><br /><sub><b>Linus Hamlin</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Alilinus" title="Bug reports">🐛</a> <a href="https://github.com/christianhelle/refitter/commits?author=lilinus" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://marcohern.com/en/#about"><img src="https://avatars.githubusercontent.com/u/5376517?v=4?s=100" width="100px;" alt="Marco Hernandez"/><br /><sub><b>Marco Hernandez</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Amarcohern" title="Bug reports">🐛</a> <a href="#ideas-marcohern" title="Ideas, Planning, & Feedback">🤔</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/david-pw"><img src="https://avatars.githubusercontent.com/u/178433875?v=4?s=100" width="100px;" alt="david-pw"/><br /><sub><b>david-pw</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Adavid-pw" title="Bug reports">🐛</a> <a href="https://github.com/christianhelle/refitter/commits?author=david-pw" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/eoma-knowit"><img src="https://avatars.githubusercontent.com/u/150660175?v=4?s=100" width="100px;" alt="eoma-knowit"/><br /><sub><b>eoma-knowit</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=eoma-knowit" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/0xced"><img src="https://avatars.githubusercontent.com/u/51363?v=4?s=100" width="100px;" alt="Cédric Luthi"/><br /><sub><b>Cédric Luthi</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=0xced" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://christophdebaene.be"><img src="https://avatars.githubusercontent.com/u/642207?v=4?s=100" width="100px;" alt="Christoph De Baene"/><br /><sub><b>Christoph De Baene</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Achristophdebaene" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/7amou3"><img src="https://avatars.githubusercontent.com/u/993610?v=4?s=100" width="100px;" alt="7amou3"/><br /><sub><b>7amou3</b></sub></a><br /><a href="#ideas-7amou3" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://haldencollier.com"><img src="https://avatars.githubusercontent.com/u/25365699?v=4?s=100" width="100px;" alt="Halden"/><br /><sub><b>Halden</b></sub></a><br /><a href="#ideas-HGCollier" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/mhartmair-cubido"><img src="https://avatars.githubusercontent.com/u/164479174?v=4?s=100" width="100px;" alt="mhartmair-cubido"/><br /><sub><b>mhartmair-cubido</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Amhartmair-cubido" title="Bug reports">🐛</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/karoberts"><img src="https://avatars.githubusercontent.com/u/7482126?v=4?s=100" width="100px;" alt="Keith Roberts"/><br /><sub><b>Keith Roberts</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Akaroberts" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/kmc059000"><img src="https://avatars.githubusercontent.com/u/660670?v=4?s=100" width="100px;" alt="Kenneth Crawford"/><br /><sub><b>Kenneth Crawford</b></sub></a><br /><a href="#ideas-kmc059000" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/christianhelle/refitter/commits?author=kmc059000" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/0x2badc0de"><img src="https://avatars.githubusercontent.com/u/173240018?v=4?s=100" width="100px;" alt="0x2badc0de"/><br /><sub><b>0x2badc0de</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3A0x2badc0de" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://meteion.ca"><img src="https://avatars.githubusercontent.com/u/6116333?v=4?s=100" width="100px;" alt="Tylor Pater"/><br /><sub><b>Tylor Pater</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=frogcrush" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/vgmello"><img src="https://avatars.githubusercontent.com/u/4777793?v=4?s=100" width="100px;" alt="Vitor M"/><br /><sub><b>Vitor M</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=vgmello" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/send0xx"><img src="https://avatars.githubusercontent.com/u/31574812?v=4?s=100" width="100px;" alt="send0xx"/><br /><sub><b>send0xx</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Asend0xx" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/naji-makhoul"><img src="https://avatars.githubusercontent.com/u/5232373?v=4?s=100" width="100px;" alt="Naji Makhoul"/><br /><sub><b>Naji Makhoul</b></sub></a><br /><a href="#ideas-naji-makhoul" title="Ideas, Planning, & Feedback">🤔</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/smoerijf"><img src="https://avatars.githubusercontent.com/u/51750688?v=4?s=100" width="100px;" alt="smoerijf"/><br /><sub><b>smoerijf</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Asmoerijf" title="Bug reports">🐛</a> <a href="https://github.com/christianhelle/refitter/commits?author=smoerijf" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/dimyle"><img src="https://avatars.githubusercontent.com/u/54911257?v=4?s=100" width="100px;" alt="Dmitry"/><br /><sub><b>Dmitry</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Adimyle" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Timovzl"><img src="https://avatars.githubusercontent.com/u/655426?v=4?s=100" width="100px;" alt="Timo van Zijll Langhout"/><br /><sub><b>Timo van Zijll Langhout</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3ATimovzl" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/AntonTeyken"><img src="https://avatars.githubusercontent.com/u/162133784?v=4?s=100" width="100px;" alt="Anton"/><br /><sub><b>Anton</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3AAntonTeyken" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://umair.me"><img src="https://avatars.githubusercontent.com/u/834935?v=4?s=100" width="100px;" alt="Muhammad Umair Irshad"/><br /><sub><b>Muhammad Umair Irshad</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Aumair-me" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://z-bo.tumblr.com"><img src="https://avatars.githubusercontent.com/u/447485?v=4?s=100" width="100px;" alt="John Zabroski"/><br /><sub><b>John Zabroski</b></sub></a><br /><a href="#ideas-jzabroski" title="Ideas, Planning, & Feedback">🤔</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Gal3m"><img src="https://avatars.githubusercontent.com/u/91008976?v=4?s=100" width="100px;" alt="Ali Sadeghi"/><br /><sub><b>Ali Sadeghi</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3AGal3m" title="Bug reports">🐛</a> <a href="#security-Gal3m" title="Security">🛡️</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://mrostamipoor.github.io/"><img src="https://avatars.githubusercontent.com/u/78902717?v=4?s=100" width="100px;" alt="Maryam Rostamipoor"/><br /><sub><b>Maryam Rostamipoor</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Amrostamipoor" title="Bug reports">🐛</a> <a href="#security-mrostamipoor" title="Security">🛡️</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://codez.one/"><img src="https://avatars.githubusercontent.com/u/11291885?v=4?s=100" width="100px;" alt="paule96"/><br /><sub><b>paule96</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/commits?author=paule96" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/rcdailey"><img src="https://avatars.githubusercontent.com/u/1768054?v=4?s=100" width="100px;" alt="Robert Dailey"/><br /><sub><b>Robert Dailey</b></sub></a><br /><a href="https://github.com/christianhelle/refitter/issues?q=author%3Arcdailey" title="Bug reports">🐛</a> <a href="https://github.com/christianhelle/refitter/commits?author=rcdailey" title="Code">💻</a></td>
    </tr>
  </tbody>
</table>

<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

#

For tips and tricks on software development, check out [my blog](https://christianhelle.com)

If you find this useful and feel a bit generous then feel free to [buy me a coffee ☕](https://www.buymeacoffee.com/christianhelle)
