Swagger-editor: PUT and PATCH with identical mapping path can't coexist in editor

Created on 8 Mar 2016  路  10Comments  路  Source: swagger-api/swagger-editor

_From @JacquesPerrault on March 5, 2016 17:39_

When the following is placed into the Swagger editor, the ui will show either the PUT or the PATCH, but not both. Additionally, if the editor is shut down, then restarted, it crashes, requiring a manual edit of the swagger.yaml in order to get the editor going again. Swagger definition and stack track posted below.

swagger definition

  /widget/{widgetId}:
    x-swagger-router-controller: widgetPut
    put:
      summary: Update a widget
      operationId: widgetPut
      consumes: ["application/json"]
      produces: ["application/json"]
      parameters:
        - name: widgetId
          in: path
          description: The UID of the widget
          required: true
          type: string
        - name: body
          in: body
          description: widget content
          required: true
          schema:
            type: object
      responses:
        "200":
          description: OK
          schema:
            $ref: "#/definitions/SuccessResponse"
        default:
          description: Error
          schema:
            $ref: "#/definitions/ErrorResponse"


  /widget/{widgetId}:
    x-swagger-router-controller: widgetPatch
    patch:
      summary: Patch a widget
      operationId: widgetPatch
      consumes: ["application/json"]
      produces: ["application/json"]
      parameters:
        - name: widgetId
          in: path
          description: The UID of the widget
          required: true
          type: string
        - name: body
          in: body
          description: widget content
          required: true
          schema:
            type: object
      responses:
        "200":
          description: OK
          schema:
            $ref: "#/definitions/SuccessResponse"
        default:
          description: Error
          schema:
            $ref: "#/definitions/ErrorResponse"

* stack trace **

_line 113_ is referring to the second instance of the mapping key, which in this case is the patch version.

{ [YAMLException: duplicated mapping key at line 113, column 3:
      /messages/{messageId}:
      ^]
  name: 'YAMLException',
  reason: 'duplicated mapping key',
  mark:
   Mark {
     name: null,
     buffer: 'swagger: "2.0"\r\ninfo:\r\n  version: "0.0.1"\r\n  title: Project Castle APIs\r\n# during dev, should point to your local machine\r\nhost: localhost:10010\r\n# basePath prefixes all resource paths \r\nbasePath: /\r\n# \r\nschemes:\r\n  # tip: remove http to make production-grade\r\n  - http\r\n  - https\r\n# format of bodies a client can send (Content-Type)\r\nconsumes:\r\n  - applic
ation/json\r\n# format of the responses to the client (Accepts)\r\nproduces:\r\n  - application/json\r\npaths:\r\n\r\n  /messages:\r\n    x-swagger-router-controller: messagesCreateOrSend\r\n    post:\r\n      summary: Create and/or send a message\r\n      description: The message entity is entirely defined by the object passed in `body`, and is intentionally left implementation agnostic.  If `sen
d` is *false* the message should be saved as a draft, otherwise the message should be marked for delivery.  Either way, return the resulting `messageId`.  This endpoint MUST be called to create a message; updates should use **PUT /messages/{messageId}** or **PATCH /messages/{messageId}** \r\n      operationId: messagesCreateOrSend\r\n      consumes: ["application/json"]\r\n      produces: ["applic
ation/json"]\r\n      parameters:\r\n        - name: send\r\n          in: query\r\n          description: send message if *true*, save as draft otherwise\r\n          required: true\r\n          type: boolean\r\n        - name: body\r\n          in: body\r\n          description: message content\r\n          required: true\r\n          schema:\r\n            type: object\r\n      responses:\r\n
      "200":\r\n          description: OK\r\n          schema:\r\n            $ref: "#/definitions/ObjectResponse"\r\n        default:\r\n          description: Error\r\n          schema:\r\n            $ref: "#/definitions/ErrorResponse"\r\n\r\n\r\n  /widget/{widgetId}:\r\n    x-swagger-router-controller: widgetPut\r\n    put:\r\n      summary: Update a widget\r\n      operationId: widgetPut\r\n
     consumes: ["application/json"]\r\n      produces: ["application/json"]\r\n      parameters:\r\n        - name: widgetId\r\n          in: path\r\n          description: The UID of the widget\r\n          required: true\r\n          type: string\r\n        - name: body\r\n          in: body\r\n          description: widget content\r\n          required: true\r\n          schema:\r\n
type: object\r\n      responses:\r\n        "200":\r\n          description: OK\r\n          schema:\r\n            $ref: "#/definitions/ObjectResponse"\r\n        default:\r\n          description: Error\r\n          schema:\r\n            $ref: "#/definitions/ErrorResponse"\r\n\r\n\r\n  /widget/{widgetId}:\r\n    x-swagger-router-controller: widgetPatch\r\n    patch:\r\n      summary: Patch a wi
dget\r\n      operationId: widgetPatch\r\n      consumes: ["application/json"]\r\n      produces: ["application/json"]\r\n      parameters:\r\n        - name: widgetId\r\n          in: path\r\n          description: The UID of the widget\r\n          required: true\r\n          type: string\r\n        - name: body\r\n          in: body\r\n          description: widget content\r\n          required
: true\r\n          schema:\r\n            type: object\r\n      responses:\r\n        "200":\r\n          description: OK\r\n          schema:\r\n            $ref: "#/definitions/ObjectResponse"\r\n        default:\r\n          description: Error\r\n          schema:\r\n            $ref: "#/definitions/ErrorResponse"\r\n\r\n\r\n  /messages/{messageId}:\r\n    x-swagger-router-controller: messages
UpdateOrSend\r\n    put:\r\n      summary: Update or send a message\r\n      description: If `send` is *false* update the message, otherwise send the message.  Either way, return the messageId.\r\n      operationId: messagesUpdateOrSend\r\n      consumes: ["application/json"]\r\n      produces: ["application/json"]\r\n      parameters:\r\n        - name: messageId\r\n          in: path\r\n
  description: The UID of the message\r\n          required: true\r\n          type: string\r\n        - name: send\r\n          in: query\r\n          description: send message if *true*, save as draft otherwise\r\n          required: true\r\n          type: boolean\r\n        - name: body\r\n          in: body\r\n          description: message content\r\n          required: true\r\n          sch
ema:\r\n            type: object\r\n      responses:\r\n        "200":\r\n          description: OK\r\n          schema:\r\n            $ref: "#/definitions/ObjectResponse"\r\n        default:\r\n          description: Error\r\n          schema:\r\n            $ref: "#/definitions/ErrorResponse"\r\n\r\n\r\n  /attachments/{messageId}:\r\n    x-swagger-router-controller: attachments\r\n    post:\r\n
      summary: Attach a file residing on the user\'s device to a message\r\n      description: This endpoint should return the URI of the attachment\r\n      operationId: attachments\r\n      consumes: ["application/json"]\r\n      produces: ["application/json"]\r\n      parameters:\r\n        - name: messageId\r\n          in: path\r\n          description: The UID of the message to be associated
 with the attachment\r\n          required: true\r\n          type: string\r\n        - name: body\r\n          in: body\r\n          description: encoded attchment content\r\n          required: true\r\n          schema:\r\n            type: object\r\n      responses:\r\n        "200":\r\n          description: OK\r\n          schema:\r\n            $ref: "#/definitions/ObjectResponse"\r\n
 default:\r\n          description: Error\r\n          schema:\r\n            $ref: "#/definitions/ErrorResponse"\r\n\r\n\r\n  /search/messages:\r\n    x-swagger-router-controller: searchMessages\r\n    post:\r\n      summary: Returns messages for the authenticated user\r\n      description: Messages can be filtered using predefined parameters, or arbitrary search parameters can be defined using t
he \'arbitraryFilterParams\' parameter.\r\n      operationId: searchMessages\r\n      consumes: ["application/json"]\r\n      produces: ["application/json"]\r\n      parameters:\r\n        - name: body\r\n          in: body\r\n          description: Filters to use as part of the search\r\n          required: true\r\n          schema:\r\n            $ref: "#/definitions/Filter"\r\n      responses:\
r\n        "200":\r\n          description: OK\r\n          schema:\r\n            $ref: "#/definitions/ObjectResponse"\r\n        default:\r\n          description: Error\r\n          schema:\r\n            $ref: "#/definitions/ErrorResponse"\r\n\r\n\r\n# complex objects have schema definitions\r\ndefinitions:\r\n\r\n  Filter:\r\n    type: object\r\n    properties:\r\n      limit:\r\n        type
: string\r\n        description: Number of messages to return.  Limit is applied after messages have been filtered and sorted.\r\n      tags:\r\n        type: array\r\n        description: List of tags to filter on.  Only messages associated with these tags will be returned.\r\n        items:\r\n          type: string\r\n      userId:\r\n        type: string\r\n        description: Only messages b
elonging to the specified userId will be returned.  This can be used for delegation; the auth token pasesed with the request will be used to determine entitlement.\r\n      sortOrder:\r\n        type: array\r\n        description: An arbitrary string passed to the adapter ("ascending", "descending", "sentiment", etc).  Implementation is adapter-specific.  Should only be applied after all filtering
 is complete.\r\n        items:\r\n          type: string\r\n      startDate:\r\n        type: string\r\n        description: Only messages created/sent/received on or after this date will be returned.  Will work in conjunction with "endDate".\r\n      endDate:\r\n        type: string\r\n        description: Only messages created/sent/received on or before this date will be returned.  Will work in
 conjunction with "endDate".\r\n      sentiment:\r\n        type: array\r\n        description: The sentiment of the message.  Can be one or more values between 1.0 and -1.0\r\n        items:\r\n          type: number\r\n      arbitraryFilterParams:\r\n        type: object\r\n        description: Used to pass arbitrary key/value parameters to the adapter\r\n\r\n\r\n  ObjectResponse:\r\n    type: s
tring\r\n    description: Used to return an arbitrary string and an array of objects, both optional.\r\n    properties:\r\n      message:\r\n        type: string\r\n      data:\r\n        type: array\r\n        items:\r\n          type: object\r\n\r\n\r\n  ErrorResponse:\r\n    required:\r\n      - message\r\n    properties:\r\n      message:\r\n        type: string\r\n\u0000',
     position: 3295,
     line: 112,
     column: 2 },
  message: 'duplicated mapping key at line 113, column 3:\n      /messages/{messageId}:\n      ^' }

_Copied from original issue: swagger-api/swagger-core#1700_

Most helpful comment

Put them both under the same path and it will work. JSON doesn't allow duplicate keys.

All 10 comments

Put them both under the same path and it will work. JSON doesn't allow duplicate keys.

Thanks for the feedback, that worked nicely!

@webron I thought it worked, but while put/patch/delete all appear in the edit ui, I get the same error when I restart the editor. My definition is below, is there a different way I should be defining different methods (e.g. put/patch/delete) for the same path?

  /messages/{messageId}:
    x-swagger-router-controller: messagesUpdateOrSend
    put:
      summary: Update/send a message
      description: The `PUT` method should be used where it is desireable to submitting every property whether it changed or not (as opposed to updating discrete properties of a message).  This endpoint MUST NOT be called if a `messageId` is not available. If `send=false` the message MUST be saved as a draft, otherwise the message MUST be marked for delivery.
      operationId: messagesUpdateOrSend
      consumes: ["application/json"]
      produces: ["application/json"]
      parameters:
        - name: messageId
          in: path
          description: A UID used by the proxy to uniquely identify the message.
          required: true
          type: string
        - name: send
          in: query
          description: Send message if `query=true`, save as draft if `query=false`
          required: true
          type: boolean
        - name: token
          in: query
          description: auth token, if not included in header.  Example `token=[Token]`
          required: false
          type: string
        - name: body
          in: body
          description: This object must contain some (or all) message properties for a particular back end application server (e.g. Domino, Exchange, Gmail, Yahoo).  Example `body {"to":"joesmith%40email.com","from":"janesmith%40email.com","subject":"This is a test","body":"Can you hear me now%3F","tags":["keepers","follow up"],"flags":["urgent","confidential"],...}`
          required: true
          schema:
            type: object
      responses:
        "200":
          description: Success/OK
          schema:
            $ref: "#/definitions/SuccessResponse"
        default:
          description: Error
          schema:
            $ref: "#/definitions/ErrorResponse"
    x-swagger-router-controller: messagesPatchOrSend
    patch:
      summary: Update/send a message
      description: The `PATCH` method should be used where it is desireable to change discrete properties of a message (as opposed to updating every property whether it changed or not).  This endpoint can only be called if a `messageId` is available. If `send=false` update the message, otherwise mark the message for delivery.
      operationId: messagesPatchOrSend
      consumes: ["application/json"]
      produces: ["application/json"]
      parameters:
        - name: messageId
          in: path
          description: A UID used by the proxy to uniquely identify the message.
          required: true
          type: string
        - name: send
          in: query
          description: Send message if `query=true`, save as draft if `query=false`
          required: true
          type: boolean
        - name: token
          in: query
          description: auth token, if not included in header.  Example `token=[Token]`
          required: false
          type: string
        - name: body
          in: body
          description: This object should only contain fields to be updated.  Example `body {"subject":"This is another test","body":"Is there anybody out there%3F",...}`
          required: true
          schema:
            type: object
      responses:
        "200":
          description: Success/OK
          schema:
            $ref: "#/definitions/SuccessResponse"
        default:
          description: Error
          schema:
            $ref: "#/definitions/ErrorResponse"
    x-swagger-router-controller: messagesDelete
    delete:
      summary: Delete a single message
      description: Delete the message associated with `messageId` and all associated attachments.  Attachments can be resolved by the proxy server using `messageId` and need not be included in the request payload.
      operationId: messagesDelete
      consumes: ["application/json"]
      produces: ["application/json"]
      parameters:
        - name: messageId
          in: path
          description: UID of the message to be deleted
          required: true
          type: string
        - name: token
          in: query
          description: auth token, if not included in header.  Example `token=[Token]`
          required: false
          type: string
      responses:
        "200":
          description: Success/OK.
          schema:
            $ref: "#/definitions/SuccessResponse"
        default:
          description: Error
          schema:
            $ref: "#/definitions/ErrorResponse"

What error are you getting? Seems to load fine for me.

@JacquesPerrault - same as the original issue. You have x-swagger-router-controller twice under the same level, which is not allowed.

@webron ah, so you'd only have one controller for all three methods?

Sounds like, yeah.

@webron thanks. I removed the x-swagger-router-controller entirely and left the operationId. Seems happy now.

Thanks for the update, glad it worked out.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

marcopiraccini picture marcopiraccini  路  3Comments

radj picture radj  路  5Comments

ljerka picture ljerka  路  5Comments

freak4pc picture freak4pc  路  3Comments

jennaprice picture jennaprice  路  4Comments