question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

API component schema description incorrectly overwritten by API parameter description

See original GitHub issue

Describe the bug The description for a shared API component schema is overwritten by the description for an API parameter.

To Reproduce Create a class annotated with the @Schema annotation and specify a description. Create a method with a parameter with the type of this class annotated with the @Parameter annotation with a description. The description for the shared class is overwritten with description for the parameter.

Organization.java

package digital.inception.party;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.UUID;

@Schema(
    description =
        "This is the description being overwritten")
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"id", "name"})
public class Organization {

  @Schema(
      description =
          "The Universally Unique Identifier (UUID) uniquely identifying the organization",
      required = true)
  @JsonProperty(required = true)
  private UUID id;

  @Schema(description = "The name of the organization", required = true)
  @JsonProperty(required = true)
  private String name;

  public Organization() {}

  public UUID getId() {
    return id;
  }

  public String getName() {
    return name;
  }

  public void setId(UUID id) {
    this.id = id;
  }

  public void setName(String name) {
    this.name = name;
  }
}

API Method

  @Operation(summary = "Create the organization", description = "Create the organization")
  @ApiResponses(
      value = {
        @ApiResponse(
            responseCode = "204",
            description = "The organization was created successfully"),
        @ApiResponse(
            responseCode = "400",
            description = "Invalid argument",
            content =
                @Content(
                    mediaType = "application/json",
                    schema = @Schema(implementation = RestControllerError.class))),
        @ApiResponse(
            responseCode = "409",
            description = "An organization with the specified ID already exists",
            content =
                @Content(
                    mediaType = "application/json",
                    schema = @Schema(implementation = RestControllerError.class))),
        @ApiResponse(
            responseCode = "500",
            description =
                "An error has occurred and the request could not be processed at this time",
            content =
                @Content(
                    mediaType = "application/json",
                    schema = @Schema(implementation = RestControllerError.class)))
      })
  @RequestMapping(
      value = "/organizations",
      method = RequestMethod.POST,
      produces = "application/json")
  @ResponseStatus(HttpStatus.NO_CONTENT)
  public void createOrganization(
      @Parameter(name = "organization", description = "This description will overwrite the existing description", required = true)
          @RequestBody
          Organization organization)
      throws InvalidArgumentException, DuplicateOrganizationException, PartyServiceException {

   ...

  }

I believe the problem is in the calculateRequestBodySchema method of the org.springdoc.core.GenericParameterBuilder class.

The code below retrieves the existing component schema and replaces the description with the description for the API parameter.

if (schemaN != null && StringUtils.isEmpty(schemaN.getDescription()) && parameterInfo.getParameterModel() != null) {
			String description = parameterInfo.getParameterModel().getDescription();
			if (schemaN.get$ref() != null && schemaN.get$ref().contains(AnnotationsUtils.COMPONENTS_REF)) {
				String key = schemaN.get$ref().substring(21);
				Schema existingSchema = components.getSchemas().get(key);
				existingSchema.setDescription(description);
			}
			else
				schemaN.setDescription(description);
		}

I am not sure if there is a valid reason for doing this, perhaps if the description doesn’t exist for the shared component schema this might be a valid approach. If a description does exist for shared component schema then this behaviour does not seem correct. I am happy to submit a pull request that changes this behaviour to only change the description if it has not already been set for the shared component schema.

I am using springdoc-openapi-common 1.4.6.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
marcusportmanncommented, Sep 5, 2020

Thank you @debargharoy, your comment has been incredibly helpful.

I have replaced all my @Parameter annotations with the @io.swagger.v3.oas.annotations.parameters.RequestBody annotation, and specified the description I originally specified on the @Parameter annotation on this annotation. As long as this is done consistently the description on the shared schema is no longer overwritten.

It is a pity that both the @org.springframework.web.bind.annotation.RequestBody and @io.swagger.v3.oas.annotations.parameters.RequestBody annotations are required and that the second one needs to be fully qualified but at least my problem has been resolved.

0reactions
bnasslahsencommented, Sep 6, 2020

@marcusportmann,

If you are just having one object in a HTTP POST Method, using @Parameter annotation, is not the most relevant one. You should use instead @RequestBody swagger annotation which was specially designed for this purpose.

The usage of @Parameter annotation in a HTTP POST has more sense, if you have many parameters, and you want for each one a different description. At this moment:

  • If the developer fills the @Parameter description, it will be considered as the desired descirption, even the Object referenced by the Parameter annotation has an existing description. This can be useful, in case an object is reused between different HTTP methods, but we want a different description. This is an example, that you can find in the tests:
 	@Operation(summary = "Multiple files and JSON payloads as multi part request")
	@PostMapping(
			value = "multi",
			consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
			produces = MediaType.TEXT_PLAIN_VALUE)
	public String multiFilesInMultiPart(
			@RequestPart("params")
			@Parameter(
					description = "This is the configuration",
					content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE))
			final JsonRequest jsonRequest,
			@RequestPart(value = "file1", required = false) @Parameter(description = "This is file1")
			final MultipartFile file1,
			@RequestPart(value = "file2", required = false) @Parameter(description = "This is file2")
			final MultipartFile file2) {
		return "Hello World " + jsonRequest.getName();
	}
  • If the developer, just wants to reuse the description from the original object that is referenced by the Parameter annotation, he needs not to fill the Parameter description: And this is where a fix can make sense 😃
Read more comments on GitHub >

github_iconTop Results From Across the Web

Is there any way to overwrite the default description of ...
You can override any parameters description part as: from rest_framework.decorators import api_view from drf_spectacular.utils import ...
Read more >
Step 4: The paths object (OpenAPI tutorial) | Documenting APIs
The paths object contains the meat of your API information. The paths object has several sub-objects: a path items object, an operations ...
Read more >
Known Issues for Oracle Analytics Server
This document describes information about known software issues and their workarounds for this release of Oracle Analytics Server.
Read more >
Amazon API Gateway important notes
API Gateway does not support sharing a custom domain name across REST and WebSocket ... In method responses, schema definition must be of...
Read more >
Springfox Reference Documentation - GitHub Pages
Parameters added here will be part of every API Operation in the ... service and schema description models along with their builders.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found