Multiple schemas, examples by payload type or GET param


#1

Hey everybody!

I’m describing my json API in RAML and recently noticed that in some cases I will need to provide multiple schemas and examples for some endpoints. There is two such cases when I need to describe my API:

First case is when I’m sending POST request to endpoint and some of payload params determines response structure. Real word example: let’s say that param is account_type. Business account type can hold additional fields like VAT number etc, while Personal account type will have its username and other fields.

Second case is when I want to include some additional relations to resource. Let’s say I have /classifieds endpoint. I can include additional data ( relations ) to it by adding some query params like user, category, etc: /classifieds?include=user or classifieds?include=category or even both: classifieds?include=user,category. It’s obvious that in such cases examples and schemas will be different.

My considerations: For second scenario possible solution could be always to describe my API with maximum possible relations. However how to deal with first I’m not sure yet.

These scenarios I think is quite often in APIs however I was not able to find solution using docs or by google.


#2

Have you considered using the union type for this?

For example:

types:
  BusinessAccount:
  PersonalAccount:

/classifieds:
  get:
    responses:
      200:
        body:
          application/json:
            type: BusinessAccount | PersonalAccount

The above example is very simplified of course :slight_smile: Hope it helps though.


#3

Makes sense, thank you!

It’s a little bit complicated to explain, I’m trying to make my docs splited in re-usable chunks of code blocks. Now I’m wondering is there any way to pass already joined two types as variable to some resource type?

At first maybe could please take a look and verify that my current raml docs is valid, please see in action: https://anypoint.mulesoft.com/apiplatform/noname-10/#/portals/organizations/eb83f888-dced-479c-8339-9a96f8f854e2/apis/22427119/versions/784156/pages/269641 source: https://github.com/deividaspetraitis/pineska.pl


#4

Passing it into a resource type shouldn’t be a problem either. For example:

types:
  BusinessAccount:
  PersonalAccount:
  Union: BusinessAccount | PersonalAccount

resourceTypes:
  collection:
    get:
      responses:
        200:
          body:
            application/json:
              type: <<type>>

/classifieds:
  type:
    collection:
      type: Union

#5

Awesome, thank you for your time and help!

One more question about resources reusage, is there any way to inherit multiple resource types ( please see /users endpoint ) ?
For me it is a common sense to have feature since defining different options of CRUD operations and joining every time into single type looks a little bit overwhelming ( for example in some enpoints I will need only POST, in another DELETE and GET and so forth. ).

#%RAML 1.0
title: pineska.pl
version: v1
protocols: [ HTTP, HTTPS ]
baseUri: http://api.pineska.pl/{version}
mediaType: [ application/vnd.api+json ]
documentation:
 - title: Home
   content: !include documentation/home.markdown
securitySchemes:
  oauth_2_0: !include securitySchemes/oauth_2_0.raml
uses:
  CRUD: libraries/crud.raml
  http: ../libraries/http.raml
types:
  UsersBusinessCreateRequest:
    example: !include examples/users/post-business-request-example.json
  UsersPersonalCreateRequest:
    example: !include examples/users/post-personal-request-example.json
  UsersBusinessCreateResponse:
    example: !include examples/users/post-business-response-example.json
  UsersPersonalCreateResponse:
    example: !include examples/users/post-personal-response-example.json
  UserCreateRequest: UsersPersonalCreateRequest | UsersBusinessCreateRequest
  UserCreateResponse: UsersPersonalCreateResponse | UsersBusinessCreateResponse
/users:
  type:
   CRUD.create:
     location_example: http://..
     request: UserCreateRequest
     response: UserCreateResponse
   CRUD.list: # error: A resource or resourceType can inherit from a single resourceType

#6

No, RAML does not introduce multiple inheritance for resource types. I think in your particular case you can use optional methods in resource types. For example:

types:
  BusinessAccount:
  PersonalAccount:
  Union: BusinessAccount | PersonalAccount

resourceTypes:
  collection:
    get:
      responses:
        200:
          body:
            application/json:
              type: <<type>>
    post?:
      description: optional post method
      body:
        application/json:
          type: object
          properties:
            setting: string
    delete?:
      description: optional delete method
      responses:
        200:
          body:
            application/json:
              type: object
              properties:
                errorMsg: string

/classifieds:
  # only has a get method
  type:
    collection:
      type: Union
/classifieds-with-post:
  type:
    collection:
      type: Union
  post: # explicitly add post and all it's content defined inside the resource type
/classifieds-with-delete:
  type:
    collection:
      type: Union
  delete: # explicitly add delete and all it's content defined inside the resource type
/classifieds-with-all:
  type:
    collection:
      type: Union
  post: # explicitly add post and all it's content defined inside the resource type
  delete: # explicitly add delete and all it's content defined inside the resource type

This is how it looks like:

image

As you can see, the get method is everywhere since it’s not marked as optional. The post and delete are only attached to the resources that explicitly use them.

Hope that helps you!


#7

The limitation is that you cannot express that the server MUST return a BusinessAccount type if param account_type=business and MUST return a PersonalAccount is account_type=personal.