christianhelle / refitter Goto Github PK
View Code? Open in Web Editor NEWA tool for generating Refit interfaces and contracts from OpenAPI specifications
Home Page: https://refitter.github.io
License: MIT License
A tool for generating Refit interfaces and contracts from OpenAPI specifications
Home Page: https://refitter.github.io
License: MIT License
Description
Duplicate accept headers like [Headers("Accept: application/json, application/json")]
are generated when an endpoint has multiple responses with a payload. In this case, an endpoint can respond with HTTP 200 or 203 and both responses include a application/json
payload in the response body
Support Key: ptbddgt
OpenAPI Specifications
openapi: '3.0.0'
info:
version: 'v1'
title: 'Test API'
servers:
- url: 'https://test.host.com/api/v1'
paths:
/jobs/{job-id}:
get:
tags:
- 'Jobs'
summary: 'Get job details'
description: 'Get the details of the specified job.'
parameters:
- in: 'path'
name: 'job-id'
description: 'Job ID'
required: true
schema:
type: 'string'
responses:
'200':
description: 'successful operation'
content:
application/json:
schema:
$ref: '#/components/schemas/JobResponse'
'203':
description: 'successful operation'
content:
application/json:
schema:
$ref: '#/components/schemas/JobResponse'
components:
schemas:
JobResponse:
type: 'object'
properties:
job:
type: 'object'
properties:
start-date:
type: 'string'
format: 'date-time'
details:
type: 'string'
Generated code:
public interface ITestAPI
{
/// <summary>
/// Get the details of the specified job.
/// </summary>
[Headers("Accept: application/json, application/json")]
[Get("/jobs/{job-id}")]
Task<JobResponse> Jobs([AliasAs("job-id")] string job_id);
}
Describe the bug
Refitter ignores the IFormFile parameter decorated with [FromForm] which is used for receiving file upload.
The controller parameter is completely missed in the generated refit interface method.
If it worked, the generated method would have [Multipart] as method annotation and StreamPart as the type for IFormFile parameter
https://github.com/reactiveui/refit#multipart-uploads
Support Key: 8hz0dgn
OpenAPI Specifications
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"formFile": {
"type": "string",
"format": "binary"
}
}
},
"encoding": {
"formFile": {
"style": "form"
}
}
}
}
}
Additional context
Describe the bug
Attempting to download https://developers.intellihr.io/docs/v1/swagger.json results in garbled/binary JSON file being saved.
The file is publicly accessible and does not require auth, so it should be reproducible. I have a similar bug reported to another of my projects
Support Key: ptbddgt
OpenAPI Specifications
https://developers.intellihr.io/docs/v1/swagger.json
Additional context
After making a cURL request to the URI, I found out that that Refitter doesn't support URI's returning content-encoding: gzip
The following command:
curl https://developers.intellihr.io/docs/v1/swagger.json -v
returns:
* Trying 18.173.5.96:443...
* Connected to developers.intellihr.io (18.173.5.96) port 443 (#0)
* schannel: disabled automatic use of client certificate
* ALPN: offers http/1.1
* ALPN: server accepted http/1.1
* using HTTP/1.1
> GET /docs/v1/swagger.json HTTP/1.1
> Host: developers.intellihr.io
> User-Agent: curl/8.0.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 70281
< Connection: keep-alive
< x-amz-id-2: KbRD1cgNtvruOBsX/Xyxmvcnca3PLvJnb/o2tjFQV9jEBFB8rGareRNv8mj6ub1jd5AX6to/3Y4=
< x-amz-request-id: 898QGBVBFHSY8SNM
< Date: Mon, 04 Sep 2023 09:05:13 GMT
< Last-Modified: Mon, 04 Sep 2023 00:29:47 GMT
< ETag: "614dd1541549b50f0b008444459f94da"
< x-amz-server-side-encryption: AES256
< Content-Encoding: gzip
< x-amz-version-id: SDHILeEo0afGzS0a0a5ljWAToLzlnjWQ
< Accept-Ranges: bytes
< Server: AmazonS3
< Strict-Transport-Security: max-age=15552000; includeSubDomains; preload
< X-Cache: Miss from cloudfront
< Via: 1.1 78a128491ada170a2d9b82ba12d23d7a.cloudfront.net (CloudFront)
< X-Amz-Cf-Pop: CPH50-P1
< X-Amz-Cf-Id: pxEry-q7wwDbWme5LptPbbbMHcKPttbcKbFp4V5LmAIQBOtKNkvMIw==
<
Warning: Binary output can mess up your terminal. Use "--output -" to tell
Warning: curl to output it to your terminal anyway, or consider "--output
Warning: <FILE>" to save to a file.
* Failure writing output to destination
* Closing connection 0
* schannel: shutting down SSL/TLS connection with developers.intellihr.io port 443
When openapi doesn't specify format for integer type, generated property is of Int32 whereas the value could be in Int64 range, so is it not better to generate property of type Int64 ?
"prop1": {
"type": "integer"
}
Refer Open API specs for Integer (https://swagger.io/docs/specification/data-models/data-types/#numbers)
I found Refitter didn't generate valid C# output with kebab string casing parameters.
See job-id
in this sample OpenAPI 3.0 file:
openapi: "3.0.0"
info:
version: "v1"
title: "Test API"
servers:
- url: "https://test.host.com/api/v1"
paths:
/jobs/{job-id}:
get:
tags:
- "Jobs"
summary: "Get job details"
description: "Get the details of the specified job."
parameters:
- in: "path"
name: "job-id"
description: "Job ID"
required: true
schema:
type: "string"
responses:
"200":
description: "successful operation"
content:
application/json:
schema:
$ref: "#/components/schemas/JobResponse"
components:
schemas:
JobResponse:
type: "object"
properties:
job:
type: "object"
properties:
start-date:
type: "string"
format: "date-time"
details:
type: "string"
Invalid C# parameter output snippet:
[Get("/jobs/{job-id}")]
Task<JobResponse> Jobs(string job-id);
Is your feature request related to a problem? Please describe.
I'd like to generate the refit internfaces for an OpenAPI specification that consists of multiple files that are linked to each other using $ref (see https://swagger.io/docs/specification/using-ref/).
Describe the solution you'd like
It would be great if refitter would support $ref.
Describe alternatives you've considered
The alternative would be to merge the files first using a different tool. But it would be much easier, if this extra step could be avoided.
Additional context
Thank you for your help.
Hi,
I have noticed the following with refitter 0.5.26. With OpenApi spec input:
openapi: 3.0.0
x-stoplight:
id: w776sltk0h1bo
info:
title: Gamenight
version: '1.0'
contact:
name: Dennis Brentjes
email: [email protected]
url: 'https://brentj.es'
description: Api specifaction for a Gamenight server
license:
name: MIT
servers:
- url: 'http://localhost:8080'
description: Gamenight
paths:
/token:
get:
summary: ''
operationId: get-token
responses:
'200':
$ref: '#/components/responses/TokenResponse'
requestBody:
$ref: '#/components/requestBodies/LoginRequest'
description: Submit your credentials to get a JWT-token to use with the rest of the api.
parameters: []
components:
schemas:
Token:
title: Token
x-stoplight:
id: 8pz19kigm1jer
type: object
properties:
jwt_token:
type: string
Login:
title: Login
type: object
properties:
username:
type: string
password:
type: string
required:
- username
- password
requestBodies:
LoginRequest:
content:
application/json:
schema:
$ref: '#/components/schemas/Login'
responses:
TokenResponse:
description: Example response
content:
application/json:
schema:
$ref: '#/components/schemas/Token'
I get the following output, with Task missing their response output as Task result.
// <auto-generated>
// This code was generated by Refitter.
// </auto-generated>
using Refit;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace GeneratedCode
{
public interface IGamenight
{
/// <summary>
/// Submit your credentials to get a JWT-token to use with the rest of the api.
/// </summary>
[Get("/token")]
Task GetToken([Body] object body);
}
}
//----------------------
// <auto-generated>
// Generated using the NSwag toolchain v13.19.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v10.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------
#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended."
#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword."
#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?'
#pragma warning disable 612 // Disable "CS0612 '...' is obsolete"
#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ...
#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..."
#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'"
#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant"
#pragma warning disable 8603 // Disable "CS8603 Possible null reference return"
namespace GeneratedCode
{
using System = global::System;
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.19.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v10.0.0.0))")]
public partial class Token
{
[System.Text.Json.Serialization.JsonPropertyName("jwt_token")]
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault)]
public string Jwt_token { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties;
[System.Text.Json.Serialization.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary<string, object>()); }
set { _additionalProperties = value; }
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.19.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v10.0.0.0))")]
public partial class Login
{
[System.Text.Json.Serialization.JsonPropertyName("username")]
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.Never)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
public string Username { get; set; }
[System.Text.Json.Serialization.JsonPropertyName("password")]
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.Never)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
public string Password { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties;
[System.Text.Json.Serialization.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary<string, object>()); }
set { _additionalProperties = value; }
}
}
}
#pragma warning restore 108
#pragma warning restore 114
#pragma warning restore 472
#pragma warning restore 612
#pragma warning restore 1573
#pragma warning restore 1591
#pragma warning restore 8073
#pragma warning restore 3016
#pragma warning restore 8603
When I apply this patch to refitter
diff --git a/src/Refitter.Core/RefitInterfaceGenerator.cs b/src/Refitter.Core/RefitInterfaceGenerator.cs
index ad588c4..0b19ab0 100644
--- a/src/Refitter.Core/RefitInterfaceGenerator.cs
+++ b/src/Refitter.Core/RefitInterfaceGenerator.cs
@@ -40,7 +40,7 @@ public class RefitInterfaceGenerator
var operation = operations.Value;
var returnTypeParameter = operation.Responses.ContainsKey("200")
- ? generator.GetTypeName(operation.Responses["200"].Schema, true, null)
+ ? generator.GetTypeName(operation.Responses["200"].ActualResponse.Schema, true, null)
: null;
var returnType = GetReturnType(returnTypeParameter);
I get the expected output with Task returning their output.
// <auto-generated>
// This code was generated by Refitter.
// </auto-generated>
using Refit;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace GeneratedCode
{
public interface IGamenight
{
/// <summary>
/// Submit your credentials to get a JWT-token to use with the rest of the api.
/// </summary>
[Get("/token")]
Task<Token> GetToken([Body] object body);
}
}
//----------------------
// <auto-generated>
// Generated using the NSwag toolchain v13.19.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v10.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------
#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended."
#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword."
#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?'
#pragma warning disable 612 // Disable "CS0612 '...' is obsolete"
#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ...
#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..."
#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always 'false' since a value of type 'T' is never equal to 'null' of type 'T?'"
#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-compliant"
#pragma warning disable 8603 // Disable "CS8603 Possible null reference return"
namespace GeneratedCode
{
using System = global::System;
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.19.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v10.0.0.0))")]
public partial class Token
{
[System.Text.Json.Serialization.JsonPropertyName("jwt_token")]
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault)]
public string Jwt_token { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties;
[System.Text.Json.Serialization.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary<string, object>()); }
set { _additionalProperties = value; }
}
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "13.19.0.0 (NJsonSchema v10.9.0.0 (Newtonsoft.Json v10.0.0.0))")]
public partial class Login
{
[System.Text.Json.Serialization.JsonPropertyName("username")]
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.Never)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
public string Username { get; set; }
[System.Text.Json.Serialization.JsonPropertyName("password")]
[System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.Never)]
[System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)]
public string Password { get; set; }
private System.Collections.Generic.IDictionary<string, object> _additionalProperties;
[System.Text.Json.Serialization.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties ?? (_additionalProperties = new System.Collections.Generic.Dictionary<string, object>()); }
set { _additionalProperties = value; }
}
}
}
#pragma warning restore 108
#pragma warning restore 114
#pragma warning restore 472
#pragma warning restore 612
#pragma warning restore 1573
#pragma warning restore 1591
#pragma warning restore 8073
#pragma warning restore 3016
#pragma warning restore 8603
The original behaviour seems to be a bug, I have no idea however if my "fix" has any impact on existing projects but I suspect that ActualResponse wil link be a reference to itself when not being used by a ref. But that is a question you might be able to answer.
Why using CLI (reading settings from .reffiter file) I get two outputs?
One in outputFolder specified in settings file, but with name from that file name (i.e. test.refitter -> test.g.cs) and another one named Ouput.cs in directory from which I ran the command?
Please, add outputFileName to .reffiter settings so that only one output is produced.
I have a swagger doc with nullable query params and the generated Refit method signature has the param marked as nullable but not set with null by default so in order to call the method all of the nullable params need to be set as null vs just setting the params you want to set.
"/v1/accounts/{accountId}/addresses": { "get": { "tags": [ "AccountAddresses" ], "operationId": "AccountAddresses_GetAccountAddresses", "parameters": [ { "name": "accountId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" }, "x-position": 1 }, { "name": "IsPrimary", "in": "query", "schema": { "type": "boolean", "nullable": true, "default": null } }, { "name": "IsActive", "in": "query", "schema": { "type": "boolean", "nullable": true } }, { "name": "IncludeSpouse", "in": "query", "schema": { "type": "boolean" } }, { "name": "SortBy", "in": "query", "style": "form", "explode": true, "schema": { "type": "array", "nullable": true, "xml": { "name": "ArrayOfstring", "wrapped": true }, "items": { "type": "string", "xml": { "name": "string" } } } }, { "name": "Search", "in": "query", "schema": { "type": "string", "nullable": true } }, { "name": "PageNumber", "in": "query", "schema": { "type": "integer", "format": "int32" } }, { "name": "PageSize", "in": "query", "schema": { "type": "integer", "format": "int32" } }, { "name": "ExportFileName", "in": "query", "schema": { "type": "string", "nullable": true } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PagedApiResponseOfIEnumerableOfAccountAddressSummary" } } } } } }, "post": { "tags": [ "AccountAddresses" ], "operationId": "AccountAddresses_CreateAccountAddress", "parameters": [ { "name": "accountId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" }, "x-position": 1 } ], "requestBody": { "x-name": "command", "content": { "application/json": { "schema": { "nullable": true, "$ref": "#/components/schemas/CreateAccountAddress" } } }, "x-position": 2 }, "responses": { "201": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountAddressSummary" } } } } } } },
REFITTER000 System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. Systém nemůže nalézt uvedený soubor.
I tried to install package Microsoft.Bcl.AsyncInterfaces, but it did not help. VS 2022, MAUI app project.
Thanks for help
Add support for generating interfaces that returns Task<IApiResponse<T>>
as the return type
Like this:
[Get("/pet/{petId}")]
Task<IApiResponse<Pet>> GetPetById(long petId);
So that if the call to GetPetById()
fails then we can handle the negative response ourselves instead of catching an ApiException
var client = RestService.For<ISwaggerPetstore>("https://petstore3.swagger.io/api/v3");
var response = await client.GetPetById(2);
if (!response. IsSuccessStatusCode)
{
// Do something about the failed response
}
var pet = response.Content;
The IApiResponse<T>
interface comes from Refit and is defined as
/// <inheritdoc/>
public interface IApiResponse<out T> : IApiResponse
{
/// <summary>
/// Deserialized request content as <typeparamref name="T"/>.
/// </summary>
T? Content { get; }
}
/// <summary>
/// Base interface used to represent an API response.
/// </summary>
public interface IApiResponse : IDisposable
{
/// <summary>
/// HTTP response headers.
/// </summary>
HttpResponseHeaders Headers { get; }
/// <summary>
/// HTTP response content headers as defined in RFC 2616.
/// </summary>
HttpContentHeaders? ContentHeaders { get; }
/// <summary>
/// Indicates whether the request was successful.
/// </summary>
bool IsSuccessStatusCode { get; }
/// <summary>
/// HTTP response status code.
/// </summary>
HttpStatusCode StatusCode { get; }
/// <summary>
/// The reason phrase which typically is sent by the server together with the status code.
/// </summary>
string? ReasonPhrase { get; }
/// <summary>
/// The HTTP Request message which led to this response.
/// </summary>
HttpRequestMessage? RequestMessage { get; }
/// <summary>
/// HTTP Message version.
/// </summary>
Version Version { get; }
/// <summary>
/// The <see cref="ApiException"/> object in case of unsuccessful response.
/// </summary>
ApiException? Error { get; }
}
Maybe it's there and I couldn't find it, but when generating contracts, I'd like to specify some NSwag options like dateType (I don't like DateTimeOffset) or arrayType.
Describe the bug
The generated files seem to have a mixture different lines endings. This dialog appears everytime a file is opened in VS.
Perhaps consider normalizing the line endings to whatever the OS environment the tools is run in :)
Support Key: kedfgny
OpenAPI Specifications
N/A
Additional context
Add any other context about the problem here.
Describe the bug
Filtering a spec by tag using --tag A --tag B
is currently broken as it only accepts the last filter entered.
Instead it should keep all paths that contain any of the tags.
Additional context
This is due to the following check constantly overriding previous results:
exclude = method.Value.Tags?.Exists(x => x == tag) != true;
The code may be rewritten, to remove the looping over includeTags by using the following:
var exclude = method.Value.Tags?.Exists(includeTags.Contains) != true;
Also, previously the enumerated collections were cloned, to not break the enumeration, after the rewrite the enumerators are reused (.ToArray()
was removed)
7025d61#diff-275851d6772d6a0a03b9aaf63017c87331d0334e274deeebd199fe8cd07cc521R34
7025d61#diff-275851d6772d6a0a03b9aaf63017c87331d0334e274deeebd199fe8cd07cc521R37
deleting from an collection that is currently enumerated is undefined behavior
I propose ~~ a --partial
Flag for the CLI.~~ refit interfaces to be generated as partial
interfaces by default, which would comply with most other code-generator tools out there and the way the models are generated currently.
Reasoning being, for certain classes we need to add attributes, interfaces or utility methods which is currently not possible without modifying the generated code.
By having partial
classes for Models and Refit-Interfaces, we can make use of a generated.additions.cs
(example name) which contains the needed modifications.
// a.cs
internal partial interface ISomething
{
}
// a.additions.cs
[FancyAttribute("With Value")]
[Headers("X-App: MyApp")]
partial interface ISomething {}
A new and a very convenient feature allows us to use refitter file via CLI with a --settings-file
option in the following manner:
refitter ./openapi.json --settings-file ./openapi.refitter
.
The path to OpenAPI spec file (./openapi.json
) cannot be dropped from the CLI command as it results in Input file is required
error.
At the same time refitter file has an openApiPath
parameter with seemingly the same meaning. Thus it seems redundant and error-prone to have a mandatory path in a CLI command as it becomes unclear which of the paths would be used in the end - the one in CLI command or the one in .refitter file.
Describe the bug
Version 0.8.2 generates a new dependency injection IServiceCollectionExtensions, and seems to introduce a syntax error as shown below:
services
.AddRefitClient<IBackendApi>()
.ConfigureHttpClient(c => c.BaseAddress = baseUrl)
.AddHttpMessageHandler<AuthorizationMessageHandler>()
.AddHttpMessageHandler<TelemetryMessageHandler>()); // extra ) here
This seems to originate from this line
I wasn't sure if there were use cases that this worked, but this is the config that does not work, and probably has something to do with the httpMessageHandlers
in the dependency injection section.
{
"openApiPath": "../../Services/BackendApi/wwwroot/swaggerfile.json",
"namespace": "App.Services.Clients.BackendApiClient",
"naming": {
"useOpenApiTitle": false,
"interfaceName": "BackendApiClient"
},
"generateContracts": true,
"generateXmlDocCodeComments": true,
"addAutoGeneratedHeader": false,
"addAcceptHeaders": false,
"returnIApiResponse": true,
"generateOperationHeaders": true,
"typeAccessibility": 0,
"useCancellationTokens": false,
"useIsoDateFormat": true,
"multipleInterfaces": 2,
"generateDeprecatedOperations": false,
"operationNameTemplate": "{operationName}Async",
"optionalParameters": true,
"outputFolder": "./Clients",
"includePathMatches": [
"^(?!.*[Ii]ntegration[Ee]vent).*\/api.*"
],
"dependencyInjectionSettings": {
"httpMessageHandlers": [
"AuthorizationMessageHandler",
"TelemetryMessageHandler"
]
}
}
I cannot include the API spec for privacy reasons.
Describe the bug
When generating a client for an OpenApi (swagger version 2.0) with url (query) parameters of type string with a format of 'date' are generated as a regular DateTimeOffset without a 'Date' format.
Support Key: mmt1dt0
OpenAPI Specifications
(not the full specs, but this is the gist of it)
{
"swagger": "2.0",
"info": {
"title": "XX",
"version": "0.0.0"
},
"host": "x.io",
"basePath": "/",
"schemes": [
"https"
],
"paths": {
"/t/dummy/{employee_id}": {
"get": {
"summary": "X",
"description": "X",
"operationId": "dummy",
"parameters": [
{
"name": "employee_id",
"in": "path",
"description": "the specific employee",
"required": true,
"format": "int64",
"type": "integer"
},
{
"name": "valid_from",
"in": "query",
"description": "the start of the period",
"required": true,
"format": "date",
"type": "string"
},
{
"name": "valid_to",
"in": "query",
"description": "the end of the period",
"required": true,
"format": "date",
"type": "string"
}
],
"responses": {
"200": {
"description": "No response was specified",
"schema": {
"$ref": "#/definitions/DummyList"
}
}
},
"produces": [
"application/json",
"application/xml"
]
}
},
}
},
Additional context
Resulting code is:
/// <summary>
/// X
/// </summary>
[Get("/t/dummy/{employee_id}")]
Task<DummyList> Dummy(long employee_id, [Query(CollectionFormat.Multi)] System.DateTimeOffset valid_from, [Query(CollectionFormat.Multi)] System.DateTimeOffset valid_to);
When executing, this results in errors.
Expected code:
/// <summary>
/// X
/// </summary>
[Get("/t/dummy/{employee_id}")]
Task<DummyList> Dummy(long employee_id, [Query(CollectionFormat.Multi, Format = "yyyy-MM-dd")] System.DateTimeOffset valid_from, [Query(CollectionFormat.Multi, Format = "yyyy-MM-dd")] System.DateTimeOffset valid_to);
The same may be true for other date / time related formats, like 'time'. The same may also be true for entity classes where properties are generated as regular 'DateTimeOffset'.
Ideally, for 'time' and 'date', both the arguments of functions and the properties of entity classes would result in 'TimeOnly' and 'DateOnly', respectively, but I'm not sure if those are fully supported in Refit? I think they are for properties, not sure about function arguments.
Edit: apparently 'time' was no format in OpenApi (Swagger) v2, but 'date' apparently is.
Describe the bug
This problem is with the same API as in #175, they use snake_lower_case
for enum values and because JsonConverter
will instantiate the JsonStringEnumConverter
with default options the deserialization of any type with enum members will fail.
Registering a JsonStringEnumConverter
in json serialization settings does not help, because as JsonConverter
says: "When placed on a property or field, the specified converter will always be used.".
When JsonConverter
is placed on the type, if you've a compatible serializer in settings that will be used.
I see multiple solutions here, but one of them is simple:
[JsonConverter(typeof(JsonStringEnumConverter))]
for enum properties. With this settings will have to be configured but gives great flexibility. Cons: if no settings configured Json serialization will fail because there is nothing registered for enums.JsonConverter
from properties to the enum types.Now:
public enum Foo
{
FooOne = 0,
FooTwo = 1
}
public class FooClass
{
[JsonConverter(typeof(JsonStringEnumConverter))]
public Foo enumValue { get; set; }
}
With fix:
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Foo
{
FooOne = 0,
FooTwo = 1
}
public class FooClass
{
public Foo enumValue { get; set; }
}
This way there is no requirement to have settings configured for enums, but gives the flexibility to have the behavior changed or register even typed enum converters there.
Support Key: [my-support-key]
N/A
OpenAPI Specifications
Same as in #175
Additional context
[EnumMember]
is not used with System.Text.Json
so their declaration can be omitted.
When using the new Refitter Source Generator to generate Refit Interfaces and classes, the generated code is not being picked up by Refit's Source Generator:
This makes the Refitter Source Generator unusable for now.
Link to repo to reproduce the issue.
Any ideas on how to fix this ?
This was pointed out to me by @kgamecarter
Example YAML:
swagger: '2.0'
info:
title: Reference parameters
version: v0.0.1
paths:
'/orders/{orderId}/order-items/{orderItemId}':
parameters:
- $ref: '#/parameters/OrderId'
- $ref: '#/parameters/OrderItemId'
delete:
summary: Delete an order item
description: >-
This method allows to remove an order item from an order, by specifying
their ids.
responses:
"204":
description: No Content.
default:
description: Default response
schema:
$ref: '#/definitions/Error'
definitions:
Error:
type: object
properties:
message:
type: string
parameters:
OrderId:
name: orderId
in: path
description: Identifier of the order.
required: true
type: string
format: uuid
OrderItemId:
name: orderItemId
in: path
description: Identifier of the order item.
required: true
type: string
format: uuid
Generated code:
public interface IReferenceparameters
{
/// <summary>
/// This method allows to remove an order item from an order, by specifying their ids.
/// </summary>
[Delete("/orders/{orderId}/order-items/{orderItemId}")]
Task OrderItems();
}
missing orderId and orderItemId path parameters
This would allow us to only generate a subset of the interfaces/methods we need.
e.g. App might need "Configuration"-Controller/Group Methods, but not others.
by allowing things like the following, the consumers can specify exactly what they need.
matches are based on regex
--include '^/api/v1/user/.*'
--include '^/api/(?!pet\b)' // include everything that is NOT /api/pet
For a less fine grained, but also useful way, we could also add filter for the "Tags" section of an openapi spec.
matches are based value, case-insensitive
--include-tag User \
--include-tag Configuration
Is your feature request related to a problem?
I think it would be nice if it were possible to choose naming for methods when interfaces are generated ByEndpoint. Right now it is only possible to customize method names when all endpoints are in a single interface. When doing it for a single interface the {operationName} is a requirement, but I do not think this should be a requirement since there will only be one method in each interface.
Describe the solution you'd like
Example of how this could work:
{
"openApiPath": "./openapi.json",
"namespace": "Your.Namespace.Of.Choice.GeneratedCode",
"multipleInterfaces": "ByEndpoint",
"operationNameTemplate": "ExecuteAsync" // Default is Execute
}
The .refitter file above results in the following code:
/// <summary>
/// Update an existing pet
/// </summary>
public partial interface IUpdatePetEndpoint
{
/// <summary>
/// Update an existing pet by Id
/// </summary>
[Put("/pet")]
Task<Pet> Execute([Body] Pet body);
}
/// <summary>
/// Add a new pet to the store
/// </summary>
public partial interface IAddPetEndpoint
{
/// <summary>
/// Add a new pet to the store
/// </summary>
[Post("/pet")]
Task<Pet> Execute([Body] Pet body);
}
...
First off, sorry for feature bombing
It would be very handy to be able to specify the access modifier for the generated DTOs and Clients.
backstory:
In our project, we have modularized everything and try to keep our public
Api surface as small as possible.
We define most of our classes as internal
unless they explicitly are needed in other places.
All HTTP calls a module needs and all their DTOs reside in the module and never leave it's scope.
The generated code for OpenAPI specs where the operationId
contains spaces, doesn't build
OpenAPI Specifications
openapi: '3.0.0'
paths:
/jobs/{job-id}:
get:
tags:
- 'Jobs'
operationId: 'Get job details'
description: 'Get the details of the specified job.'
parameters:
- in: 'path'
name: 'job-id'
description: 'Job ID'
required: true
schema:
type: 'string'
responses:
'200':
description: 'successful operation'
https://github.com/christianhelle/refitter/blob/main/src/Refitter.Core/ParameterExtractor.cs#L15
I noticed that in the file ParameterExtractor.cs, parameters are added for the route and the body, but not for the query.
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.
.devcontainer/devcontainer.json
mcr.microsoft.com/devcontainers/dotnet 1-6.0
ghcr.io/devcontainers/features/powershell 1
ghcr.io/devcontainers/features/dotnet 2
.github/workflows/build.yml
actions/checkout v4
actions/upload-artifact v3
.github/workflows/changelog.yml
actions/checkout v4
ruby/setup-ruby v1
.github/workflows/codecov.yml
actions/checkout v4
actions/upload-artifact v3
codecov/codecov-action v4
.github/workflows/docfx.yml
actions/checkout v4
peaceiris/actions-gh-pages v4
.github/workflows/release-template.yml
actions/checkout v4
nelonoel/branch-name v1.0.1
actions/upload-artifact v3
actions/github-script v7
.github/workflows/smoke-tests.yml
actions/checkout v4
.github/workflows/template-source-generator.yml
actions/checkout v4
.github/workflows/template-url.yml
actions/checkout v4
.github/workflows/template.yml
actions/checkout v4
actions/upload-artifact v3
src/Refitter.Core/Refitter.Core.csproj
OasReader 1.6.16.15
NSwag.Core.Yaml 14.1.0
NSwag.CodeGeneration.CSharp 14.1.0
Microsoft.SourceLink.GitHub 8.0.0
src/Refitter.SourceGenerator.Tests/Refitter.SourceGenerator.Tests.csproj
Polly.Contrib.WaitAndRetry 1.1.1
Microsoft.Extensions.Http.Polly 8.0.7
Refit.HttpClientFactory 7.1.2
coverlet.collector 6.0.2
xunit.runner.visualstudio 2.8.2
xunit 2.9.0
FluentAssertions 6.12.0
Microsoft.NET.Test.Sdk 17.10.0
Microsoft.Extensions.Http.Resilience 8.7.0
src/Refitter.SourceGenerator/Refitter.SourceGenerator.csproj
Refit 7.1.2
OasReader 1.6.16.15
NSwag.Core.Yaml 14.1.0
NSwag.CodeGeneration.CSharp 14.1.0
H.Generators.Extensions 1.22.0
Microsoft.CodeAnalysis.CSharp 4.8.0
src/Refitter.Tests/Refitter.Tests.csproj
coverlet.collector 6.0.2
xunit.runner.visualstudio 2.8.2
xunit 2.9.0
Microsoft.NET.Test.Sdk 17.10.0
Atc.Test 1.0.89
src/Refitter/Refitter.csproj
Microsoft.SourceLink.GitHub 8.0.0
Spectre.Console.Cli 0.49.1
Exceptionless 6.0.4
When Refitter generates Refit interfaces from a OAS 3.0 spec file, it doesn't add the "Accept" header , which necesssary for ASP.NET Core's ProblemDetails Middleware to function properly.
According to OAS 3.0 specification, The content
property in responses
contains the MIME type expected in the response.
I'm suggesting to add an optional parameter addAcceptHeaders
to add the accept header.
Examples
addAcceptHeaders
: /// Multiple status values can be provided with comma separated strings
/// </summary>
[Get("/pet/findByStatus")]
Task<ICollection<Pet>> FindPetsByStatus([Query(CollectionFormat.Multi)] IEnumerable<Anonymous> status);
addAcceptHeaders
: /// Multiple status values can be provided with comma separated strings
/// </summary>
[Headers("Accept: application/json")]
[Get("/pet/findByStatus")]
Task<ICollection<Pet>> FindPetsByStatus([Query(CollectionFormat.Multi)] IEnumerable<Anonymous> status);```
Describe the bug
Hello there, interesting project so gave it a go :)
The following command refitter https://api.hubspot.com/api-catalog-public/v1/apis/events/v3/send --namespace HubSpot --output ./GeneratedCode.cs
generated this code
namespace HubSpot
{
public interface ICustomBehavioralEventsAPI
{
/// <summary>
/// Endpoint to send an instance of a behavioral event
/// </summary>
[Post("/events/v3/send")]
Task Post/events/v3/send([Body] BehavioralEventHttpCompletionRequest body);
}
}
As you can see the method name is not valid C#.
Support Key: kedfgny
OpenAPI Specifications
https://api.hubspot.com/api-catalog-public/v1/apis/events/v3/send
Additional context
Add any other context about the problem here.
Describe the bug
I have a receiving API endpoint with following signature:
[HttpPost("[action]/{bucketName}/{directory}", Name = nameof(UploadFileAsync))]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> UploadFileAsync(string bucketName,
[FromRoute] string directory,
[FromForm] UploadFileArgs uploadFileArgs,
IFormFile file,
CancellationToken cancellationToken)
using refitter CLI i get the following contract generated for the controller:
/// <summary>
/// Returns information about file
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("Refitter", "0.7.5.0")]
public interface IFileApi
{
[Headers("Accept: application/json")]
[Get("/v1/File/GetFileInfo/{bucketName}/{objectName}")]
Task<FileInfo> GetFileInfoAsync(string bucketName, string objectName, CancellationToken cancellationToken = default);
[Headers("Accept: application/octet-stream")]
[Get("/v1/File/DownloadFile/{bucketName}/{objectName}")]
Task DownloadFileAsync(string bucketName, string objectName, [Query] string versionId, CancellationToken cancellationToken = default);
[Multipart]
[Headers("Accept: application/json")]
[Post("/v1/File/UploadFile/{bucketName}/{directory}")]
Task UploadFileAsync(string bucketName, string directory, StreamPart file, CancellationToken cancellationToken = default);
[Headers("Accept: application/json")]
[Post("/v1/File/CopyFile/{fromBucketName}/{filePath}/{toDirectory}")]
Task CopyFileAsync(string fromBucketName, string filePath, string toDirectory, [Query] string toBucketName, CancellationToken cancellationToken = default);
[Headers("Accept: application/json")]
[Post("/v1/File/MoveFile/{fromBucketName}/{fromFilePath}/{toFilePath}")]
Task MoveFileAsync(string fromBucketName, string fromFilePath, string toFilePath, [Query] string toBucketName, CancellationToken cancellationToken = default);
[Delete("/v1/File/DeleteFile/{bucketName}/{filePath}")]
Task DeleteFileAsync(string bucketName, string filePath, CancellationToken cancellationToken = default);
}
The endpoint in question is missing the long[] OrganizationalUnitIds
which is a single property of the [FromForm] UploadFileArgs uploadFileArgs
argument in the receiving endpoint. In line 545 of openApi spec the request body is defined as follows:
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"type": "object",
"properties": {
"OrganizationalUnitIds": {
"type": "array",
"items": {
"type": "integer",
"format": "int64"
}
},
"file": {
"type": "string",
"format": "binary"
}
}
},
"encoding": {
"OrganizationalUnitIds": {
"style": "form"
},
"file": {
"style": "form"
}
}
}
}
}
Support Key: [h/tnek2]
The support key is a unique identifier generated on the machine which is used when logging telemetry data. This feature is introduced in v0.5.4 and is shown in the output when running Refitter.
This issue is used to integrate with the @all-contributors bot
To reduce the amount of generated Contracts, we could walk the path
s and remove and non-referenced schema
As we already are able to filter paths, we can make use of that to clean up the spec and generate less code.
Example code for cleaning up the schema definitions
// Uses Microsoft.OpenApi.Readers & SwashBuckle.AspNetCore for Reading and Writing specs
void Main()
{
var rdr = new Microsoft.OpenApi.Readers.OpenApiStreamReader();
using var specFile = File.OpenRead(@"C:\spec.json");
// doc is a "filtered" OpenApi-spec
var doc = rdr.Read(specFile, out var diagnostic);
var schemaCleaner = new SchemaCleaner();
schemaCleaner.RemoveUnreferencedSchema(doc);
using var tw = File.CreateText(@"C:\clean_spec.yaml");
var writer = new Microsoft.OpenApi.Writers.OpenApiYamlWriter(tw);
doc.SerializeAsV3(writer);
}
public class SchemaCleaner
{
public void RemoveUnreferencedSchema(OpenApiDocument doc)
{
var usage = FindUsedSchema(doc);
var unused = doc.Components.Schemas.Where(s => !usage.Contains(s.Key))
.ToArray();
foreach (var unusedSchema in unused)
{
doc.Components.Schemas.Remove(unusedSchema);
}
}
HashSet<string> FindUsedSchema(OpenApiDocument doc)
{
var toProcess = new Stack<OpenApiSchema>();
foreach (var (_, pathItem) in doc.Paths)
{
foreach (var p in pathItem.Parameters)
{
TryPush(p.Schema, toProcess);
}
foreach (var (_, op) in pathItem.Operations)
{
foreach (var (_, resp) in op.Responses)
{
foreach (var (_, header) in resp.Headers)
{
TryPush(header.Schema, toProcess);
}
foreach (var (_, content) in resp.Content)
{
TryPush(content.Schema, toProcess);
}
}
}
}
var seen = new HashSet<string>();
while (toProcess.TryPop(out var schema))
{
if (schema.Reference?.Id is { } refId)
{
if (!seen.Add(refId))
{
// prevent recursion
continue;
}
}
foreach (var subSchema in EnumerateSchema(schema))
{
TryPush(subSchema, toProcess);
}
}
return seen;
}
private void TryPush(OpenApiSchema? schema, Stack<OpenApiSchema> stack)
{
if (schema == null)
{
return;
}
stack.Push(schema);
}
IEnumerable<OpenApiSchema> EnumerateSchema(OpenApiSchema? schema)
{
if (schema is null)
{
return Enumerable.Empty<OpenApiSchema>();
}
return EnumerateInternal(schema)
.Where(x => x != null)
.Select(x => x!);
static IEnumerable<OpenApiSchema?> EnumerateInternal(OpenApiSchema schema)
{
yield return schema.AdditionalProperties;
yield return schema.Items;
yield return schema.Not;
foreach (var subSchema in schema.AllOf)
{
yield return subSchema;
}
foreach (var subSchema in schema.AnyOf)
{
yield return subSchema;
}
foreach (var subSchema in schema.OneOf)
{
yield return subSchema;
}
foreach (var (_, subSchema) in schema.Properties)
{
yield return subSchema;
}
}
}
}
Is your feature request related to a problem? Please describe.
To enable the generated client to have the serializers source generated, the tool could generate an <ApiTypeName>JsonSerializerContext
class which inherits from JsonSerializerContext
and add all the type names with JsonSerializable
to the class, so the serializer source generator could kick in and do its job.
This feature can only be added to the standalone tool because source generators cannot interact with each other currently.
Describe the solution you'd like
An <ApiTypeName>JsonSerializerContext
class would be generated as well.
Describe alternatives you've considered
Manually write this class by hand which is tedious.
Additional context
More info on it: https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/
When Refitter generates an operation, the parameter names in the methods are formatted in snakeCase.
Here is an example with Username
and Password
parameter:
{
"/user/login": {
"get": {
"tags": [
"user"
],
"summary": "Logs user into the system",
"description": "",
"operationId": "loginUser",
"parameters": [
{
"name": "Username",
"in": "query",
"description": "The user name for login",
"required": false,
"schema": {
"type": "string"
}
},
{
"name": "Password",
"in": "query",
"description": "The password for login in clear text",
"required": false,
"schema": {
"type": "string"
}
}
],
...
}
}
}
[Get("/user/login")]
Task<string> LoginUser([Query] string username, [Query] string password);
http://swagger.io/user/login?username=XXXX&password=XXXX
This is causing issues in APIs that require the original casing for parameter names ( Username
instead of username
and Password
instead of password
)
i don't quite get the reasoning why the LTS net6.0 is not supported.
i can't install this tool into our build, because we develop on "LTS"s only.
Current workaround is to install the tool globally if net7.0 is installed and use the global executable.
Hi!
Is it possible for add a support for using file from CLI params?
Like this:
refitter ./openapi.json --settings-file cli.json
I saw you added .refitter file for setup source generation, but some of the parameters weren't supported in the CLI. For example "naming" param.
It would be soo cool to send just file to the command line instead of passing params.
Describe the bug
When generating a client for an OpenApi (swagger version 2.0) with a model definition with a property named System
, the generated code no longer compiles. Reason being that the same class also uses references to other classes from the System
namespace.
Support Key: mmt1dt0
OpenAPI Specifications
(not the full specs, but this is the gist of it)
{
"swagger": "2.0",
"info": {
"title": "XX",
"version": "0.0.0"
},
"host": "x.io",
"basePath": "/",
"schemes": [
"https"
],
"definitions": {
"Dummy": {
"type": "object",
"properties": {
"system": {
"type": "string",
"description": "XX"
}
},
"description": "XXX",
"example": {
"system": "Dummy"
}
}
}
},
Additional context
May also be true for some reserved words. System is not really a reserved word, but just not very practical.
Describe the bug
I try to generate a client for the FusionAuth spec and it is using oneOf
for IdentityProviderField
and in the resulting source file no IdentityProvider
base class is generated.
Support Key: [my-support-key]
N/A (did not find it in output)
OpenAPI Specifications
https://raw.githubusercontent.com/FusionAuth/fusionauth-openapi/main/openapi.yaml
Additional context
My quick fix were these:
public class IdentityProvider
{
}
public partial class IdentityProviderResponse<T> where T: IdentityProvider
{
[JsonPropertyName("identityProvider")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public T IdentityProvider { get; set; }
[JsonPropertyName("identityProviders")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public ICollection<T> IdentityProviders { get; set; }
private IDictionary<string, object> _additionalProperties;
[JsonExtensionData]
public IDictionary<string, object> AdditionalProperties
{
get { return _additionalProperties ?? (_additionalProperties = new Dictionary<string, object>()); }
set { _additionalProperties = value; }
}
}
Task<IdentityProviderResponse<T>> RetrieveIdentityProviderWithIdAsync<T>(string identityProviderId, CancellationToken cancellationToken = default) where T : IdentityProvider;
Describe the bug
The following command:
refitter https://api.hubspot.com/api-catalog-public/v1/apis/webhooks/v3 --namespace HubSpot --output ./GeneratedCode.cs
Generates the following:
public interface IWebhooksAPI
{
[Get("/webhooks/v3/{appId}/settings")]
Task<SettingsResponse> GetAll(int appId);
[Put("/webhooks/v3/{appId}/settings")]
Task<SettingsResponse> Configure(int appId, [Body] SettingsChangeRequest body);
[Delete("/webhooks/v3/{appId}/settings")]
Task Clear(int appId);
[Get("/webhooks/v3/{appId}/subscriptions")]
Task<SubscriptionListResponse> GetAll(int appId);
[Post("/webhooks/v3/{appId}/subscriptions")]
Task Create(int appId, [Body] SubscriptionCreateRequest body);
[Post("/webhooks/v3/{appId}/subscriptions/batch/update")]
Task<BatchResponseSubscriptionResponse> UpdateBatch(int appId, [Body] BatchInputSubscriptionBatchUpdateRequest body);
[Get("/webhooks/v3/{appId}/subscriptions/{subscriptionId}")]
Task<SubscriptionResponse> GetById(int subscriptionId, int appId);
[Delete("/webhooks/v3/{appId}/subscriptions/{subscriptionId}")]
Task Archive(int subscriptionId, int appId);
[Patch("/webhooks/v3/{appId}/subscriptions/{subscriptionId}")]
Task<SubscriptionResponse> Update(int subscriptionId, int appId, [Body] SubscriptionPatchRequest body);
}
Here there are two GetAll
methods defined that are clashing.
Support Key: kedfgny
OpenAPI Specifications
https://api.hubspot.com/api-catalog-public/v1/apis/webhooks/v3
Also happens with https://api.hubspot.com/api-catalog-public/v1/apis/crm/v3/properties
Per documentation file for --settings-file
: .. Specifying this option will ignore all other settings
.
This does not seem to be precisely correct as --output
parameter is still taken into account and allows to specify a name for a generated output file. This is a welcome feature as output file name doesn't seem to be configurable via a `.refitter' file.
Maybe it would help to reflect the option in the documentation.
When generating Refit Interfaces for operations with header parameters, if the header key contains a -
, the resulting code contains an AliasAs
, which is ignored by Refit when serializing the header parameters.
parameters:
- name: api-key
in: header
description: ''
required: false
schema:
type: string
[Header("api_key"), AliasAs("api-key")] string api_key
Describe the bug
Code generation fails if the output folder doesn't exist
Support Key: ptbddgt
OpenAPI Specifications
https://petstore3.swagger.io/api/v3/openapi.json
Additional context:
$ refitter https://petstore3.swagger.io/api/v3/openapi.json --output ../Boom/Kaboom/GeneratedCode.cs
Exception message
Could not find a part of the path 'C:\Boom\Kaboom\GeneratedCode.cs'.
Stack trace
System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Boom\Kaboom\GeneratedCode.cs'.
at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(System.String fullPath, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.IO.FileOptions options) at offset 161
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(System.String fullPath, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.IO.FileOptions options, System.Int64 preallocationSize) at offset 6
at System.IO.Strategies.OSFileStreamStrategy..ctor(System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.IO.FileOptions options, System.Int64 preallocationSize) at offset 49
at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.IO.FileOptions options, System.Int64 preallocationSize) at offset 24
at System.IO.Strategies.FileStreamHelpers.ChooseStrategy(System.IO.FileStream fileStream, System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.IO.FileOptions options, System.Int64 preallocationSize)
at System.IO.File.AsyncStreamWriter(System.String path, System.Text.Encoding encoding, System.Boolean append)
at System.IO.File.WriteAllTextAsync(System.String path, System.String contents, System.Text.Encoding encoding, System.Threading.CancellationToken cancellationToken) at offset 85
at Refitter.GenerateCommand.<ExecuteAsync>d__1.MoveNext() at offset 397 in /home/runner/work/refitter/refitter/src/Refitter/GenerateCommand.cs:line 45:col 13
sample openapi:
animal.json
sample refitter config file:
Animal.refitter
{
"openApiPath": "./animal.json",
"namespace": "Animal",
"naming": {
"useOpenApiTitle": false
},
"multipleInterfaces": "ByTag",
"operationNameTemplate": "{operationName}Async",
"outputFolder": "../Clients",
"outputFilename": "Animal.cs",
"codeGeneratorSettings": {
"requiredPropertiesMustBeDefined": true,
"generateDataAnnotations": true,
"anyType": "object",
"dateType": "System.DateTimeOffset",
"dateTimeType": "System.DateTimeOffset",
"timeType": "System.TimeSpan",
"timeSpanType": "System.TimeSpan",
"arrayType": "System.Collections.Generic.ICollection",
"dictionaryType": "System.Collections.Generic.IDictionary",
"arrayInstanceType": "System.Collections.ObjectModel.Collection",
"dictionaryInstanceType": "System.Collections.Generic.Dictionary",
"arrayBaseType": "System.Collections.ObjectModel.Collection",
"dictionaryBaseType": "System.Collections.Generic.Dictionary",
"propertySetterAccessModifier": "",
"generateImmutableArrayProperties": false,
"generateImmutableDictionaryProperties": false,
"handleReferences": false,
"jsonSerializerSettingsTransformationMethod": null,
"generateJsonMethods": false,
"enforceFlagEnums": false,
"inlineNamedDictionaries": false,
"inlineNamedTuples": true,
"inlineNamedArrays": false,
"generateOptionalPropertiesAsNullable": false,
"generateNullableReferenceTypes": false,
"generateNativeRecords": false,
"generateDefaultValues": true,
"inlineNamedAny": false,
"excludedTypeNames": []
}
}
Describe the bug
refitter https://api.getport.io/json -o IPortApi.cs
Refitter v0.7.3.37
Support key: 6mxy0om
Error:
Unexpected initial token 'Boolean' when populating object. Expected JSON object or array. Path
'paths./v1/blueprints/{blueprint_identifier}/permissions.patch.requestBody.content.application/json.schema.properties.ad
ditionalProperties', line 1, position 3314.
Error: Could not find color or style 'T'.
Support Key: 6mxy0om
OpenAPI Specifications
https://api.getport.io/json
Currently the generated code looks like this
[Post("/v1/Endpoint")]
Task EndpointPOST([Body] EndpointV1 body);
To support timeouts etc. it would be nice to get refitter to add the CancellationToken-parameter like this
[Post("/v1/Endpoint")]
Task EndpointPOST([Body] EndpointV1 body, CancellationToken cancellationToken = default);
I imagine this is done this way because generators don't have access to eachothers' output.
I'm currently looking at adding security schemes to the Api generator, but am unsure how to handle it. I suspect that it have to be separate functions, or maybe seperate interfaces, for each securityscheme defined one? But I'm unsure what would be the better way forward and wanted to discuss it.
Is your feature request related to a problem? Please describe.
To match our existing coding conventions and to increase code readability, it would be great to have a config parameter that allows to set a suffix to the generated contract types (like Dto --> PetDto).
Additional context
Thank you for your help.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.