Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example.externalValue is not displayed #5433

Open
shockey opened this issue Jun 29, 2019 · 31 comments
Open

Example.externalValue is not displayed #5433

shockey opened this issue Jun 29, 2019 · 31 comments

Comments

@shockey
Copy link
Contributor

shockey commented Jun 29, 2019

Example Swagger/OpenAPI definition

openapi: 3.0.0

paths:
  /:
    post:
      requestBody:
        content:
          image/png:
            schema:
              type: string
              format: binary
            examples:
              KittenImage:
                externalValue: "https://placekitten.com/200/300"
      responses:
        "200":
          description: OK!

Current behavior

image

Expected behavior

I should be able to use the externally-referenced image as an example value for my endpoint (provided that Swagger UI is able to reach the resource).

Additional context or thoughts

#5427.

@offboarded-x233534
Copy link

offboarded-x233534 commented Jul 16, 2019

I don't know if this is the appropriate issue, but instead of binary image, I simply want external JSON to display. Is this already planned?

openapi: 3.0.2
info:
  description: 'myapp'
  version: '2.0.0'
  title: 'myapp 2.0 Rest API'
servers:
  - url: http://localhost:8080/rest
    description: Local Environment
  - url: https://app-dev.myapp.foo/rest
    description: Development Environment
paths:
  /rest/companies:
    get:
      summary: 'Get all companies'
      description: 'foo'
      produces:
        - 'application/json'
      responses:
        '200':
          description: 'successful operation'
          content:
            application/json:
              schema:
                type: 'array'
                items:
                  $ref: '#/components/schemas/Company'
              examples:
                jsonObject:
                  summary: This is an example in Company
                  externalValue: 'https://static.myapp.foo/examples/rest_companies_example.json
components:
  schemas:
    Company:
      type: 'object'
      properties:
        id:
          type: 'integer'
          format: 'int64'
        name:
          type: 'string'

I build my self a quick hack, that works for me for now

47b992f...clouless:feature/examplesExternalValue

@membersound
Copy link

Same for me, would like to embed external json, but it's simply empty...

@matrunchyk
Copy link

@shockey Thank you for opening this issue! Do you know an approx. ETA for this?

@simundev
Copy link

I have the same problem. I prefer to keep my examples in external .json files (same with models) so as not to clutter the spec itself too much. Any idea where this is in the priority stack please?

@yoanncouillec
Copy link

Same here. externalValue does not display the pointed json

@verilog15
Copy link

verilog15 commented May 27, 2020

Same here. externalValue does not work for me. It displays an empty field. Was there a 3.0.x OpenAPI version which it worked? Or is there some other way to do it without setting it manually?

@teffi
Copy link

teffi commented Jun 11, 2020

Echoing this issue. Would be helpful to finally have externalValue work with example.

@lyzkov
Copy link

lyzkov commented Jun 14, 2020

The documentation says that there is possible to use externalValue. Please update the documentation or fix a bug.

@verilog15
Copy link

Has someone found a way to bypass this issue and somehow use externalValue?

@ipichris
Copy link

ipichris commented Oct 5, 2020

Anything that can be done to get this on the roadmap?

@vaimodi
Copy link

vaimodi commented Nov 6, 2020

Any workaround for this issue? Please share the details when we should expect the fix.

@ambition-consulting
Copy link

Can we get this fixed please? You have done a great job on introducing multiple example values for the multiple ways that an API endpoint can be called - now please let us also use them in your UI!

@lyzkov
Copy link

lyzkov commented Mar 12, 2021

Can we get this fixed please? You have done a great job on introducing multiple example values for the multiple ways that an API endpoint can be called - now please let us also use them in your UI!

Hallo, swagger team @fehguy could you prioritise this task? External examples are crucial, I mean SUPER IMPORTANT, for spreading Single Source of Truth principle on mocking objects reusable across testing frameworks, and especially, for staging environments across platforms.

@mathis-m
Copy link
Contributor

mathis-m commented Mar 12, 2021

@tim-lai I think this is only partially a swagger-ui issue!
I have tried to integrate externalValue examples (from params, requestBody, response) into the sample generation process.
I realized that this value is not resolved, I think swagger-js should resolve this just like it resolves refs.

Else ways I will implement some resolver that will fetch the raw value hosted behind the externalValue url.

@veblogic
Copy link

veblogic commented Jul 15, 2021

@mathis-m , I am facing the same issue. Is this issue resolved?
Appreciate your efforts and time invested.

@arman-sydikov
Copy link

arman-sydikov commented Aug 19, 2021

Workaround with wrapComponents

Sample openapi.yaml

openapi: 3.0.1
info:
  title: Swagger Petstore
  description: 'This is a sample server Petstore server'
  version: 1.0.0
servers:
- url: https://petstore.swagger.io/v2
- url: http://petstore.swagger.io/v2
paths:
  /router/rest:
    get:
      summary: test
      operationId: test
      responses:
        '200':
          content:
            application/json:
              schema:
                type: object
              examples:
                success:
                  summary: JSON example
                  value: Loading...
                  externalValue: 'example/test.json'
            application/xml:
              schema:
                type: object
                xml:
                  name: xml
              examples:
                success:
                  summary: XML example
                  value: Loading...
                  externalValue: 'example/test.xml'

Add custom plugin to index.html

// Examples map
const examples = {};

// Custom plugin for logic that happens before the response element is created
const CustomPlugin = () => {
  return {
    wrapComponents: {
      response: (Original, { React, oas3Actions, oas3Selectors }) => (props) => {
        const contentType = oas3Selectors.responseContentType(props.path, props.method)
        const externalValue = props.response.getIn(['content', contentType, 'examples', props.activeExamplesKey, 'externalValue'])
        // Check if externalValue field exists
        if (externalValue) {
          // Check if examples map already contains externalValue key
          if (examples[externalValue]) {
            // Set example value directly from examples map
            props.response = props.response.setIn(['content', contentType, 'examples', props.activeExamplesKey, 'value'], examples[externalValue])
          } else {
            // Download external file
            fetch(externalValue)
            .then(res => res.text())
            .then(data => {
              // Put downloaded file content into the examples map
              examples[externalValue] = data
              // Simulate select another example action
              oas3Actions.setActiveExamplesMember({
                "name": 'fake',
                "pathMethod": [props.path, props.method],
                "contextType": "responses",
                "contextName": props.code
              })
              // Reselect this example
              oas3Actions.setActiveExamplesMember({
                "name": props.activeExamplesKey,
                "pathMethod": [props.path, props.method],
                "contextType": "responses",
                "contextName": props.code
              })
            })
            .catch(e => console.error(e))
          }
        }
        return React.createElement(Original, props)
      }
    }
  }
}

window.onload = function() {
  const ui = SwaggerUIBundle({
    url: 'openapi.yaml',
    dom_id: '#swagger-ui',
    deepLinking: true,
    presets: [
      SwaggerUIBundle.presets.apis,
      SwaggerUIStandalonePreset
    ],
    plugins: [
      SwaggerUIBundle.plugins.DownloadUrl,
      // Add custom plugin
      CustomPlugin
    ],
    layout: "StandaloneLayout"
  });

  window.ui = ui;
};

@sjaakd
Copy link

sjaakd commented Nov 24, 2021

I guess this issue also applies to having xml documents as example#externalValue. I'm dealing with the annotation version of openapi (org.eclipse.microprofile.openapi.annotations) and having problems with large String constants as example#value. Falling back on example#externalValue does not work.

@ShambuGIT
Copy link

ShambuGIT commented Jan 10, 2022

I am facing the same issue. The workaround helps to make it work. But can anyone provide me the permanent fix on this.

@sima0815
Copy link

Thanks for this fix! Do you have any suggestions on how to get this working for the request body as well. I want to have an example with an external JSON File within the Request Body.

Workaround with wrapComponents

Sample openapi.yaml

openapi: 3.0.1
info:
  title: Swagger Petstore
  description: 'This is a sample server Petstore server'
  version: 1.0.0
servers:
- url: https://petstore.swagger.io/v2
- url: http://petstore.swagger.io/v2
paths:
  /router/rest:
    get:
      summary: test
      operationId: test
      responses:
        '200':
          content:
            application/json:
              schema:
                type: object
              examples:
                success:
                  summary: JSON example
                  value: Loading...
                  externalValue: 'example/test.json'
            application/xml:
              schema:
                type: object
                xml:
                  name: xml
              examples:
                success:
                  summary: XML example
                  value: Loading...
                  externalValue: 'example/test.xml'

Add custom plugin to index.html

// Examples map
const examples = {};

// Custom plugin for logic that happens before the response element is created
const CustomPlugin = () => {
  return {
    wrapComponents: {
      response: (Original, { React, oas3Actions, oas3Selectors }) => (props) => {
        const contentType = oas3Selectors.responseContentType(props.path, props.method)
        const externalValue = props.response.getIn(['content', contentType, 'examples', props.activeExamplesKey, 'externalValue'])
        // Check if externalValue field exists
        if (externalValue) {
          // Check if examples map already contains externalValue key
          if (examples[externalValue]) {
            // Set example value directly from examples map
            props.response = props.response.setIn(['content', contentType, 'examples', props.activeExamplesKey, 'value'], examples[externalValue])
          } else {
            // Download external file
            fetch(externalValue)
            .then(res => res.text())
            .then(data => {
              // Put downloaded file content into the examples map
              examples[externalValue] = data
              // Simulate select another example action
              oas3Actions.setActiveExamplesMember({
                "name": 'fake',
                "pathMethod": [props.path, props.method],
                "contextType": "responses",
                "contextName": props.code
              })
              // Reselect this example
              oas3Actions.setActiveExamplesMember({
                "name": props.activeExamplesKey,
                "pathMethod": [props.path, props.method],
                "contextType": "responses",
                "contextName": props.code
              })
            })
            .catch(e => console.error(e))
          }
        }
        return React.createElement(Original, props)
      }
    }
  }
}

window.onload = function() {
  const ui = SwaggerUIBundle({
    url: 'openapi.yaml',
    dom_id: '#swagger-ui',
    deepLinking: true,
    presets: [
      SwaggerUIBundle.presets.apis,
      SwaggerUIStandalonePreset
    ],
    plugins: [
      SwaggerUIBundle.plugins.DownloadUrl,
      // Add custom plugin
      CustomPlugin
    ],
    layout: "StandaloneLayout"
  });

  window.ui = ui;
};

@CxVercility
Copy link

Push.
How has this not been fixed in 2 and a half years?!

@mathis-m
Copy link
Contributor

Push.
How has this not been fixed in 2 and a half years?!

If you have time have a look at swagger-api/swagger-js#1978 and finish it up. Currently I have no time to work on it.

@Aravinda93
Copy link

Hello Team,

I am working on Open-API and facing the same issue. Can you please provide me with some workaround?
I have posted my question here: https://stackoverflow.com/q/71779533/7584240

@mathis-m @arman-sydikov If you get a chance please provide some work-around. Thanks a lot in advance.

@natemow
Copy link

natemow commented Jul 14, 2022

In case it helps somebody else...I'm using swagger-ui-dist and replacing stuff in the package using good ol' Bash. I switched from swagger.json to swagger.yaml for doc output so multiline strings could be stored in example.MyKey.value. Here's a Bash workaround for populating example.MyKey.value in the generated swagger.yaml...it's just replacing value: path with that file's contents:

# Read in example and insert 8 spaces at the beginning of each line (for proper YAML formatting).
EXAMPLE='/path/to/examples/example.xml';
VALUE=$(cat "$EXAMPLE");
VALUE=$(echo "$VALUE" | sed 's/^/        /');

# Use awk var substitution to insert multiline value.
awk -v search="value: $EXAMPLE" -v replace="value: |-\n$VALUE" "{gsub(search,replace)}1" ./swagger.yaml > ./temp.yaml \
  && mv ./temp.yaml swagger.yaml;

@CxVercility
Copy link

CxVercility commented Aug 26, 2022

Push.
How has this not been fixed in 2 and a half years?!

If you have time have a look at swagger-api/swagger-js#1978 and finish it up. Currently I have no time to work on it.

I dont have any experience with JS and that's not the point i was trying to convey to be honest.
Im not asking you to make it work in your free time, but the least that should be done is a deprecation of that option with a fat warning or a flat out removal so people dont waste their time trying to get this to work, if you don't intend to do anything about it any time soon

@mathis-m
Copy link
Contributor

mathis-m commented Sep 2, 2022

@tim-lai @char0n This is a really low hanging fruit. Can you please give this some priority on "your internal backlog"

In addition, this is not a swagger-ui issue. It arises because of wrong resolution / normalization in the swagger-js package.

@mathis-m
Copy link
Contributor

mathis-m commented Sep 2, 2022

It is literally all there, in my initial pr at swagger-api/swagger-js#2013

It is just missing the base64 part and some tests.

@ben12
Copy link

ben12 commented Jul 24, 2023

Any news ?

@char0n
Copy link
Member

char0n commented Jul 27, 2023

Hi @ben12,

This is actually already supported in SwaggerUI@5 and OpenAPI 3.1.0 definitions.

openapi: 3.1.0
info:
  title: Swagger Petstore
  description: 'This is a sample server Petstore server'
  version: 1.0.0
servers:
  - url: https://petstore.swagger.io/v2
  - url: http://petstore.swagger.io/v2
paths:
  /router/rest:
    get:
      summary: test
      operationId: test
      responses:
        '200':
          description: response
          content:
            application/json:
              schema:
                type: object
              examples:
                success:
                  summary: JSON example
                  externalValue: https://gist.githubusercontent.com/char0n/5c35aee4fd95a23b18f6ed76d51ce83f/raw/0014ab1e8882ffbe285465ded4c18b4b745aecc4/test.yaml

URIs with .yaml, .yml, and .json extensions are currently natively supported. In all other cases the content of the externalValue is fetched, base64 encoded and assign to value field. Now I'm only explaining how it works so far, if anybody have any suggestions how to make it better, we're more then open to it.


Related to OpenAPI 3.0.x support, work for this has been done already by @mathis-m in swagger-api/swagger-js#2013, but in long term we want OpenAPI 3.0.x resolution to be facilitated by ApiDOM (same as for OpenAPI 3.1.0) and not by old legacy specmap mechanism.

@ben12
Copy link

ben12 commented Jul 27, 2023

Thanks, it work. My mistake was the OpenApi version (3.0.3 instead of 3.1.0).

So this issue may be closed ?

@char0n
Copy link
Member

char0n commented Jul 28, 2023

Thanks, it work. My mistake was the OpenApi version (3.0.3 instead of 3.1.0).

I'm just glad that you can use this feature for your OpenAPI 3.1.0 definitions now.

So this issue may be closed ?

Not really, as we're still missing this feature for OpenAPI 3.0.x. We'll introduce ApiDOM facilitated resolution for OpenAPI 3.0.x as an opt-in behavior in SwaggerClient and SwaggerUI subsequently. If/When we have this, we can close this issue.

@markliuliu
Copy link

markliuliu commented Dec 13, 2023

Hi @char0n, Thanks for your comment, By your comment we are able to use OpenAPI 31 to show the external Value. But we still have some questions.
Is any reason Swagger UI have to use Base64 to encode the format not list above like csv?
Is there any way let Swagger UI don't encode our value or help us to decode in value block?

env:
OpenAPI 3.1.0
Swagger UI 5.0.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests