Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

google cloud endpoints body array

We have a rest API that is written in Java (hosted in Wildfly). Our service is running in kubernetes (GKE). We want to leverage Cloud Endpoints to track usage and responsiveness of our API. The API is not new, we have been shipping software that interacts with it for years. It is also quite large (thousands of public methods). We have Swagger documentation for our API, and have no validation errors. When I try to deploy our Swagger using:

gcloud beta service-management deploy swagger.yaml

It is not successful. I get the following error repeated 237 times:

ERROR: unknown location: http: body field path 'body' must be a non-repeated message.

I have tracked it down to 237 methods that include a json array in a body parameter. In our API these are methods that either accept or return a list of objects. Is there any way I can get this accepted by service-management deploy? Changing our API isn't an option, but we would really like to be able to use endpoints.

For example, this method signature:

@PUT
@Path ("/foobars/undelete")
@Consumes (MediaType.APPLICATION_JSON)
@Produces (MediaType.APPLICATION_JSON)
@ApiOperation (value = "Undelete foobars")
@ApiResponses (value =
{
    @ApiResponse (
        code              = 200,
        message           = "foobars undeleted",
        response          = FooBar.class,
        responseContainer = "List"
    ) , @ApiResponse (
        code              = 206,
        message           = "Not all foobars undeleted",
        response          = FooBar.class,
        responseContainer = "List"
    ) , @ApiResponse (
        code              = 410,
        message           = "Not found"
    ) , @ApiResponse (
        code              = 500,
        message           = "Server Error"
    )
})
public Response undeleteFooBars (@ApiParam (value = "FooBar ID List") List<UUID> entityIds)

generates this swagger snippet:

"/foobars/undelete":
    put:
      tags:
      - foo
      summary: Undelete FooBars
      description: ''
      operationId: undeleteFooBars
      consumes:
      - application/json
      produces:
      - application/json
      parameters:
      - in: body
        name: body
        description: FooBar ID List
        required: false
        schema:
          type: array
          items:
            type: string
            format: uuid
      responses:
        '200':
          description: Foo Bars undeleted
          schema:
            type: array
            items:
              "$ref": "#/definitions/FooBar"
        '206':
          description: Not all FooBars undeleted
          schema:
            type: array
            items:
              "$ref": "#/definitions/FooBar"
        '410':
          description: Not found
        '500':
          description: Server Error
like image 530
Brandon Davis Avatar asked Mar 31 '17 16:03

Brandon Davis


1 Answers

I have had the exact same problem with Endpoints, where it does not seem to think that passing an array of objects is valid as a body parameter. I worked around this by just using a generic object and a decent description. The description will not programatically fix anything, but using a generic object allows Endpoints to work and the description gives information to the consumer of the API for what is expected.

parameters:
  - in: body
    name: body
    description: Array of FooBar objects
    required: false
    schema:
      type: object

This seems like an oversight on the part of the Endpoints team IMHO as using an array of objects in the body fits fine within the OpenApi spec and works with tools like http://editor.swagger.io/

Edit: I should also add that it is generally bad practice to use just a raw array as a request body or response body as it can cause a contract breaking change if additional properties are desired in the future, like say a count or pagination information.
If this is an existing API and you are just documenting the existing contract, then this solution will work to get the job done, but if you are designing a new API, then a better definition would be:

parameters:
  - in: body
    name: body
    description: All the FooBar objects
    required: false
    schema:
      type: object
      properties:
        items:
          type: array
          items:
            $ref: '#/definitions/FooBarResource'

Since this could later be extended to add additional properties like

parameters:
  - in: body
    name: body
    description: All the FooBar objects
    required: false
    schema:
      type: object
      properties:
        count:
          type: integer
          description: The total count of resources
        callbackUrl:
          type: string
          description: The URL to trigger once creation is complete
        items:
          type: array
          items:
            $ref: '#/definitions/FooBarResource'
          description: The resources to create
like image 132
Scott Avatar answered Sep 28 '22 00:09

Scott