processResponses()

in packages/extensions/modelerfour/src/modeler/modelerfour.ts [2160:2320]


  processResponses(httpOperation: OpenAPI.HttpOperation, operation: Operation) {
    const acceptTypes = new Set<string>();

    const modelerResponses = httpOperation.responses;

    // If the operation has final-state-schema lro option, add a "200" response if there isn't one already
    if (httpOperation["x-ms-long-running-operation-options"]?.["final-state-schema"]) {
      const finalStateSchema = httpOperation["x-ms-long-running-operation-options"]?.["final-state-schema"] as string;
      if (!Object.keys(modelerResponses).some((k) => k === "200")) {
        modelerResponses["200"] = {
          description: "Success",
          content: {
            "application/json": {
              schema: {
                $ref: finalStateSchema,
              },
            },
          },
        };
      }
    }

    // === Response ===
    for (const { key: responseCode, value: response } of this.resolveDictionary(modelerResponses)) {
      const isErr = responseCode === "default" || response["x-ms-error-response"];

      const knownMediaTypes = this.filterMediaTypes(response.content);

      if (knownMediaTypes.size === 0) {
        // it has no actual response *payload*
        // so we just want to create a simple response .
        const rsp = new Response({
          extensions: this.interpret.getExtensionProperties(response),
        });
        rsp.language.default.description = response.description;

        const headers = this.processResponseHeaders(response.headers);
        rsp.protocol.http = SetType(HttpResponse, {
          statusCodes: [responseCode],
          headers: headers.length ? headers : undefined,
        });
        if (isErr) {
          operation.addException(rsp);
        } else {
          operation.addResponse(rsp);
        }
      } else {
        for (const [knownMediaType, mediatypes] of knownMediaTypes.entries()) {
          const allMt = mediatypes.map((each: any) => each.mediaType);
          for (const mediaType of allMt) {
            acceptTypes.add(mediaType);
          }

          const headers = this.processResponseHeaders(response.headers);
          if (knownMediaType === KnownMediaType.Binary) {
            // binary response needs different response type.
            const rsp = new BinaryResponse({
              extensions: this.interpret.getExtensionProperties(response),
            });
            rsp.language.default.description = response.description;
            rsp.protocol.http = SetType(HttpBinaryResponse, {
              statusCodes: [responseCode],
              knownMediaType: knownMediaType,
              mediaTypes: allMt,
              headers: headers.length ? headers : undefined,
            });
            if (isErr) {
              //op.addException(rsp);
              // errors should not be binary streams!
              throw new Error(`The response body should not be a binary! ${httpOperation.operationId}/${responseCode}`);
            } else {
              operation.addResponse(rsp);
            }
            continue;
          }

          const schema = mediatypes[0].schema.instance;

          if (schema) {
            let s = this.processSchema(mediatypes[0].schema.name || "response", schema);

            // response schemas should not be constant types.
            // this replaces the constant value with the value type itself.

            if (s.type === SchemaType.Constant) {
              s = (<ConstantSchema>s).valueType;
            }

            if (isErr) {
              // Track the usage of this schema as an exception with media type
              this.trackSchemaUsage(s, {
                usage: [SchemaContext.Exception],
                serializationFormats: [knownMediaType as KnownMediaType],
              });
            } else {
              // Track the usage of this schema as an output with media type
              this.trackSchemaUsage(s, {
                usage: [SchemaContext.Output],
                serializationFormats: [knownMediaType as KnownMediaType],
              });
            }

            const rsp = new SchemaResponse(s, {
              extensions: this.interpret.getExtensionProperties(response),
              nullable: schema.nullable,
            });
            rsp.language.default.description = response.description;

            rsp.protocol.http = SetType(HttpResponse, {
              statusCodes: [responseCode],
              knownMediaType: knownMediaType,
              mediaTypes: allMt,
              headers: headers.length ? headers : undefined,
            });

            if (isErr) {
              operation.addException(rsp);
            } else {
              operation.addResponse(rsp);
            }
          }
        }
      }
    }

    function isAcceptHeaderParam(p: Parameter): boolean {
      return p.protocol.http?.in === ParameterLocation.Header && p.language.default.serializedName === "Accept";
    }

    // Synthesize an 'Accept' header based on the media types in this
    // operation and add it to all requests.  Before adding the header,
    // make sure there isn't an existing Accept parameter.
    const mediaTypes = Array.from(acceptTypes);
    if (this.options["always-create-accept-parameter"] === true && acceptTypes.size > 0) {
      const acceptSchema = this.getAcceptParameterSchema(mediaTypes);
      if (!operation.parameters?.find(isAcceptHeaderParam)) {
        for (const request of operation.requests ?? []) {
          if (request.parameters?.find(isAcceptHeaderParam)) {
            // Already has an accept parameter, move on to the next.
            continue;
          }

          request.addParameter(
            new Parameter("accept", "Accept header", acceptSchema, {
              implementation: ImplementationLocation.Method,
              required: true,
              origin: "modelerfour:synthesized/accept",
              protocol: {
                http: new HttpParameter(ParameterLocation.Header),
              },
              language: {
                default: {
                  serializedName: "Accept",
                },
              },
            }),
          );
        }
      }
    }
  }