Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions generators/csharp/base/src/AsIs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const AsIsFiles = {
Pager: "Pager.Template.cs",
// HTTP
ApiResponse: "ApiResponse.Template.cs",
RawResponse: "RawResponse.Template.cs",
BaseRequest: "BaseRequest.Template.cs",
EmptyRequest: "EmptyRequest.Template.cs",
EncodingCache: "EncodingCache.Template.cs",
Expand Down
26 changes: 26 additions & 0 deletions generators/csharp/base/src/asIs/RawResponse.Template.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using global::System.Net;
using global::System.Net.Http.Headers;

namespace <%= namespace%>;

/// <summary>
/// Represents an API response with the deserialized body and HTTP metadata.
/// </summary>
/// <typeparam name="T">The type of the response body.</typeparam>
public record RawResponse<T>
{
/// <summary>
/// The deserialized response body.
/// </summary>
public required T Body { get; init; }

/// <summary>
/// The HTTP status code of the response.
/// </summary>
public required int StatusCode { get; init; }

/// <summary>
/// The HTTP response headers.
/// </summary>
public required HttpResponseHeaders Headers { get; init; }
}
8 changes: 8 additions & 0 deletions generators/csharp/base/src/context/GeneratorContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,14 @@ export abstract class GeneratorContext extends AbstractGeneratorContext {
});
}

public getRawSubpackageClassReference(subpackage: Subpackage): ast.ClassReference {
return this.csharp.classReference({
name: `Raw${subpackage.name.pascalCase.unsafeName}Client`,
namespace: this.getNamespaceFromFernFilepath(subpackage.fernFilepath),
origin: this.model.explicit(subpackage, "Raw")
});
}

/**
* Returns the service with the given id
* @param serviceId
Expand Down
17 changes: 17 additions & 0 deletions generators/csharp/codegen/src/context/generation-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,12 @@ export class Generation {
origin: this.model.staticExplicit(this.names.classes.rootClientForSnippets),
namespace: this.namespaces.root
}),
/** The raw response client class for root client */
RawRootClient: () =>
this.csharp.classReference({
origin: this.model.staticExplicit(`Raw${this.names.classes.rootClient}`),
namespace: this.namespaces.root
}),
/** Base exception class for API errors (HTTP 4xx/5xx responses) */
BaseApiException: () =>
this.csharp.classReference({
Expand Down Expand Up @@ -856,6 +862,17 @@ export class Generation {
namespace: this.namespaces.publicCore,
generics: genericType ? [genericType] : undefined
});
},
/**
* Generic raw response wrapper containing body and HTTP metadata.
* @param bodyType - The type of the response body
*/
RawResponse: (bodyType: ast.Type | ast.ClassReference): ast.ClassReference => {
return this.csharp.classReference({
origin: this.model.staticExplicit("RawResponse"),
namespace: this.namespaces.publicCore,
generics: [bodyType]
});
}
});
public Primitive = lazy({
Expand Down
16 changes: 16 additions & 0 deletions generators/csharp/sdk/src/SdkGeneratorCli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ import { IdempotentRequestOptionsInterfaceGenerator } from "./options/Idempotent
import { RequestOptionsGenerator } from "./options/RequestOptionsGenerator";
import { RequestOptionsInterfaceGenerator } from "./options/RequestOptionsInterfaceGenerator";
import { buildReference } from "./reference/buildReference";
import { RawRootClientGenerator } from "./root-client/RawRootClientGenerator";
import { RootClientGenerator } from "./root-client/RootClientGenerator";
import { SdkGeneratorContext } from "./SdkGeneratorContext";
import { RawSubPackageClientGenerator } from "./subpackage-client/RawSubPackageClientGenerator";
import { SubPackageClientGenerator } from "./subpackage-client/SubPackageClientGenerator";
import { WebSocketClientGenerator } from "./websocket/WebsocketClientGenerator";
import { WrappedRequestGenerator } from "./wrapped-request/WrappedRequestGenerator";
Expand Down Expand Up @@ -137,7 +139,16 @@ export class SdkGeneratorCLI extends AbstractCsharpGeneratorCli {
});
context.project.addSourceFiles(subClient.generate());

// Generate raw client for subpackages with endpoints
if (subpackage.service != null && service != null) {
const rawSubClient = new RawSubPackageClientGenerator({
context,
subpackage,
serviceId: subpackage.service,
service
});
context.project.addSourceFiles(rawSubClient.generate());

this.generateRequests(context, service, subpackage.service);
}
}
Expand Down Expand Up @@ -196,6 +207,11 @@ export class SdkGeneratorCLI extends AbstractCsharpGeneratorCli {
const rootServiceId = context.ir.rootPackage.service;
if (rootServiceId != null) {
const service = context.getHttpService(rootServiceId);

// Generate raw root client if root has endpoints
const rawRootClient = new RawRootClientGenerator(context);
context.project.addSourceFiles(rawRootClient.generate());

this.generateRequests(
context,
service ?? fail(`Service with id ${rootServiceId} not found`),
Expand Down
2 changes: 1 addition & 1 deletion generators/csharp/sdk/src/SdkGeneratorContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ export class SdkGeneratorContext extends GeneratorContext {
}

public getPublicCoreAsIsFiles(): string[] {
const files = [AsIsFiles.FileParameter];
const files = [AsIsFiles.FileParameter, AsIsFiles.RawResponse];
if (this.settings.generateNewAdditionalProperties) {
files.push(AsIsFiles.Json.AdditionalProperties);
}
Expand Down
17 changes: 12 additions & 5 deletions generators/csharp/sdk/src/endpoint/EndpointGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,22 @@ export class EndpointGenerator extends AbstractEndpointGenerator {
rawClientReference,
rawGrpcClientReference,
rawClient,
grpcClientInfo
grpcClientInfo,
generateRawResponse = false,
rawResponseClientReference
}: {
serviceId: ServiceId;
endpoint: HttpEndpoint;
rawClientReference: string;
rawGrpcClientReference: string;
rawGrpcClientReference?: string;
rawClient: RawClient;
grpcClientInfo: GrpcClientInfo | undefined;
grpcClientInfo?: GrpcClientInfo | undefined;
generateRawResponse?: boolean;
/** If provided, generate wrapper methods that delegate to this raw response client */
rawResponseClientReference?: string;
}
) {
if (this.isGrpcEndpoint(grpcClientInfo, endpoint)) {
if (this.isGrpcEndpoint(grpcClientInfo, endpoint) && rawGrpcClientReference != null) {
this.grpc.generate(cls, {
serviceId,
endpoint,
Expand All @@ -47,7 +52,9 @@ export class EndpointGenerator extends AbstractEndpointGenerator {
serviceId,
endpoint,
rawClientReference,
rawClient
rawClient,
generateRawResponse,
rawResponseClientReference
});
}
}
Expand Down
Loading
Loading