Search code examples
jsonschemaraml

RAML: using same data type for GET & POST with differing properties


So I'm extracting a JSON schema out of my RAML spec to validate output in GET methods and also the input in the POST method.

Every entity of this type has a "required" ID property - at least it's required when listing those entities in a 'get item' or 'get collection'-request. But when validating the received post data to create such an entity the ID is obviously not required (and discarded if it's send anyway).

What's the best DRY way to have this ID property required for GET requests, but not required, or even better not existing in the type for POST requests?

TL;DR: start reading below ;)

Example to make it easier to understand:

For GET requests the type should be like:

properties:
  id:
  something1: 
  something2?: 

For POST requests the type should be like:

properties:
  something1: 
  something2?: 

without having to define both separately, but also without using inheritance to have to create two types for every resource.

Ideally I would solve it that way, but that doesn't seem to work:

get:
  description: Retrieve a list of <<resourcePathName|!uppercamelcase>>.
  responses:
    200:
      body:
        application/json:
          type: [ entity_id_object, <<resourcePathName|!singularize|!uppercamelcase>> ][]
          example: <<exampleCollection>>

and entity_id_object ist just:

entity_id_object:
   properties:
     id:

I think it's because the <<resourcePathName|!singularize|!uppercamelcase>> is not working in this combination.


Solution

  • I can't think of a way of doing it without two types yet. But this example at least only makes you only pass one type and automatically appends 'NoId' to the type name for POST requests.

    #%RAML 1.0
    title: My API
    version: v1
    mediaType: application/json
    
    types:
      ResponseNoId:
        properties:
          something1: 
          something2?:
      ResponseId:
        properties:
          id:
          something1: 
          something2?:
      Response:
        ResponseNoId|ResponseId
    
    resourceTypes:
      collection:
        usage: Use this resourceType to represent a collection of items
        description: A collection of <<resourcePathName|!uppercamelcase>>
        get:
          description: |
            Get all <<resourcePathName|!uppercamelcase>>,
            optionally filtered
          is: [ hasResponseCollection: { typeName: <<typeName>> } ]
        post:
          description: |
            Create a new <<resourcePathName|!uppercamelcase|!singularize>>
          is: [ hasRequestItem: { typeName: <<typeName>> } ]
      item:
        usage: Use this resourceType to represent any single item
        description: A single <<typeName>>
        get:
          description: Get a <<typeName>>
          is: [ hasResponseItem: { typeName: <<typeName>> } ]
    
    traits:
      hasRequestItem:
        body:
          application/json:
            type: <<typeName>>
      hasResponseItem:
        responses:
          200:
            body:
              application/json:
                type: <<typeName>>
      hasResponseCollection:
        responses:
          200:
            body:
              application/json:
                type: <<typeName>>[]
    
    /myResource:
      type: { collection: { typeName: Response } }
      get:
    
      /{id}:
        type: { item: { typeName: Response } }
      post:
        body:
          application/json: