Skip to content

Commit

Permalink
Support client request id modular and small fixes (#1985)
Browse files Browse the repository at this point in the history
* Ignore the custom client-request-id header in modular

* Remove the only item

* Remove the debug options

* Change test case namings

* Revert changes

* update changes

* update the test cases

* update the code

* update the code to fix modular issue

* Regen smoke and integration testing

* update test cases

* update the test cases

* update the isunexpected helper

* Fix int test issues

* Fix the test issue

* Fix this test issue

* update the test cases

* Add more ignored headers

* Refactoring

* Enable azure core cases

* adjust the positions

* Update .vscode/launch.json

* fix the issue bugs

* Update packages/typespec-ts/src/index.ts

* Fix small issue

* Remove useless codes

* Revert the changes for default response support

* Regenerate codes

* Revert changes in rlc int test

* Remove console.log code lines

* Update packages/typespec-ts/test/integration/encodeDatetime.spec.ts

* Update packages/typespec-ts/test/integration/encodeDatetime.spec.ts

* Update packages/typespec-ts/test/integration/encodeDatetime.spec.ts

* Update packages/typespec-ts/test/integration/encodeDatetime.spec.ts

* Update packages/typespec-ts/test/integration/encodeDatetime.spec.ts

* Revert changes

* fix lint issues

* Revert changes

* Update packages/typespec-ts/src/modular/helpers/operationHelpers.ts

Co-authored-by: Qiaoqiao Zhang <55688292+qiaozha@users.noreply.github.com>

* update the order

---------

Co-authored-by: Qiaoqiao Zhang <55688292+qiaozha@users.noreply.github.com>
  • Loading branch information
MaryGao and qiaozha committed Aug 29, 2023
1 parent 62cd637 commit 47adf85
Show file tree
Hide file tree
Showing 48 changed files with 829 additions and 196 deletions.
46 changes: 36 additions & 10 deletions packages/rlc-common/src/buildObjectTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ export function buildObjectInterfaces(
const objectInterfaces: InterfaceDeclarationStructure[] = [];

for (const objectSchema of objectSchemas) {
if (objectSchema.alias || objectSchema.outputAlias) {
if (
objectSchema.alias ||
objectSchema.outputAlias ||
objectSchema.fromCore
) {
continue;
}
const baseName = getObjectBaseName(objectSchema, schemaUsage);
Expand Down Expand Up @@ -417,18 +421,40 @@ export function getPropertySignature(
importedModels: Set<string>
): PropertySignatureStructure {
const propertyName = property.name;

const description = property.description;
let type =
generateForOutput(schemaUsage, property.usage) && property.outputTypeName
? property.outputTypeName
: property.typeName
? property.typeName
: property.type;
if (property.typeName && property.fromCore) {
importedModels.add(property.typeName);
let type;
const hasCoreInArray =
property.type === "array" &&
(property as any).items &&
(property as any).items.fromCore;
const hasCoreInRecord =
property.type === "dictionary" &&
(property as any).additionalProperties &&
(property as any).additionalProperties.fromCore;
if (hasCoreInArray && property.typeName) {
type = property.typeName;
importedModels.add(
(property as any).items.typeName ?? (property as any).items.name
);
} else if (hasCoreInRecord && property.typeName) {
type = property.typeName;
importedModels.add(
(property as any).additionalProperties.typeName ??
(property as any).additionalProperties.name
);
} else {
type =
generateForOutput(schemaUsage, property.usage) && property.outputTypeName
? property.outputTypeName
: property.typeName
? property.typeName
: property.type;
if (property.typeName && property.fromCore) {
importedModels.add(property.typeName);
type = property.typeName;
}
}

return {
name: propertyName,
...(description && { docs: [{ description }] }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { Client } from '@azure-rest/core-client';
import { ClientOptions } from '@azure-rest/core-client';
import { CreateHttpPollerOptions } from '@azure/core-lro';
import { ErrorModel } from '@azure-rest/core-client';
import { ErrorResponse } from '@azure-rest/core-client';
import { HttpResponse } from '@azure-rest/core-client';
import { KeyCredential } from '@azure/core-auth';
Expand Down Expand Up @@ -234,15 +235,6 @@ export interface DocumentContent {
value: string;
}

// @public
export interface ErrorModelOutput {
code: string;
details?: Array<ErrorModelOutput>;
innererror?: InnerErrorOutput;
message: string;
target?: string;
}

// @public
export interface ExtendedClinicalCodedElementOutput {
category?: string;
Expand Down Expand Up @@ -306,12 +298,6 @@ export type HealthInsightsClinicalMatchingClient = Client & {
path: Routes;
};

// @public
export interface InnerErrorOutput {
code?: string;
innererror?: InnerErrorOutput;
}

// @public (undocumented)
export function isUnexpected(response: GetJob200Response | GetJobDefaultResponse): response is GetJobDefaultResponse;

Expand Down Expand Up @@ -391,7 +377,7 @@ export interface TrialMatcherPatientResultOutput {
// @public
export interface TrialMatcherResultOutput {
readonly createdDateTime: string;
readonly errors?: Array<ErrorModelOutput>;
readonly errors?: Array<ErrorModel>;
readonly expirationDateTime: string;
readonly jobId: string;
readonly lastUpdateDateTime: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import { ErrorModel } from "@azure-rest/core-client";

/** The response for the Trial Matcher request. */
export interface TrialMatcherResultOutput {
/** A processing job identifier. */
Expand All @@ -18,33 +20,11 @@ export interface TrialMatcherResultOutput {
*/
readonly status: string;
/** An array of errors, if any errors occurred during the processing job. */
readonly errors?: Array<ErrorModelOutput>;
readonly errors?: Array<ErrorModel>;
/** The inference results for the Trial Matcher request. */
readonly results?: TrialMatcherResultsOutput;
}

/** The error object. */
export interface ErrorModelOutput {
/** One of a server-defined set of error codes. */
code: string;
/** A human-readable representation of the error. */
message: string;
/** The target of the error. */
target?: string;
/** An array of details about specific errors that led to this reported error. */
details?: Array<ErrorModelOutput>;
/** An object containing more specific information than the current object about the error. */
innererror?: InnerErrorOutput;
}

/** An object containing more specific information about the error. As per Microsoft One API guidelines - https://github.com/Microsoft/api-guidelines/blob/vNext/Guidelines.md#7102-error-condition-responses. */
export interface InnerErrorOutput {
/** One of a server-defined set of error codes. */
code?: string;
/** Inner error. */
innererror?: InnerErrorOutput;
}

/** The inference results for the Trial Matcher request. */
export interface TrialMatcherResultsOutput {
/** Results for the patients given in the request. */
Expand Down
10 changes: 6 additions & 4 deletions packages/typespec-ts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { join } from "path";
import { GenerationDirDetail, SdkContext } from "./utils/interfaces.js";
import { transformRLCOptions } from "./transform/transfromRLCOptions.js";
import { ModularCodeModel } from "./modular/modularCodeModel.js";
import { getClientName } from "@azure-tools/rlc-common";

export * from "./lib.js";

Expand Down Expand Up @@ -119,7 +120,10 @@ export async function $onEmit(context: EmitContext) {
const rlcModels = await transformRLCModel(client, dpgContext);
rlcCodeModels.push(rlcModels);
serviceNameToRlcModelsMap.set(client.service.name, rlcModels);
needUnexpectedHelper.set(client.name, hasUnexpectedHelper(rlcModels));
needUnexpectedHelper.set(
getClientName(rlcModels),
hasUnexpectedHelper(rlcModels)
);

await emitModels(rlcModels, program);
await emitContentByBuilder(program, buildClientDefinitions, rlcModels);
Expand Down Expand Up @@ -162,9 +166,7 @@ export async function $onEmit(context: EmitContext) {
buildModels(modularCodeModel, subClient);
buildModelsOptions(modularCodeModel, subClient);
const hasClientUnexpectedHelper =
needUnexpectedHelper.get(
subClient.rlcClientName.replace("Context", "Client")
) ?? false;
needUnexpectedHelper.get(subClient.rlcClientName) ?? false;
buildOperationFiles(
dpgContext,
modularCodeModel,
Expand Down
32 changes: 11 additions & 21 deletions packages/typespec-ts/src/modular/buildCodeModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import {
import {
getAuthentication,
getHeaderFieldName,
getHttpOperation,
getPathParamName,
getQueryParamName,
getServers,
Expand All @@ -53,7 +52,8 @@ import {
HttpServer,
isStatusCode,
HttpOperation,
isHeader
isHeader,
getHttpOperation
} from "@typespec/http";
import { getAddedOnVersions } from "@typespec/versioning";
import {
Expand All @@ -80,7 +80,10 @@ import {
Type as HrlcType,
Header
} from "./modularCodeModel.js";
import { getEnrichedDefaultApiVersion } from "../utils/modelUtils.js";
import {
getEnrichedDefaultApiVersion,
isAzureCoreErrorType
} from "../utils/modelUtils.js";
import { camelToSnakeCase, toCamelCase } from "../utils/casingUtils.js";
import {
RLCModel,
Expand All @@ -90,7 +93,8 @@ import {
} from "@azure-tools/rlc-common";
import {
getOperationGroupName,
getOperationName
getOperationName,
isIgnoredHeaderParam
} from "../utils/operationUtil.js";
import { SdkContext } from "../utils/interfaces.js";
import { Project } from "ts-morph";
Expand Down Expand Up @@ -554,23 +558,6 @@ function emitResponseHeaders(
return retval;
}

function isAzureCoreErrorType(t?: Type): boolean {
if (
t?.kind !== "Model" ||
!["Error", "ErrorResponse", "InnerError"].includes(t.name)
)
return false;
const namespaces = ".Azure.Core.Foundations".split(".");
while (
namespaces.length > 0 &&
(t?.kind === "Model" || t?.kind === "Namespace") &&
t.namespace?.name === namespaces.pop()
) {
t = t.namespace;
}
return namespaces.length == 0;
}

function emitResponse(
context: SdkContext,
response: HttpOperationResponse,
Expand Down Expand Up @@ -753,6 +740,9 @@ function emitBasicOperation(
});

for (const param of httpOperation.parameters.parameters) {
if (isIgnoredHeaderParam(param)) {
continue;
}
const emittedParam = emitParameter(context, param, "Method");
if (isApiVersion(context, param) && apiVersionParam === undefined) {
apiVersionParam = emittedParam;
Expand Down
13 changes: 8 additions & 5 deletions packages/typespec-ts/src/modular/emitModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export function buildModels(
// We are generating both models and enums here
const coreClientTypes = new Set<string>();
const models = codeModel.types.filter(
(t) => (t.type === "model" || t.type === "enum") && !isAzureCoreError(t)
(t) =>
(t.type === "model" || t.type === "enum") && !isAzureCoreErrorSdkType(t)
);

// Skip to generate models.ts if there is no any models
Expand Down Expand Up @@ -78,8 +79,8 @@ export function buildModels(
properties: properties.map((p) => {
const propertyMetadata = getType(p.type);
let propertyTypeName = propertyMetadata.name;
if (isAzureCoreError(p.type)) {
propertyTypeName = isAzureCoreError(p.type)
if (isAzureCoreErrorSdkType(p.type)) {
propertyTypeName = isAzureCoreErrorSdkType(p.type)
? getCoreClientErrorType(propertyTypeName)
: propertyTypeName;
}
Expand Down Expand Up @@ -122,10 +123,12 @@ export function buildModels(
return modelsFile;
}

function isAzureCoreError(t: Type) {
function isAzureCoreErrorSdkType(t: Type) {
return (
t.name &&
["Error", "InnerError"].includes(t.name) &&
["error", "errormodel", "innererror", "errorresponse"].includes(
t.name.toLowerCase()
) &&
t.isCoreErrorType === true
);
}
Expand Down
28 changes: 19 additions & 9 deletions packages/typespec-ts/src/modular/helpers/operationHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export function getDeserializePrivateFunction(
): OptionalKind<FunctionDeclarationStructure> {
const { name } = getOperationName(operation);

let parameters: OptionalKind<ParameterDeclarationStructure>[] = [
const parameters: OptionalKind<ParameterDeclarationStructure>[] = [
{
name: "result",
type: getRLCResponseType(operation.rlcResponse)
Expand All @@ -103,14 +103,6 @@ export function getDeserializePrivateFunction(
if (response?.type?.type) {
returnType = buildType(response.type.name, response.type);
} else {
if (!needUnexpectedHelper) {
parameters = [
{
name: "_result",
type: getRLCResponseType(operation.rlcResponse)
}
];
}
returnType = { name: "", type: "void" };
}

Expand All @@ -128,6 +120,24 @@ export function getDeserializePrivateFunction(
"throw result.body",
"}"
);
} else {
const validStatus = [
...new Set(
operation.responses
.flatMap((r) => r.statusCodes)
.filter((s) => s !== "default")
)
];

if (validStatus.length > 0) {
statements.push(
`if(${validStatus
.map((s) => `result.status !== "${s}"`)
.join(" || ")}){`,
"throw result.body",
"}"
);
}
}

if (response?.type?.type === "any") {
Expand Down
6 changes: 2 additions & 4 deletions packages/typespec-ts/src/transform/transformResponses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,10 @@ function transformBody(
const bodySchema = getSchemaForType(dpgContext, body!.type, [
SchemaContext.Output
]) as Schema;
if (bodySchema.fromCore) {
fromCore = true;
}
fromCore = bodySchema.fromCore ?? false;
const bodyType = getTypeName(bodySchema);
const importedNames = getImportedModelName(bodySchema);
if (importedNames) {
if (importedNames && !fromCore) {
importedNames
.filter((name) => {
return name !== "any";
Expand Down
10 changes: 3 additions & 7 deletions packages/typespec-ts/src/transform/transformSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
getSchemaForType,
includeDerivedModel,
getBodyType,
trimUsage
trimUsage,
isAzureCoreErrorType
} from "../utils/modelUtils.js";
import { SdkContext } from "../utils/interfaces.js";

Expand Down Expand Up @@ -61,12 +62,7 @@ export function transformSchemas(
getGeneratedModels(bodyModel, SchemaContext.Input);
}
for (const resp of route.responses) {
if (
resp.type.kind === "Model" &&
resp.type.name === "ErrorResponse" &&
resp.type.namespace?.name === "Foundations" &&
resp.type.namespace.namespace?.name === "Core"
) {
if (isAzureCoreErrorType(resp.type)) {
continue;
}
for (const resps of resp.responses) {
Expand Down
Loading

0 comments on commit 47adf85

Please sign in to comment.