Skip to content

Commit

Permalink
[Multipart][TCGC] Support @multipartBody for bodyParam of `SdkHttpO…
Browse files Browse the repository at this point in the history
…peration` (#1281)

supplement for PR #1090
- Support @multipartBody for `bodyParam` of `SdkHttpOperation`
- Only property of multipart body shall be added `multipartOptions` and
the property of base model shall have no `multipartOptions`
  • Loading branch information
msyyc committed Aug 5, 2024
1 parent e6d8370 commit 26b39f9
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: fix
packages:
- "@azure-tools/typespec-client-generator-core"
---

Support @multipartBody for `bodyParam` of `SdkHttpOperation`
2 changes: 1 addition & 1 deletion packages/typespec-client-generator-core/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ function getSdkHttpParameters(
const tspBody = httpOperation.parameters.body;
// we add correspondingMethodParams after we create the type, since we need the info on the type
const correspondingMethodParams: SdkModelPropertyType[] = [];
if (tspBody && tspBody?.bodyKind !== "multipart") {
if (tspBody) {
// if there's a param on the body, we can just rely on getSdkHttpParameter
if (tspBody.property && !isNeverOrVoidType(tspBody.property.type)) {
const getParamResponse = diagnostics.pipe(
Expand Down
10 changes: 9 additions & 1 deletion packages/typespec-client-generator-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1336,7 +1336,15 @@ export function getSdkModelPropertyType(
flatten: shouldFlattenProperty(context, type),
};
if (operation) {
diagnostics.pipe(updateMultiPartInfo(context, type, result, operation));
const httpOperation = getHttpOperationWithCache(context, operation);
if (
type.model &&
httpOperation.parameters.body &&
httpOperation.parameters.body.type === type.model
) {
// only add multipartOptions for property of multipart body
diagnostics.pipe(updateMultiPartInfo(context, type, result, operation));
}
}
return diagnostics.wrap(result);
}
Expand Down
8 changes: 8 additions & 0 deletions packages/typespec-client-generator-core/test/package.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3111,6 +3111,14 @@ describe("typespec-client-generator-core: package", () => {
strictEqual(op.bodyParam.kind, "body");
strictEqual(op.bodyParam.name, "testRequest");
deepStrictEqual(op.bodyParam.correspondingMethodParams, [documentMethodParam]);

const anonymousModel = runner.context.sdkPackage.models[0];
strictEqual(anonymousModel.properties.length, 1);
strictEqual(anonymousModel.properties[0].kind, "property");
strictEqual(anonymousModel.properties[0].isMultipartFileInput, true);
ok(anonymousModel.properties[0].multipartOptions);
strictEqual(anonymousModel.properties[0].multipartOptions.isFilePart, true);
strictEqual(anonymousModel.properties[0].multipartOptions.isMulti, false);
});

it("anonymous model with @body should not be spread", async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1502,4 +1502,71 @@ describe("typespec-client-generator-core: model types", () => {
ok(inputModel);
strictEqual(inputModel.usage, UsageFlags.Input | UsageFlags.Xml);
});

it("check bodyParam for @multipartBody", async function () {
await runner.compileWithBuiltInService(`
model Address {
city: string;
}
model MultiPartRequest{
id?: HttpPart<string>;
profileImage: HttpPart<bytes>;
address: HttpPart<Address>;
picture: HttpPart<File>;
}
@post
op upload(@header contentType: "multipart/form-data", @multipartBody body: MultiPartRequest): void;
`);
const formDataMethod = runner.context.sdkPackage.clients[0].methods[0];
strictEqual(formDataMethod.kind, "basic");
strictEqual(formDataMethod.name, "upload");
strictEqual(formDataMethod.parameters.length, 2);

strictEqual(formDataMethod.parameters[0].name, "contentType");
strictEqual(formDataMethod.parameters[0].type.kind, "constant");
strictEqual(formDataMethod.parameters[0].type.value, "multipart/form-data");

strictEqual(formDataMethod.parameters[1].name, "body");
strictEqual(formDataMethod.parameters[1].type.kind, "model");
strictEqual(formDataMethod.parameters[1].type.name, "MultiPartRequest");

const formDataOp = formDataMethod.operation;
strictEqual(formDataOp.parameters.length, 1);
ok(formDataOp.parameters.find((x) => x.name === "contentType" && x.kind === "header"));

const formDataBodyParam = formDataOp.bodyParam;
ok(formDataBodyParam);
strictEqual(formDataBodyParam.type.kind, "model");
strictEqual(formDataBodyParam.type.name, "MultiPartRequest");
strictEqual(formDataBodyParam.correspondingMethodParams.length, 1);
strictEqual(formDataBodyParam.type.properties.length, 4);
strictEqual(formDataBodyParam.type.properties[0].name, "id");
strictEqual(formDataBodyParam.type.properties[0].type.kind, "string");
strictEqual(formDataBodyParam.type.properties[1].name, "profileImage");
strictEqual(formDataBodyParam.type.properties[1].type.kind, "bytes");
strictEqual(formDataBodyParam.type.properties[2].name, "address");
strictEqual(formDataBodyParam.type.properties[2].type.kind, "model");
strictEqual(formDataBodyParam.type.properties[2].type.name, "Address");
strictEqual(formDataBodyParam.type.properties[3].name, "picture");
strictEqual(formDataBodyParam.type.properties[3].type.kind, "model");
strictEqual(formDataBodyParam.type.properties[3].type.name, "File");
});

it("check multipartOptions for property of base model", async function () {
await runner.compileWithBuiltInService(`
model MultiPartRequest{
fileProperty: HttpPart<File>;
}
@post
op upload(@header contentType: "multipart/form-data", @multipartBody body: MultiPartRequest): void;
`);
const models = runner.context.sdkPackage.models;
const fileModel = models.find((x) => x.name === "File");
ok(fileModel);
for (const p of fileModel.properties) {
strictEqual(p.kind, "property");
strictEqual(p.isMultipartFileInput, false);
strictEqual(p.multipartOptions, undefined);
}
});
});

0 comments on commit 26b39f9

Please sign in to comment.