stoplightio / http-spec

Utilities to normalize OpenAPI v2 and v3 objects for the Stoplight ecosystem.

Home Page:https://stoplight.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Responses with the same status code

karol-maciaszek opened this issue · comments

This was discovered while testing Prism powered by Postman Collection document.

IHttpOperation type allows defining several IHttpOperationResponse’s having the same status code. But due to how Prism's negotiator works we will always consider only first response with matching code (https://github.com/stoplightio/prism/blob/master/packages/http/src/mocker/negotiator/InternalHelpers.ts#L75).

For example, if we have two separate response objects with status code 200 and different mediaTypes (1. JSON, 2. XML) && we have received accept header preferring XML, then we fail to find it.

It was not possible to define several responses with the same status code in OpenAPI2/3 due to code being a property. So we never run into such a problem using OpenAPI. But with Postman Collection it is possible to define several responses within a single operation having the same codes and the rest being different. This effectively causes Prism to fail to find a proper response.

The questions:

  1. Should Prism handle such cases as multiple response objects having the same status code?
  2. How about the rest of our tooling, are we ready for such cases?
  3. If we don't want to support ^, then maybe multiple responses from Postman Collection should be merged into one?
    3a. ...ignored?
  4. If we allow responses having the some code it may possible cause problem if we want to convert IHttpOperation back into OpenAPI document- do we (will )?have such case?

@XVincentX @philsturgeon @lottamus @marbemac

Good find! My thoughts:

Should Prism handle such cases as multiple response objects having the same status code?

I do not think IHttpOperation should support multiple response objects with the same code. IMHO we should be turning postman collection -> IHttpRequest[] -> IHttpOperation[]. I understand that right now we are going direct from postman -> IHttpOperation[], which is fine. I'll outline my thoughts on what a complete process might look like - I'm not sure how feasible any of it is given the current implementation, but it's at least some ideas.

  1. transform postman collection into IHttpRequest[] objects
  2. transform IHttpRequest[] objects into IHttpOperation[] objects. should generate schemas from example request/response bodies, etc - likely what we're doing right now in postman -> IHttpOperation transformation, not much different.
  3. given a list of IHttpOperation[] objects, identify all duplicate IHttpOperation objects (by duplicate I mean matching request signature e.g. method + path.
  4. merge duplicate IHttpOperation objects together. during this process, we attempt to intelligently merge schemas, headers, responses etc, resulting in a single more complete IHttpOperation object for that method + path signature.

Step 4 is where most of the complexity is beyond what I understand has already been done re postman transformer. To your original question - if two operations define the same 200 response code, each with one example, we'd merge their schemas together to get a more representative final schema (something like https://github.com/goodeggs/merge-json-schemas or a homegrown merge func inspired by libraries like that), and also end up with two examples in the final operation (since merging example objects does not make sense, instead we'd concatenate to end up with two separate example response objects for the 200 response code). Similar logic goes for parameters, headers, etc.

Ultimately the hope is that we can use this same transformation pipeline to drive "learning" - e.g. taking logged requests and generating openapi documents (this is separate from the immediate benefit we're after regarding mocking postman collections with prism). The final pipeline for learning might look like Logged IHttpRequest objects (from prism, or elsewhere) -[transform]-> IHttpOperation[] -[transform]-> OpenAPI Document.

More of an answer that you were probably looking for, but hopefully provides some context on the greater ambitions with the work you've been doing! Eager to hear what you think.

Paging @handrews for another pair of eyes on the proposal from @marbemac here. 1-3 sound excellent to me but I saw "merge" and wanna get your eyes on it.

@marbemac for context the word "merge" has a looooot of history in JSON Schema, which I wont get into.

@marbemac What can we do at the moment? I guess we can either take the long path, which is to modify HttpSpec to start outputting HttpRequest objects and then derive the operations from there — or maybe we could short-circuit this at the moment and to the merging (once we figure out a strategy) directly in the transformer?

for context the word "merge" has a looooot of history in JSON Schema

Yup definitely not talking about $merge keyword or anything - perhaps best effort combine is a better phrase? :)

What can we do at the moment? I guess we can either take the long path, which is to modify HttpSpec to start outputting HttpRequest objects and then derive the operations from there

Don't think we need to modify to go from postman to IHttpRequest right now. Instead could start with functions to combine a list of HttpOperation objects, since that's relevant now and in future world where it's postman -> IHttpRequest -> IHttpOperation (end is still an array of IHttpOperations that we need to "combine" where possible). Should prob start with an exploration and write up of how operation combining might work, and how we'll handle the various cases?

🎉 This issue has been resolved in version 2.8.0 🎉

The release is available on:

Your semantic-release bot 📦🚀