in packages/autorest.go/src/transform/transform.ts [799:924]
function createResponseEnvelope(codeModel: m4.CodeModel, group: m4.OperationGroup, op: m4.Operation) {
// create the `type <type>Response struct` response
// aggregate headers from all responses as all of them will go into the same result envelope
const headers = new Map<string, HttpHeaderWithDescription>();
// skip adding headers for LROs for now, this is to avoid adding
// any LRO-specific polling headers.
// TODO: maybe switch to skip specific polling ones in the future?
if (!helpers.isLROOperation(op)) {
for (const resp of values(op.responses)) {
// check if the response is expecting information from headers
for (const header of values(resp.protocol.http!.headers)) {
const head = <m4.HttpHeader>header;
// convert each header to a property and append it to the response properties list
const name = head.language.go!.name;
if (!headers.has(name)) {
const description = `${name} contains the information returned from the ${head.header} header response.`;
headers.set(name, <HttpHeaderWithDescription>{
...head,
description: description
});
}
}
}
}
// contains all the response envelopes
const responseEnvelopes = <Array<m4.ObjectSchema>>codeModel.language.go!.responseEnvelopes;
// first create the response envelope, each operation gets one
// if single-client is enabled, omit the <OperationGroup> prefix
let clientPrefix = capitalize(group.language.go!.clientName);
if (codeModel.language.go!.singleClient) {
clientPrefix = '';
}
const respEnvName = ensureUniqueModelName(codeModel, `${clientPrefix}${op.language.go!.name}Response`, 'Envelope');
const opName = helpers.isLROOperation(op) ? 'Begin' + op.language.go!.name : op.language.go!.name;
const respEnv = newObject(respEnvName, createResponseEnvelopeDescription(respEnvName, `${group.language.go!.clientName}.${helpers.isPageableOperation(op) && !helpers.isLROOperation(op) ? `New${opName}Pager` : opName}`));
respEnv.language.go!.responseType = true;
respEnv.properties = new Array<m4.Property>();
responseEnvelopes.push(respEnv);
op.language.go!.responseEnv = respEnv;
if (helpers.isLROOperation(op)) {
respEnv.language.go!.forLRO = true;
}
// add any headers to the response
for (const item of items(headers)) {
const prop = newRespProperty(item.key, item.value.description, item.value.schema, false);
// propagate any extensions so we can access them through the property
prop.extensions = item.value.extensions;
prop.language.go!.fromHeader = item.value.header;
respEnv.properties.push(prop);
}
// now create the result field
if (codeModel.language.go!.headAsBoolean && op.requests![0].protocol.http!.method === 'head') {
op.language.go!.headAsBoolean = true;
const successProp = newProperty('Success', 'Success indicates if the operation succeeded or failed.', newBoolean('bool', 'bool response'));
successProp.language.go!.byValue = true;
respEnv.properties.push(successProp);
respEnv.language.go!.resultProp = successProp;
return;
}
if (helpers.isMultiRespOperation(op)) {
const resultTypes = new Array<string>();
for (const response of values(op.responses)) {
// the operation might contain a mix of schemas and non-schema responses.
// we only care about the ones that return a schema.
if (helpers.isSchemaResponse(response)) {
resultTypes.push(response.schema.language.go!.name);
}
}
const resultProp = newRespProperty('Value', `Possible types are ${resultTypes.join(', ')}\n`, newAny('multi-response value'), true);
respEnv.properties.push(resultProp);
respEnv.language.go!.resultProp = resultProp;
return;
}
const response = helpers.getSchemaResponse(op);
// if the response defines a schema then add it to the response envelope
if (response) {
const rawJSONAsBytes = <boolean>codeModel.language.go!.rawJSONAsBytes;
// propagate marshalling format to the response envelope
respEnv.language.go!.marshallingFormat = response.schema.language.go!.marshallingFormat;
// for operations that return scalar types we use a fixed field name
let propName = scalarResponsePropName;
if (response.schema.type === m4.SchemaType.Object) {
// for object types use the type's name as the field name
propName = response.schema.language.go!.name;
} else if (response.schema.type === m4.SchemaType.Array) {
// for array types use the element type's name
propName = recursiveTypeName(response.schema);
} else if (rawJSONAsBytes && (response.schema.type === m4.SchemaType.Any || response.schema.type === m4.SchemaType.AnyObject)) {
propName = 'RawJSON';
} else if (response.schema.type === m4.SchemaType.Any) {
propName = 'Interface';
} else if (response.schema.type === m4.SchemaType.AnyObject) {
propName = 'Object';
}
if (response.schema.serialization?.xml && response.schema.serialization.xml.name) {
// always prefer the XML name
propName = capitalize(response.schema.serialization.xml.name);
}
// we want to pass integral types byref to maintain parity with struct fields
const byValue = helpers.isTypePassedByValue(response.schema) || response.schema.type === m4.SchemaType.Object;
const resultSchema = substitueDiscriminator(response);
const resultProp = newRespProperty(propName, response.schema.language.go!.description, resultSchema, byValue);
if (resultSchema.language.go!.discriminatorInterface) {
// if the schema is a discriminator we need to flag this on the property itself.
// this is so the correct unmarshaller is created for the response envelope.
resultProp.isDiscriminator = true;
}
respEnv.properties.push(resultProp);
respEnv.language.go!.resultProp = resultProp;
} else if (helpers.isBinaryResponseOperation(op)) {
const binaryProp = newProperty('Body', 'Body contains the streaming response.', newBinary('binary response'));
binaryProp.language.go!.byValue = true;
respEnv.properties.push(binaryProp);
respEnv.language.go!.resultProp = binaryProp;
}
if (respEnv.properties.length === 0) {
// if we get here it means the operation doesn't return anything. we set
// this to undefined to simplify detection of an empty response envelope
respEnv.properties = undefined;
}
}