Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.NET Client Patterns: Service description for bytes upload should generate client following unbranded .NET client patterns #4909

Open
annelo-msft opened this issue Oct 29, 2024 · 7 comments
Labels
compiler:core Issues for @typespec/compiler

Comments

@annelo-msft
Copy link
Member

annelo-msft commented Oct 29, 2024

TypeSpec file:

import "@typespec/http";
import "@typespec/rest";

@service({
    title: "PutBytes",
  })
   
  namespace PutBytes;
   
  using TypeSpec.Http;
  using TypeSpec.Rest;
     
  interface PutBytesClient {
    @put @route("upload") Upload(document: bytes) : void;
  }

Expected client output

  • Client should have a public constructor that takes endpoint and client options
  • Client constructor should validate arguments, assign endpoint, create options if needed, and create pipeline
  • Convenience methods should take CancellationToken parameters
  • Model types should not be defined or used if BinaryContent can be created directly from input
  • Protocol methods should take a nullable RequestOptions parameter. Should be optional where parameter types are different from convenience overloads.
  • Rest file should only create instances of classifiers used by the client
  • Rest file should not re-allocate a classifier that has already been allocated
  • Request creation helpers should use correct status code classifier for PUT (200 or 201, see Azure API Guidelines)
  • Request creation helpers should add correct header type (Content-Type should be application/octet-stream for byte uploads)
  • Emitted internal helper files should not have methods that aren't used by the client
  • Emitted internal helper files should be added if needed by the client
  • Nullable annotations should be used
  • No subclient factory method should be added when there are no subclients
  • No internal constructors should be added when they are not called
  • (would be nice) use file scoped namespace declarations

A diff of expected generator output compared to current generator output is here: annelo-msft#2

@annelo-msft annelo-msft added the emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp label Oct 29, 2024
@annelo-msft annelo-msft changed the title .NET Client Patterns: Service description to upload bytes should generate client following unbranded .NET client patterns .NET Client Patterns: Service description for bytes upload should generate client following unbranded .NET client patterns Oct 29, 2024
@JoshLove-msft
Copy link
Contributor

JoshLove-msft commented Oct 30, 2024

Currently in order to generate the content type and a binary upload method that doesn't serialize a model, the tsp would need to look like this - note we add the contentType header and body decorator:

  interface PutBytesClient {
    @put @route("upload") Upload(@header contentType: "application/octet-stream", @body document: bytes) : void;
  }

@JoshLove-msft
Copy link
Contributor

/cc @schaabs for thoughts on the tsp requirements mentioned in previous comment.

@annelo-msft
Copy link
Member Author

Adding the context that @KrzysztofCwalina raised the concern with me directly that those decorators would need to be added to obtain a client that used the headers and didn't write those models.

I am happy to defer to @schaabs and @KrzysztofCwalina regarding whether that is the TypeSpec we would like customers/partners to need to write in order to have our .NET generator write a client that can upload application/octet-stream bytes to a service. For me personally, I would wonder the following about:

@put @route("upload") Upload(document: bytes) : void;
  1. When does it make sense that this TypeSpec would use application/json ContentType header? Is it common?
    • My thinking with this question is -- ideally the most common desired outcome would map to the simplest TypeSpec. It would be preferable if TypeSpec authors needed to write more TypeSpec to satisfy uncommon scenarios, rather than the inverse
  2. Does it make sense that bytes would need a model to support it for the most common case?
    • My thinking here is that we have .NET types (in BCL, Azure.Core, and SCM) that map to bytes. Ideally, these would be used to represent the input parameters of the client method for this service operation in the most common case. Model types make sense when more than this is needed (to provide what is essentially a POCO to group primitives and other BCL/Core types that need to be assembled to write the content of a request to send to the service). If a TypeSpec type has a corresponding .NET BCL/Core type, I am not sure I see the benefit of adding a model to the public API for that -- or having an internal type to wrap it, since that would add performance overhead in terms of allocations and possibly CPU time as well.

@JoshLove-msft
Copy link
Contributor

JoshLove-msft commented Oct 30, 2024

As part of determining the tsp -> C# story, we should keep in mind what the experience would look like across other language generators. It would be odd if a single tsp generated semantically different clients across the languages that we support, which makes me wonder if these type of inferences would be better to make further upstream in TCGC so that all the language emitters get it for free.

@JoshLove-msft JoshLove-msft added the compiler:core Issues for @typespec/compiler label Nov 5, 2024
@JoshLove-msft
Copy link
Contributor

Content-Type is required for HTTP, so the compiler should either default what it thinks the Content-Type should be, or it should error.

@JoshLove-msft
Copy link
Contributor

@tadelesh is this defaulted in TCGC?

@JoshLove-msft JoshLove-msft removed the emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp label Jan 16, 2025
@tadelesh
Copy link
Member

tadelesh commented Jan 17, 2025

for content type, it is defaulted by typespec http library. for the Upload operation, tcgc get the request body's content type as application/json, the only addition work tcgc does is to add a Content-Type header parameter if user does not explicitly define one, and for this case, the type for that header is a constant application/json.

another discussion about the default content type: #5408 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler:core Issues for @typespec/compiler
Projects
None yet
Development

No branches or pull requests

3 participants