Browse Source

feat(RequestBody): set default true for 'send empty value' (#6228)

bubble
Tim Lai 4 years ago
committed by GitHub
parent
commit
b68942c043
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 610 additions and 15 deletions
  1. +45
    -14
      src/core/components/parameter-include-empty.jsx
  2. +15
    -1
      src/core/plugins/oas3/components/request-body.jsx
  3. +418
    -0
      test/e2e-cypress/static/documents/features/petstore-only-pet.openapi.yaml
  4. +132
    -0
      test/e2e-cypress/tests/features/oas3-request-body-allow-empty-values.js

+ 45
- 14
src/core/components/parameter-include-empty.jsx View File

@@ -1,22 +1,53 @@
import React from "react"
import React, { Component } from "react"
import cx from "classnames"
import PropTypes from "prop-types"

export const ParameterIncludeEmpty = ({ isIncluded, onChange, isDisabled }) => {
const onCheckboxChange = e => {
onChange(e.target.checked)
}
return <label className={cx("parameter__empty_value_toggle", {
"disabled": isDisabled
})}>
<input type="checkbox" disabled={isDisabled} checked={!isDisabled && isIncluded} onChange={onCheckboxChange} />
Send empty value
</label>
}
ParameterIncludeEmpty.propTypes = {

const noop = () => { }

const ParameterIncludeEmptyPropTypes = {
isIncluded: PropTypes.bool.isRequired,
isDisabled: PropTypes.bool.isRequired,
isIncludedOptions: PropTypes.object,
onChange: PropTypes.func.isRequired,
}

export default ParameterIncludeEmpty
const ParameterIncludeEmptyDefaultProps = {
onChange: noop,
isIncludedOptions: {},
}
export default class ParameterIncludeEmpty extends Component {
static propTypes = ParameterIncludeEmptyPropTypes
static defaultProps = ParameterIncludeEmptyDefaultProps

componentDidMount() {
const { isIncludedOptions, onChange } = this.props
const { shouldDispatchInit, defaultValue } = isIncludedOptions
if (shouldDispatchInit) {
onChange(defaultValue)
}
}

onCheckboxChange = e => {
const { onChange } = this.props
onChange(e.target.checked)
}

render() {
let { isIncluded, isDisabled } = this.props

return (
<div>
<label className={cx("parameter__empty_value_toggle", {
"disabled": isDisabled
})}>
<input type="checkbox"
disabled={isDisabled}
checked={!isDisabled && isIncluded}
onChange={this.onCheckboxChange} />
Send empty value
</label>
</div>
)
}
}

+ 15
- 1
src/core/plugins/oas3/components/request-body.jsx View File

@@ -53,6 +53,19 @@ const RequestBody = ({
const handleFile = (e) => {
onChange(e.target.files[0])
}
const setIsIncludedOptions = (key) => {
let options = {
key,
shouldDispatchInit: false,
defaultValue: true
}
let currentInclusion = requestBodyInclusionSetting.get(key, "no value")
if (currentInclusion === "no value") {
options.shouldDispatchInit = true
// future: can get/set defaultValue from a config setting
}
return options
}

const Markdown = getComponent("Markdown", true)
const ModelExample = getComponent("modelExample")
@@ -173,7 +186,8 @@ const RequestBody = ({
{required ? null : (
<ParameterIncludeEmpty
onChange={(value) => onChangeIncludeEmpty(key, value)}
isIncluded={requestBodyInclusionSetting.get(key)}
isIncluded={requestBodyInclusionSetting.get(key) || false}
isIncludedOptions={setIsIncludedOptions(key)}
isDisabled={!isEmptyValue(currentValue)}
/>
)}


+ 418
- 0
test/e2e-cypress/static/documents/features/petstore-only-pet.openapi.yaml View File

@@ -0,0 +1,418 @@
openapi: 3.0.2
servers:
- url: /v3
info:
description: |-
This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about
Swagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!
You can now help us improve the API whether it's by making changes to the definition itself or to the code.
That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
Some useful links:
- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)
- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)
version: 1.0.5-SNAPSHOT
title: Swagger Petstore - OpenAPI 3.0
termsOfService: 'http://swagger.io/terms/'
contact:
email: apiteam@swagger.io
license:
name: Apache 2.0
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
tags:
- name: pet
description: Everything about your Pets
externalDocs:
description: Find out more
url: 'http://swagger.io'
paths:
/pet:
post:
tags:
- pet
summary: Add a new pet to the store
description: Add a new pet to the store
operationId: addPet
responses:
'200':
description: Successful operation
content:
application/xml:
schema:
$ref: '#/components/schemas/Pet'
application/json:
schema:
$ref: '#/components/schemas/Pet'
'405':
description: Invalid input
security:
- petstore_auth:
- 'write:pets'
- 'read:pets'
requestBody:
description: Create a new pet in the store
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
application/xml:
schema:
$ref: '#/components/schemas/Pet'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/Pet'
put:
tags:
- pet
summary: Update an existing pet
description: Update an existing pet by Id
operationId: updatePet
responses:
'200':
description: Successful operation
content:
application/xml:
schema:
$ref: '#/components/schemas/Pet'
application/json:
schema:
$ref: '#/components/schemas/Pet'
'400':
description: Invalid ID supplied
'404':
description: Pet not found
'405':
description: Validation exception
security:
- petstore_auth:
- 'write:pets'
- 'read:pets'
requestBody:
description: Update an existent pet in the store
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
application/xml:
schema:
$ref: '#/components/schemas/Pet'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/Pet'
/pet/findByStatus:
get:
tags:
- pet
summary: Finds Pets by status
description: Multiple status values can be provided with comma separated strings
operationId: findPetsByStatus
parameters:
- name: status
in: query
description: Status values that need to be considered for filter
required: false
explode: true
schema:
type: string
enum:
- available
- pending
- sold
default: available
responses:
'200':
description: successful operation
content:
application/xml:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
'400':
description: Invalid status value
security:
- petstore_auth:
- 'write:pets'
- 'read:pets'
/pet/findByTags:
get:
tags:
- pet
summary: Finds Pets by tags
description: >-
Multiple tags can be provided with comma separated strings. Use tag1,
tag2, tag3 for testing.
operationId: findPetsByTags
parameters:
- name: tags
in: query
description: Tags to filter by
required: false
explode: true
schema:
type: array
items:
type: string
responses:
'200':
description: successful operation
content:
application/xml:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
'400':
description: Invalid tag value
security:
- petstore_auth:
- 'write:pets'
- 'read:pets'
'/pet/{petId}':
get:
tags:
- pet
summary: Find pet by ID
description: Returns a single pet
operationId: getPetById
parameters:
- name: petId
in: path
description: ID of pet to return
required: true
schema:
type: integer
format: int64
responses:
'200':
description: successful operation
content:
application/xml:
schema:
$ref: '#/components/schemas/Pet'
application/json:
schema:
$ref: '#/components/schemas/Pet'
'400':
description: Invalid ID supplied
'404':
description: Pet not found
security:
- api_key: []
- petstore_auth:
- 'write:pets'
- 'read:pets'
post:
tags:
- pet
summary: Updates a pet in the store with form data
description: ''
operationId: updatePetWithForm
parameters:
- name: petId
in: path
description: ID of pet that needs to be updated
required: true
schema:
type: integer
format: int64
- name: name
in: query
description: Name of pet that needs to be updated
required: true
schema:
type: string
- name: status
in: query
description: Status of pet that needs to be updated
schema:
type: string
responses:
'405':
description: Invalid input
security:
- petstore_auth:
- 'write:pets'
- 'read:pets'
delete:
tags:
- pet
summary: Deletes a pet
description: ''
operationId: deletePet
parameters:
- name: api_key
in: header
description: ''
required: false
schema:
type: string
- name: petId
in: path
description: Pet id to delete
required: true
schema:
type: integer
format: int64
responses:
'400':
description: Invalid pet value
security:
- petstore_auth:
- 'write:pets'
- 'read:pets'
'/pet/{petId}/uploadImage':
post:
tags:
- pet
summary: uploads an image
description: ''
operationId: uploadFile
parameters:
- name: petId
in: path
description: ID of pet to update
required: true
schema:
type: integer
format: int64
- name: additionalMetadata
in: query
description: Additional Metadata
required: false
schema:
type: string
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
security:
- petstore_auth:
- 'write:pets'
- 'read:pets'
requestBody:
content:
application/octet-stream:
schema:
type: string
format: binary
externalDocs:
description: Find out more about Swagger
url: 'http://swagger.io'
components:
schemas:
Category:
x-swagger-router-model: io.swagger.petstore.model.Category
properties:
id:
type: integer
format: int64
example: 1
name:
type: string
example: Dogs
xml:
name: category
type: object
Tag:
x-swagger-router-model: io.swagger.petstore.model.Tag
properties:
id:
type: integer
format: int64
name:
type: string
xml:
name: tag
type: object
Pet:
x-swagger-router-model: io.swagger.petstore.model.Pet
required:
- name
- photoUrls
properties:
id:
type: integer
format: int64
example: 10
name:
type: string
example: doggie
category:
$ref: '#/components/schemas/Category'
photoUrls:
type: array
xml:
wrapped: true
items:
type: string
xml:
name: photoUrl
tags:
type: array
xml:
wrapped: true
items:
$ref: '#/components/schemas/Tag'
xml:
name: tag
status:
type: string
description: pet status in the store
enum:
- available
- pending
- sold
xml:
name: pet
type: object
ApiResponse:
properties:
code:
type: integer
format: int32
type:
type: string
message:
type: string
xml:
name: '##default'
type: object
requestBodies:
Pet:
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
application/xml:
schema:
$ref: '#/components/schemas/Pet'
description: Pet object that needs to be added to the store
securitySchemes:
petstore_auth:
type: oauth2
flows:
implicit:
authorizationUrl: 'https://petstore.swagger.io/oauth/authorize'
scopes:
'write:pets': modify pets in your account
'read:pets': read your pets
api_key:
type: apiKey
name: api_key
in: header

+ 132
- 0
test/e2e-cypress/tests/features/oas3-request-body-allow-empty-values.js View File

@@ -0,0 +1,132 @@
/**
* @prettier
*/

describe("OpenAPI 3.0 Allow Empty Values in Request Body", () => {
it("should not apply or render to required fields", () => {
cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml"
)
.get("#operations-pet-addPet")
.click()
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Request Body
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(2) > .parameters-col_description .parameter__empty_value_toggle input")
.should("not.exist")
})

it("by default, should be checked for all non-required fields", () => {
cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml"
)
.get("#operations-pet-addPet")
.click()
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Request Body
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input")
.should("be.checked")
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(6) > .parameters-col_description .parameter__empty_value_toggle input")
.should("be.checked")
})

it("checkbox should be toggle-able", () => {
cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml"
)
.get("#operations-pet-addPet")
.click()
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Request Body
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input")
.should("be.checked")
.uncheck()
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input")
.should("not.be.checked")
})

it("on execute, should allow send with all empty values", () => {
cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml"
)
.get("#operations-pet-addPet")
.click()
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Execute
.get(".execute.opblock-control__btn")
.click()
// cURL component
.get(".responses-wrapper .copy-paste")
.should("exist")
.get(".responses-wrapper .copy-paste textarea")
.should("contains.text", "tags=&status=")
})

it("on execute, should allow send with some empty values", () => {
cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml"
)
.get("#operations-pet-addPet")
.click()
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Request Body
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input")
.uncheck()
// Execute
.get(".execute.opblock-control__btn")
.click()
// cURL component
.get(".responses-wrapper .copy-paste")
.should("exist")
.get(".responses-wrapper .copy-paste textarea")
.should("contains.text", "&status=")
.should("not.contains.text", "tags=")
})

it("on execute, should allow send with skip all empty values", () => {
cy.visit(
"/?url=/documents/features/petstore-only-pet.openapi.yaml"
)
.get("#operations-pet-addPet")
.click()
.get(".opblock-section .opblock-section-request-body .body-param-content-type > select")
.select("application/x-www-form-urlencoded")
// Expand Try It Out
.get(".try-out__btn")
.click()
// Request Body
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(5) > .parameters-col_description .parameter__empty_value_toggle input")
.uncheck()
.get(".opblock-body .opblock-section .opblock-section-request-body .parameters:nth-child(6) > .parameters-col_description .parameter__empty_value_toggle input")
.uncheck()
// Execute
.get(".execute.opblock-control__btn")
.click()
// cURL component
.get(".responses-wrapper .copy-paste")
.should("exist")
.get(".responses-wrapper .copy-paste textarea")
.should("not.contains.text", "tags=")
.should("not.contains.text", "status=")
})

})

Loading…
Cancel
Save