Method Inputs
This document outlines the method input signatures that language emitters will generate.
Basic​
HTTP Get​
- TypeSpec
- Python
- CSharp
- Typescript
- Java
- Go
@get
op get(): User;
def get() -> User:
...
//protocol method
public virtual async Task<Response> GetUserAsync(RequestContext context){}
public virtual Response GetUser(RequestContext context){}
//convenience method
public virtual async Task<Response<User>> GetUser(CancellationToken cancellationToken = default)
public virtual Response<User> GetUser(CancellationToken cancellationToken = default)
// from user experience perspective
// RLC
export interface GetUser200Response extends HttpResponse {
status: "200";
body: User;
}
export type DemoServiceContext = Client & {
path: {
/** Resource for '/analyze' has methods for the following verbs: post */
(path: "/users"): {
get(
options: RequestParameters,
): StreamableMethod<GetUser200Response | GetUserDefaultResponse>;
};
};
};
// Modular Api Layer
export async function get(): Promise<User>;
// Modular classical client layer
export class DemoServiceClient {
get(options: GetUserOptionalParams): Promise<User>;
}
public User get();
type ClientGetOptions struct {
}
type ClientGetResponse struct {
}
func (client *Client) Get(ctx context.Context, options *ClientGetOptions) (ClientGetResponse, error)
HTTP Post​
- TypeSpec
- Python
- CSharp
- Typescript
- Java
- Go
@post
op post(@body body: User): void;
For model inputs, Python automatically generates an overload that allows SDK users to input through a file stream.
@overload
def post(body: User, **kwargs: Any) -> None:
...
@overload
def post(body: JSON, **kwargs: Any) -> None:
...
@overload
def post(body: IO[bytes], **kwargs: Any) -> None:
...
def post(body: [User, JSON, IO[bytes]], **kwargs: Any) -> None:
...
//protocol method
public virtual async Task<Response> PostAsync(RequestContent content, RequestContext context = null)
public virtual Response Post(RequestContent content, RequestContext context = null)
//convenience method
public virtual async Task<Response> PostAsync(User user, CancellationToken cancellationToken = default)
public virtual Response Post(User user, CancellationToken cancellationToken = default)
// from user experience perspective
export type DemoServiceContext = Client & {
path: {
/** Resource for '/completions' has methods for the following verbs: post */
(path: "/users"): {
post(
options: {
body: User;
} & RequestParameters,
): StreamableMethod<PostUserDefaultResponse>;
};
};
};
// Modular Api Layer
export async function post(body: User, options: PostOptionalParams): Promise<void>;
// Modular classical client layer
export class DemoServiceClient {
post(body: User, options: PostOptionalParams): Promise<void>;
}
public void post(User user);
type ClientPostOptions struct {
}
type ClientPostResponse struct {
}
func (client *Client) Post(ctx context.Context, user User, options *ClientPostOptions) (ClientPostResponse, error)
Spread​
Please exercise caution when using the spread feature.
- The model to be spread should have fewer than 6 settable properties. See simple methods.
- The model to be spread should remain stable across api-versions. Adding an optional property across api-versions could result in one additional method overload in SDK client.
- The model to be spread should not be used in JSON Merge Patch.
Alias​
- TypeSpec
- Python
- CSharp
- Typescript
- Java
- Go
alias User = {
firstName: string;
lastName: string;
};
@post
op upload(...User): void;
For Python, we will also generate the overloads described in the HTTP Post section, but will omit them for brevity.
def upload(first_name: str, last_name: str) -> None:
...
//protocol method
public virtual async Task<Response> UploadAsync(RequestContent content, RequestContext context = null)
public virtual Response Upload(RequestContent content, RequestContext context = null)
//convenience method
public virtual async Task<Response> UploadAsync(string firstName, string lastName, CancellationToken cancellationToken = default)
public virtual Response Upload(string firstName, string lastName, CancellationToken cancellationToken = default)
// from user experience perspective
export type DemoServiceContext = Client & {
path: {
/** Resource for '/completions' has methods for the following verbs: post */
(path: "/users"): {
post(
options: {
body: {
firstName: string;
lastName: string;
};
} & RequestParameters,
): StreamableMethod<PostUserDefaultResponse>;
};
};
};
// Modular Api Layer
export async function upload(
firstName: string,
lastName: string,
options: UploadOptionalParams,
): Promise<void>;
// Modular classical client layer
export class DemoServiceClient {
upload(firstName: string, lastName: string, options: UploadOptionalParams): Promise<void>;
}
public void upload(String firstName, String lastName);
type ClientUploadOptions struct {
}
type ClientUploadResponse struct {
}
func (client *Client) Upload(ctx context.Context, firstName string, lastName string, options *ClientUploadOptions) (ClientUploadResponse, error)
Alias with @header/@query/@path properties​
- TypeSpec
- Python
- CSharp
- Typescript
- Java
- Go
alias User = {
@path id: string;
firstName: string;
lastName: string;
};
op upload(...User): void;
For Python, we will also generate the overloads described in the HTTP Post section, but will omit them for brevity.
def upload(self, id: str, first_name: str, last_name: str, *, content_type: str = "application/json") -> None:
...
//protocol method
public virtual async Task<Response> UploadAsync(string id, RequestContent content, RequestContext context = null)
public virtual Response Upload(string id, RequestContent content, RequestContext context = null)
//convenience method
public virtual async Task<Response> UploadAsync(string id, string firstName, string lastName, CancellationToken cancellationToken = default)
public virtual Response Upload(string id, string firstName, string lastName, CancellationToken cancellationToken = default)
// from user experience perspective
export type DemoServiceContext = Client & {
path: {
/** Resource for '/completions' has methods for the following verbs: post */
(
path: "/users/{id}",
id,
): {
post(
options: {
body: {
firstName: string;
lastName: string;
};
} & RequestParameters,
): StreamableMethod<PostUserDefaultResponse>;
};
};
};
// Modular Api Layer
export async function upload(
id: string,
firstName: string,
lastName: string,
options: UploadOptionalParams,
): Promise<void>;
// Modular classical client layer
export class DemoServiceClient {
upload(
id: string,
firstName: string,
lastName: string,
options: UploadOptionalParams,
): Promise<void>;
}
public void upload(String id, String firstName, String lastName);
type ClientUploadOptions struct {
}
type ClientUploadResponse struct {
}
func (client *Client) Upload(ctx context.Context, id string, firstName string, lastName string, options *ClientUploadOptions) (ClientUploadResponse, error)
Named model​
- TypeSpec
- Python
- CSharp
- Typescript
- Java
- Go
model User {
firstName: string;
lastName: string;
}
op upload(...User): void;
For Python, we will also generate the overloads described in the HTTP Post section, but will omit them for brevity.
def upload(self, first_name: str, last_name: str, *, content_type: str = "application/json") -> None:
...
public partial class User
{
public User(string firstName, string lastName) { }
public string FirstName { get; }
public string LastName { get; }
}
//protocol method
public virtual async Task<Response> UploadAsync(RequestContent content, RequestContext context = null)
public virtual Response Upload(RequestContent content, RequestContext context = null)
//convenience method
public virtual async Task<Response> UploadAsync(User user, CancellationToken cancellationToken = default)
public virtual Response Upload(string firstName, string lastName, CancellationToken cancellationToken = default)
// from user experience perspective
export type DemoServiceContext = Client & {
path: {
/** Resource for '/completions' has methods for the following verbs: post */
(path: "/users"): {
post(
options: {
body: {
firstName: string;
lastName: string;
};
} & RequestParameters,
): StreamableMethod<PostUserDefaultResponse>;
};
};
};
// Modular Api Layer
export async function upload(
firstName: string,
lastName: string,
options: UploadOptionalParams,
): Promise<void>;
// Modular classical client layer
export class DemoServiceClient {
upload(firstName: string, lastName: string, options: UploadOptionalParams): Promise<void>;
}
public void upload(String firstName, String lastName);
type ClientUploadOptions struct {
}
type ClientUploadResponse struct {
}
func (client *Client) Upload(ctx context.Context, firstName string, lastName string, options *ClientUploadOptions) (ClientUploadResponse, error)
Model with @body
property​
- TypeSpec
- Python
- CSharp
- Typescript
- Java
- Go
model User {
firstName: string;
lastName: string;
}
model UserRequest {
@body user: User;
}
op upload(...UserRequest): void;
For Python, we will also generate the overloads described in the HTTP Post section, but will omit them for brevity.
def upload(self, body: [User, JSON, IO[bytes]], *, content_type: str = "application/json") -> None:
...
public partial class User
{
public User(string firstName, string lastName){}
public string FirstName { get; }
public string LastName { get; }
}
//protocol method
public virtual async Task<Response> UploadAsync(RequestContent content, RequestContext context = null)
public virtual Response Upload(RequestContent content, RequestContext context = null)
//convenience method
public virtual async Task<Response> UploadAsync(User user, CancellationToken cancellationToken = default)
public virtual Response Upload(User user, CancellationToken cancellationToken = default)
// from user experience perspective
export type DemoServiceContext = Client & {
path: {
/** Resource for '/completions' has methods for the following verbs: post */
(path: "/users"): {
post(
options: {
body: User;
} & RequestParameters,
): StreamableMethod<PostUserDefaultResponse>;
};
};
};
// Modular Api Layer
export async function upload(user: User, options: UploadOptionalParams): Promise<void>;
// Modular classical client layer
export class DemoServiceClient {
upload(user: User, options: UploadOptionalParams): Promise<void>;
}
// Model class
@Immutable
public final class User implements JsonSerializable<User> {
public User(String firstName, String lastName);
public String getFirstName();
public String getLastName();
}
// Client API
public void upload(User user);
type User struct {
firstName *string
lastName *string
}
type ClientUploadOptions struct {
}
type ClientUploadResponse struct {
}
func (client *Client) Upload(ctx context.Context, user User, options *ClientUploadOptions) (ClientUploadResponse, error)
Model with @header/@query/@path properties​
- TypeSpec
- Python
- CSharp
- Typescript
- Java
- Go
model BlobProperties {
@path
name: string;
@header testHeader: string;
}
@route("blob_properties/{name}")
op getBlobProperties(...BlobProperties): void;
For Python, we will also generate the overloads described in the HTTP Post section, but will omit them for brevity.
def get_blob_properties(self, name: str, *, test_header: string, content_type: str = "application/json") -> None:
...
//protocol method
public virtual async Task<Response> GetBlobPropertiesAsync(string name, string testHeader, RequestContext context = null)
public virtual Response GetBlobProperties(string name, string testHeader, RequestContext context = null)
// from user experience perspective
export type DemoServiceContext = Client & {
path: {
/** Resource for '/completions' has methods for the following verbs: post */
(path: "/blob_properties/{name}", name): {
post(
options: {
headers: {
"test-header": string;
} & RawHttpHeaders
} & RequestParameters
): StreamableMethod<PostUserDefaultResponse>;
};
};
};
// Modular Options
export interface GetBlobPropertiesOptionalParams extends OperationOptions {
requestOptions: {
headers: {
test-header: string
} & RawHttpHeadersInput
}
}
// Modular api layer
export async function getBlobProperties(name: string, options: GetBlobPropertiesOptionalParams): Promise<void>;
// Modular classical client layer
export class DemoServiceClient {
getBlobProperties(name: string, options: GetBlobPropertiesOptionalParams): Promise<void>
}
public void getBlobProperties(String name, String testHeader);
type ClientGetBlobPropertiesOptions struct {
}
type ClientGetBlobPropertiesResponse struct {
}
func (client *Client) GetBlobProperties(ctx context.Context, name string, testHeader string, options *ClientGetBlobPropertiesOptions) (ClientGetBlobPropertiesResponse, error)
Model mixed with normal and @header/@query/@path properties​
- TypeSpec
- Python
- CSharp
- Typescript
- Java
- Go
model Schema {
@header contentType: "application/json";
schema: bytes;
}
@post
op register(...Schema): void;
For Python, we will also generate the overloads described in the HTTP Post section, but will omit them for brevity.
class Schema:
schema: bytes
def register(self, body: [Schema, JSON, IO[bytes]], *, content_type: str = "application/json") -> None:
...
public partial class Schema
{
public Schema(BinaryData schemaProperty){}
public BinaryData SchemaProperty { get; }
}
//protocol method
public virtual async Task<Response> RegisterAsync(RequestContent content, RequestContext context = null)
public virtual Response Register(RequestContent content, RequestContext context = null)
//convenience method
public virtual async Task<Response> RegisterAsync(Schema schema, CancellationToken cancellationToken = default)
public virtual Response Register(Schema schema, CancellationToken cancellationToken = default)
// from user experience perspective
export type DemoServiceContext = Client & {
path: {
/** Resource for '/completions' has methods for the following verbs: post */
(path: "/schemaRegister"): {
post(
options: {
headers: {
"content-type": "application/json";
} & RawHttpHeaders;
body: {
schema: string;
};
} & RequestParameters,
): StreamableMethod<PostUserDefaultResponse>;
};
};
};
// Modular model
export interface Schema {
schema: string;
}
// Modular api layer
export async function register(
body: Schema,
options: GetBlobPropertiesOptionalParams,
): Promise<void>;
// Modular classical client layer
export class DemoServiceClient {
getBlobProperties(body: Schema, options: GetBlobPropertiesOptionalParams): Promise<void>;
}
// Model class
@Immutable
public final class Schema implements JsonSerializable<Schema> {
public Schema(byte[] schema);
public byte[] getSchema();
}
// Client API
public void register(Schema schema);
type ClientRegisterOptions struct {
}
type ClientRegisterResponse struct {
}
func (client *Client) Register(ctx context.Context, schema []byte, options *ClientRegisterOptions) (ClientRegisterResponse, error)
Using Azure.Core.ResourceOperations template​
Resource create and update operations are not impacted by spread since they all have explicit defined body parameter. Only resource action operations are impacted by spread.
If the action parameter is a model, then the model will be spread.
- TypeSpec
- Python
- CSharp
- Typescript
- Java
- Go
@resource("widgets")
model Widget {
@key("widgetName")
name: string;
}
model RepairInfo {
problem: string;
contact: string;
}
model RepairResult {
reason: string;
info: string;
}
alias Operations = Azure.Core.ResourceOperations<{}>;
op scheduleRepairs is Operations.ResourceAction<Widget, RepairInfo, RepairResult>;
For Python, we will also generate the overloads described in the HTTP Post section, but will omit them for brevity.
class RepairInfo:
problem: str
contact: str
class RepairResult:
reason: str
info: str
def scheduleRepairs(self, widget_name: str, problem: str, contact: str, *, content_type: str = "application/json") -> RepairResult:
...
// from user experience perspective
export interface RepairInfo {
problem: string;
contact: string;
}
export type WidgetServiceContext = Client & {
path: {
(
path: "/widgets/{widgetName}:scheduleRepairs",
widgetName: string,
): {
post(
options: {
body: RepairInfo;
} & RequestParameters,
): StreamableMethod<PostUserDefaultResponse>;
};
};
};
// Modular api layer
export async function scheduleRepairs(
context: Client,
widgetName: string,
problem: string,
contact: string,
options: ScheduleRepairsOptionalParams = { requestOptions: {} },
): Promise<RepairResult>;
// Modular classical client layer
export class WidgetServiceClient {
scheduleRepairs(
widgetName: string,
problem: string,
contact: string,
options: ScheduleRepairsOptionalParams = { requestOptions: {} },
): Promise<RepairResult>;
}
public RepairResult scheduleRepairs(String widgetName, String problem, String contact);
type ClientScheduleRepairsOptions struct {
}
type RepairResult struct {
reason *string
info *string
}
type ClientScheduleRepairsResponse struct {
RepairResult
}
func (client *Client) ScheduleRepairs(ctx context.Context, widgetName string, problem string, contact string, options *ClientScheduleRepairsOptions) (ClientScheduleRepairsResponse, error)
If you want to keep the model, you have two options to prevent spreading:
@override
- If you don't want to do client customizations, you could use a wrapper to explicitly set the body to prevent spread.
- TypeSpec
- Python
- CSharp
- Typescript
- Java
- Go
1. @override
​
The @override
decorator allows you to replace the default client method generated by TCGC based on your service definition.
If your service definition spreads a model into the method signature, but you prefer that the generated client SDKs maintain the model intact, the @override
decorator provides a solution.
Additionally, you can specify a language scope
to limit the changes to a specific language emitter.
// client.tsp
namespace Widget.Client;
op scheduleRepairs(
body: RepairInfo,
`api-version`: Azure.Core.Foundations.ApiVersionParameter,
): RepairResult;
@@override(Widget.Service.scheduleRepairs, Widget.Client.scheduleRepairs);
2. wrapper​
If you prefer not to implement customizations in client.tsp
, you can add @bodyRoot
to the input in main.tsp
prior to passing the model to the template.
// main.tsp
namespace Widget.Service;
@resource("widgets")
model Widget {
@key("widgetName")
name: string;
}
model RepairInfo {
problem: string;
contact: string;
}
model RepairResult {
reason: string;
info: string;
}
alias Operations = Azure.Core.ResourceOperations<{}>;
alias BodyParameter<
T,
TName extends valueof string = "body",
TDoc extends valueof string = "Body parameter."
> = {
@doc(TDoc)
@friendlyName(TName)
@bodyRoot
body: T;
};
op scheduleRepairs is Operations.ResourceAction<Widget, BodyParameter<RepairInfo>, RepairResult>;
For Python, we will also generate the overloads described in the HTTP Post section, but will omit them for brevity.
class RepairInfo:
problem: str
contact: str
class RepairResult:
reason: str
info: str
def scheduleRepairs(self, body: [Schema, JSON, IO[bytes]], *, content_type: str = "application/json") -> RepairResult:
...
// from user experience perspective
export interface RepairInfo {
problem: string;
contact: string;
}
export type WidgetServiceContext = Client & {
path: {
(
path: "/widgets/{widgetName}:scheduleRepairs",
widgetName: string,
): {
post(
options: {
body: RepairInfo;
} & RequestParameters,
): StreamableMethod<PostUserDefaultResponse>;
};
};
};
// Modular api layer
export async function scheduleRepairs(
context: Client,
widgetName: string,
body: RepairInfo,
options: ScheduleRepairsOptionalParams = { requestOptions: {} },
): Promise<RepairResult>;
// Modular classical client layer
export class WidgetServiceClient {
scheduleRepairs(
widgetName: string,
body: RepairInfo,
options: ScheduleRepairsOptionalParams = { requestOptions: {} },
): Promise<RepairResult>;
}
// Model class
@Immutable
public final class RepairInfo implements JsonSerializable<RepairInfo> {
public RepairInfo(String problem, String contact);
public String getProblem();
public String getContact();
}
@Immutable
public final class RepairResult implements JsonSerializable<RepairResult> {
public String getReason();
public String getInfo();
}
// Client API
public RepairResult scheduleRepairs(String widgetName, RepairInfo body);
type RepairInfo struct {
problem *string
contact *string
}
type ClientScheduleRepairsOptions struct {
}
type RepairResult struct {
reason *string
info *string
}
type ClientScheduleRepairsResponse struct {
RepairResult
}
func (client *Client) ScheduleRepairs(ctx context.Context, widgetName string, body RepairInfo, options *ClientScheduleRepairsOptions) (ClientScheduleRepairsResponse, error)