Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions codegen/internal/generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ func (g *Generator) Run(doc *v3.Document) error {
if err := g.renderRoot(tmpl, rootData); err != nil {
return err
}
if err := g.renderApiVersion(tmpl, apiVersionTemplateData{
Namespace: g.config.Namespace,
ApiVersion: apiVersionFromSpec(doc),
}); err != nil {
return err
}

return nil
}
Expand Down Expand Up @@ -156,6 +162,24 @@ func (g *Generator) renderRoot(t *template.Template, data rootTemplateData) erro
return nil
}

func (g *Generator) renderApiVersion(t *template.Template, data apiVersionTemplateData) error {
targetDir := filepath.Join(g.config.OutputDir, "Http")
if err := os.MkdirAll(targetDir, 0o755); err != nil {
return fmt.Errorf("create http directory: %w", err)
}
filePath := filepath.Join(targetDir, "ApiVersion.g.cs")
file, err := os.Create(filePath)
if err != nil {
return fmt.Errorf("create api version file: %w", err)
}
defer file.Close()

if err := t.ExecuteTemplate(file, "api_version.tmpl", data); err != nil {
return fmt.Errorf("render api version template: %w", err)
}
return nil
}

func (g *Generator) renderModels(t *template.Template, models []modelTemplateData) error {
for _, model := range models {
var templateName string
Expand Down Expand Up @@ -1176,6 +1200,11 @@ type rootTemplateData struct {
Clients []clientTemplateData
}

type apiVersionTemplateData struct {
Namespace string
ApiVersion string
}

func toMethodParameters(params []parameterTemplateData) []methodParameter {
result := make([]methodParameter, 0, len(params))
for _, param := range params {
Expand All @@ -1188,6 +1217,16 @@ func toMethodParameters(params []parameterTemplateData) []methodParameter {
return result
}

func apiVersionFromSpec(doc *v3.Document) string {
if doc != nil && doc.Info != nil {
version := strings.TrimSpace(doc.Info.Version)
if version != "" {
return version
}
}
return "1.0.0"
}

func hasCollections(params []parameterTemplateData) bool {
for _, param := range params {
if param.IsCollection {
Expand Down
6 changes: 6 additions & 0 deletions codegen/internal/generator/templates/api_version.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace {{ .Namespace }};

internal static class ApiVersionInfo
{
internal const string Value = "{{ .ApiVersion }}";
}
67 changes: 67 additions & 0 deletions src/SumUp.Tests/RuntimeHeadersTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.Net.Http;
using System.Runtime.InteropServices;
using SumUp.Http;
using Xunit;

namespace SumUp.Tests;

public class RuntimeHeadersTests
{
[Fact]
public void CreateRequest_AddsRuntimeHeaders()
{
using var httpClient = new HttpClient { BaseAddress = new Uri("https://api.sumup.com") };
var options = new SumUpClientOptions();
var apiClient = new ApiClient(httpClient, options);

var request = apiClient.CreateRequest(HttpMethod.Get, "/ping");

AssertHeader(request, "X-Sumup-Api-Version", ApiVersionInfo.Value);
AssertHeader(request, "X-Sumup-Lang", "dotnet");
AssertHeader(request, "X-Sumup-Runtime", "dotnet");
AssertHeader(request, "X-Sumup-Os", GetExpectedOs());
AssertHeader(request, "X-Sumup-Arch", GetExpectedArch());

Assert.True(request.Headers.Contains("X-Sumup-Package-Version"));
Assert.True(request.Headers.Contains("X-Sumup-Runtime-Version"));
}

private static void AssertHeader(HttpRequestMessage request, string name, string expected)
{
Assert.True(request.Headers.TryGetValues(name, out var values));
Assert.Contains(expected, values);
}

private static string GetExpectedOs()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return "windows";
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return "linux";
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return "darwin";
}

return RuntimeInformation.OSDescription;
}

private static string GetExpectedArch()
{
return RuntimeInformation.OSArchitecture switch
{
Architecture.X64 => "x86_64",
Architecture.X86 => "x86",
Architecture.Arm64 => "arm64",
Architecture.Arm => "arm",
_ => RuntimeInformation.OSArchitecture.ToString().ToLowerInvariant()
};
}
}
1 change: 1 addition & 0 deletions src/SumUp/Http/ApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ internal HttpRequestMessage CreateRequest(HttpMethod method, string pathTemplate
request.Headers.Accept.Clear();
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.UserAgent.ParseAdd(_options.UserAgent);
RuntimeHeaders.Apply(request.Headers);

return request;
}
Expand Down
6 changes: 6 additions & 0 deletions src/SumUp/Http/ApiVersion.g.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace SumUp;

internal static class ApiVersionInfo
{
internal const string Value = "1.0.0";
}
68 changes: 68 additions & 0 deletions src/SumUp/Http/RuntimeHeaders.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Net.Http.Headers;
using System.Reflection;
using System.Runtime.InteropServices;

namespace SumUp.Http;

internal static class RuntimeHeaders
{
private const string Language = "dotnet";
private const string Runtime = "dotnet";

private static readonly string PackageVersion =
Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0";

private static readonly string OsName = GetOsName();
private static readonly string RuntimeArch = GetArchitecture();
private static readonly string RuntimeVersion = RuntimeInformation.FrameworkDescription;

internal static void Apply(HttpRequestHeaders headers)
{
SetHeader(headers, "X-Sumup-Api-Version", ApiVersionInfo.Value);
SetHeader(headers, "X-Sumup-Lang", Language);
SetHeader(headers, "X-Sumup-Package-Version", PackageVersion);
SetHeader(headers, "X-Sumup-Os", OsName);
SetHeader(headers, "X-Sumup-Arch", RuntimeArch);
SetHeader(headers, "X-Sumup-Runtime", Runtime);
SetHeader(headers, "X-Sumup-Runtime-Version", RuntimeVersion);
}

private static void SetHeader(HttpRequestHeaders headers, string name, string value)
{
headers.Remove(name);
headers.TryAddWithoutValidation(name, value);
}

private static string GetOsName()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return "windows";
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return "linux";
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return "darwin";
}

return RuntimeInformation.OSDescription;
}

private static string GetArchitecture()
{
return RuntimeInformation.OSArchitecture switch
{
System.Runtime.InteropServices.Architecture.X64 => "x86_64",
System.Runtime.InteropServices.Architecture.X86 => "x86",
System.Runtime.InteropServices.Architecture.Arm64 => "arm64",
System.Runtime.InteropServices.Architecture.Arm => "arm",
_ => RuntimeInformation.OSArchitecture.ToString().ToLowerInvariant()
};
}
}
Loading