mirror of
				https://github.com/Redocly/redoc.git
				synced 2025-11-04 01:37:32 +03:00 
			
		
		
		
	feat: support multiple examples for parameters (#1470)
This commit is contained in:
		
							parent
							
								
									340a568262
								
							
						
					
					
						commit
						d12e410d99
					
				| 
						 | 
					@ -9,6 +9,8 @@ import {
 | 
				
			||||||
  TypePrefix,
 | 
					  TypePrefix,
 | 
				
			||||||
  TypeTitle,
 | 
					  TypeTitle,
 | 
				
			||||||
  ToggleButton,
 | 
					  ToggleButton,
 | 
				
			||||||
 | 
					  FieldLabel,
 | 
				
			||||||
 | 
					  ExampleValue,
 | 
				
			||||||
} from '../../common-elements/fields';
 | 
					} from '../../common-elements/fields';
 | 
				
			||||||
import { serializeParameterValue } from '../../utils/openapi';
 | 
					import { serializeParameterValue } from '../../utils/openapi';
 | 
				
			||||||
import { ExternalDocumentation } from '../ExternalDocumentation/ExternalDocumentation';
 | 
					import { ExternalDocumentation } from '../ExternalDocumentation/ExternalDocumentation';
 | 
				
			||||||
| 
						 | 
					@ -23,6 +25,8 @@ import { Badge } from '../../common-elements/';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { l } from '../../services/Labels';
 | 
					import { l } from '../../services/Labels';
 | 
				
			||||||
import { OptionsContext } from '../OptionsProvider';
 | 
					import { OptionsContext } from '../OptionsProvider';
 | 
				
			||||||
 | 
					import { FieldModel } from '../../services/models/Field';
 | 
				
			||||||
 | 
					import styled from '../../styled-components';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const MAX_PATTERN_LENGTH = 45;
 | 
					const MAX_PATTERN_LENGTH = 45;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,20 +48,19 @@ export class FieldDetails extends React.PureComponent<FieldProps, { patternShown
 | 
				
			||||||
    const { patternShown } = this.state;
 | 
					    const { patternShown } = this.state;
 | 
				
			||||||
    const { enumSkipQuotes, hideSchemaTitles } = this.context;
 | 
					    const { enumSkipQuotes, hideSchemaTitles } = this.context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { schema, description, example, deprecated } = field;
 | 
					    const { schema, description, example, deprecated, examples } = field;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const rawDefault = !!enumSkipQuotes || field.in === 'header'; // having quotes around header field default values is confusing and inappropriate
 | 
					    const rawDefault = !!enumSkipQuotes || field.in === 'header'; // having quotes around header field default values is confusing and inappropriate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let exampleField: JSX.Element | null = null;
 | 
					    let renderedExamples: JSX.Element | null = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (showExamples && example !== undefined) {
 | 
					    if (showExamples && (example !== undefined || examples !== undefined)) {
 | 
				
			||||||
      const label = l('example') + ':';
 | 
					      if (examples !== undefined) {
 | 
				
			||||||
      if (field.in && (field.style || field.serializationMime)) {
 | 
					        renderedExamples = <Examples field={field} />;
 | 
				
			||||||
        // decode for better readability in examples: see https://github.com/Redocly/redoc/issues/1138
 | 
					 | 
				
			||||||
        const serializedValue = decodeURIComponent(serializeParameterValue(field, example));
 | 
					 | 
				
			||||||
        exampleField = <FieldDetail label={label} value={serializedValue} raw={true} />;
 | 
					 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        exampleField = <FieldDetail label={label} value={example} />;
 | 
					        const label = l('example') + ':';
 | 
				
			||||||
 | 
					        const raw = !!field.in;
 | 
				
			||||||
 | 
					        renderedExamples = <FieldDetail label={label} value={getSerializedValue(field, field.example)} raw={raw}  />;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,7 +103,7 @@ export class FieldDetails extends React.PureComponent<FieldProps, { patternShown
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
        <FieldDetail raw={rawDefault} label={l('default') + ':'} value={schema.default} />
 | 
					        <FieldDetail raw={rawDefault} label={l('default') + ':'} value={schema.default} />
 | 
				
			||||||
        {!renderDiscriminatorSwitch && <EnumValues type={schema.type} values={schema.enum} />}{' '}
 | 
					        {!renderDiscriminatorSwitch && <EnumValues type={schema.type} values={schema.enum} />}{' '}
 | 
				
			||||||
        {exampleField}
 | 
					        {renderedExamples}
 | 
				
			||||||
        {<Extensions extensions={{ ...field.extensions, ...schema.extensions }} />}
 | 
					        {<Extensions extensions={{ ...field.extensions, ...schema.extensions }} />}
 | 
				
			||||||
        <div>
 | 
					        <div>
 | 
				
			||||||
          <Markdown compact={true} source={description} />
 | 
					          <Markdown compact={true} source={description} />
 | 
				
			||||||
| 
						 | 
					@ -113,3 +116,40 @@ export class FieldDetails extends React.PureComponent<FieldProps, { patternShown
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function Examples({ field }: { field: FieldModel }) {
 | 
				
			||||||
 | 
					  if (!field.examples) {
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
 | 
					      <FieldLabel> {l('examples')}: </FieldLabel>
 | 
				
			||||||
 | 
					      <ExamplesList>
 | 
				
			||||||
 | 
					        {Object.values(field.examples).map((example, idx) => {
 | 
				
			||||||
 | 
					          return (
 | 
				
			||||||
 | 
					            <li key={idx}>
 | 
				
			||||||
 | 
					              <ExampleValue>{getSerializedValue(field, example.value)}</ExampleValue> - {example.summary || example.description}
 | 
				
			||||||
 | 
					            </li>
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					        })}
 | 
				
			||||||
 | 
					      </ExamplesList>
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getSerializedValue(field: FieldModel, example: any) {
 | 
				
			||||||
 | 
					  if (field.in) {
 | 
				
			||||||
 | 
					    // decode for better readability in examples: see https://github.com/Redocly/redoc/issues/1138
 | 
				
			||||||
 | 
					    return decodeURIComponent(serializeParameterValue(field, example));
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return example;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ExamplesList = styled.ul`
 | 
				
			||||||
 | 
					  margin-top: 1em;
 | 
				
			||||||
 | 
					  padding-left: 0;
 | 
				
			||||||
 | 
					  list-style-position: inside;
 | 
				
			||||||
 | 
					`;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ export interface LabelsConfig {
 | 
				
			||||||
  default: string;
 | 
					  default: string;
 | 
				
			||||||
  deprecated: string;
 | 
					  deprecated: string;
 | 
				
			||||||
  example: string;
 | 
					  example: string;
 | 
				
			||||||
 | 
					  examples: string;
 | 
				
			||||||
  nullable: string;
 | 
					  nullable: string;
 | 
				
			||||||
  recursive: string;
 | 
					  recursive: string;
 | 
				
			||||||
  arrayOf: string;
 | 
					  arrayOf: string;
 | 
				
			||||||
| 
						 | 
					@ -20,6 +21,7 @@ const labels: LabelsConfig = {
 | 
				
			||||||
  default: 'Default',
 | 
					  default: 'Default',
 | 
				
			||||||
  deprecated: 'Deprecated',
 | 
					  deprecated: 'Deprecated',
 | 
				
			||||||
  example: 'Example',
 | 
					  example: 'Example',
 | 
				
			||||||
 | 
					  examples: 'Examples',
 | 
				
			||||||
  nullable: 'Nullable',
 | 
					  nullable: 'Nullable',
 | 
				
			||||||
  recursive: 'Recursive',
 | 
					  recursive: 'Recursive',
 | 
				
			||||||
  arrayOf: 'Array of ',
 | 
					  arrayOf: 'Array of ',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,8 @@ import { RedocNormalizedOptions } from '../RedocNormalizedOptions';
 | 
				
			||||||
import { extractExtensions } from '../../utils/openapi';
 | 
					import { extractExtensions } from '../../utils/openapi';
 | 
				
			||||||
import { OpenAPIParser } from '../OpenAPIParser';
 | 
					import { OpenAPIParser } from '../OpenAPIParser';
 | 
				
			||||||
import { SchemaModel } from './Schema';
 | 
					import { SchemaModel } from './Schema';
 | 
				
			||||||
 | 
					import { ExampleModel } from './Example';
 | 
				
			||||||
 | 
					import { mapValues } from '../../utils/helpers';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DEFAULT_SERIALIZATION: Record<
 | 
					const DEFAULT_SERIALIZATION: Record<
 | 
				
			||||||
  OpenAPIParameterLocation,
 | 
					  OpenAPIParameterLocation,
 | 
				
			||||||
| 
						 | 
					@ -46,6 +48,7 @@ export class FieldModel {
 | 
				
			||||||
  required: boolean;
 | 
					  required: boolean;
 | 
				
			||||||
  description: string;
 | 
					  description: string;
 | 
				
			||||||
  example?: string;
 | 
					  example?: string;
 | 
				
			||||||
 | 
					  examples?: Record<string, ExampleModel>;
 | 
				
			||||||
  deprecated: boolean;
 | 
					  deprecated: boolean;
 | 
				
			||||||
  in?: OpenAPIParameterLocation;
 | 
					  in?: OpenAPIParameterLocation;
 | 
				
			||||||
  kind: string;
 | 
					  kind: string;
 | 
				
			||||||
| 
						 | 
					@ -81,6 +84,13 @@ export class FieldModel {
 | 
				
			||||||
      info.description === undefined ? this.schema.description || '' : info.description;
 | 
					      info.description === undefined ? this.schema.description || '' : info.description;
 | 
				
			||||||
    this.example = info.example || this.schema.example;
 | 
					    this.example = info.example || this.schema.example;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (info.examples !== undefined) {
 | 
				
			||||||
 | 
					      this.examples = mapValues(
 | 
				
			||||||
 | 
					        info.examples,
 | 
				
			||||||
 | 
					        example => new ExampleModel(parser, example, name, info.encoding),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (serializationMime) {
 | 
					    if (serializationMime) {
 | 
				
			||||||
      this.serializationMime = serializationMime;
 | 
					      this.serializationMime = serializationMime;
 | 
				
			||||||
    } else if (info.style) {
 | 
					    } else if (info.style) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/types/open-api.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								src/types/open-api.d.ts
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -95,6 +95,7 @@ export interface OpenAPIParameter {
 | 
				
			||||||
  example?: any;
 | 
					  example?: any;
 | 
				
			||||||
  examples?: { [media: string]: Referenced<OpenAPIExample> };
 | 
					  examples?: { [media: string]: Referenced<OpenAPIExample> };
 | 
				
			||||||
  content?: { [media: string]: OpenAPIMediaType };
 | 
					  content?: { [media: string]: OpenAPIMediaType };
 | 
				
			||||||
 | 
					  encoding?: Record<string, OpenAPIEncoding>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface OpenAPIExample {
 | 
					export interface OpenAPIExample {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user