How do I reference nested sub-schemas from RAML?

@rdohms I have been poking around for a satisfactory solution to this for some time as well…
My current workaround involves the following:
1- define each entity in its own file without any extension (song, book),
2- !include each entity in the schemas section of the raml file
3- host the schemas on an http server
4- define the schema id of the roots (song) as absolute URIs to http server
5- the referenced entity schema id (book) will then be resolved against the root entity URI hence able to be located on the http server.
…Works for me on Mule 3.6.1 + ApiKit
but I’m still interested to hear about a solution resolving schemas on local file system

@lco, that sounds like a good workaround for the time being.

@rdohms: i think that is not a problem of the spec itself. it’s more a problem of the parser.

@lco i was thinking something similar, i’ll try both out and see what happens.

@christian_vogel i’m not sure, i’m thinking that the way json-schema is integrated in the RAML spec breaks how json-schema does references, since its usually wrapped in a yaml shell. So it may be an issue with the spec that means regular json schema parsers don’t work with RAML embedded json schemas.

What may be a better solution is to allow you to link to a complete json schema file with all entities and allow RAML to reference the schema id. That way json schema is resolving in its own isolated shell and RAML is capable of reading from it.

I am not really sure if that would be true for the json schema parser going through the value of a schema parameter. But that is something easily to test right :wink:

I like the idea to also have to ability to directly include your json schema, but on the other side I would recommend to always have the actual schema outside your RAML and to do an !include. Unfortunately, the way most of the parser works are to inject the JSON schema back into the RAML, afaik. Maybe in the future there is a more elegant way of doing that.

I’m facing the same issue now.

Has there been any updates? I’ve seen the github issues, and looked all around, but i can’t seem to find a best practice for this.

I was considering writing each entity in its own file, then writing a script to compile it down to one file.

Would that be a better approach or perhaps creating mini raml files with !includes for the dependencies?

Can you post an example, please.

@christian_vogel Thanks for your reply.

Say I have 4 entities:

Users, Dogs, Cats, and Collars.

Each is independent, and have CRUD endpoints. But, Users have Dogs and Cats. Dogs and Cats have Collars.

I want to define each of these entities separately, with independent endpoints for their CRUD functionality.

I also want to return a User with an array of Dogs and Cats and their nested properties.

I want to define each entity’s schema in a separate file and just include them in the responses.

I tried @lco 's solution, but I couldn’t get it working on my local machine.

Thanks again for your responses Christian.

So with RAML 1.0 (current RC1) and types you can do the following:

collar.raml

#%RAML 1.0 DataType

properties:
  name: string 

dog.raml

#%RAML 1.0 DataType

properties:
  name: string
  collars:
    type: array
    items: !include collar.raml

cat.raml

#%RAML 1.0 DataType

properties:
  name: string
  collars:
    type: array
    items: !include collar.raml

user.raml

#%RAML 1.0 DataType

properties:
  dogs:
    type: array
    items: !include dog.raml
  cats:
    type: array
    items: !include cat.raml

api.raml

#%RAML 1.0
title: My API

types:
  User: !include user.raml

/users:
  get:
    responses:
      200:
        body:
          application/json:
            type: User[]

So how does this work if you want to use a “oneOf” type? For example, I want an animal.raml to be a cat or dog type.

This doesn’t seem to work in the API Workbench 0.8.31?

#%RAML 1.0 DataType
---
type: !include cat.raml | !include dog.raml
properties:
  legs: number

Hi the syntax type: !include anothertype.raml basically inlines the type definition and is not intended to be used for complex type expressions like unions. I would strongly recommend to create identifiers for your types using libraries and use the identifiers instead.

lib.raml

#%RAML 1.0 Library

types:
  cat: !include cat.raml
  dog: !include dog.raml 

animal.raml

#%RAML 1.0 DataType
---
uses: 
  lib: lib.raml

type: lib.cat | lib.dog
properties:
  legs: number
1 Like

Oh I see, that would be an excelent solution indeed. Thanks for the quick reply!

Happy to help!

1 Like

And now I’ve just run into the same issue.
the example JSON does validate against the above JSONSchema… however the use of references (for cleanliness more than anything else) makes the RAML parser blow up.

/0247:
  displayName: 0247 - Request HIT Medical Evidence
  description: |
    The 0247 transaction is to be used to submit a user initiated request for
    medical records from a Health IT partner.
  type:
    hit:
      exampleItem: !include json/0247.json
      schemaItem: !include schema/0247.schema.json
  post:
    body:
      application/json:
        example: !include json/0247.json
        schema: !include schema/0247.schema.json
    responses:
      200:
        body:
          application/json:
            example: !include json/0248-success.json # <-- this is where it's complaining
            schema: !include schema/0248.schema.json

and here’s 0248.schema.json

{
    "$schema": "http://json-schema.org/draft-04/schema#",
    "type": "object",
    "properties": {
        "Folder": {
            "type": "object",
            "properties": {
                "Case": {
                    "type": "object",
                    "properties": {
                        "HealthITUserRequestNotification": {
                            "type": "object",
# using oneOf and referencing subschemas elsewhere in the same document
                            "oneOf": [{                                    
                                "$ref": "#/definitions/success"
                            }, {
                                "$ref": "#/definitions/error"
                            }]
                        },
                        "_adjudicativeLevelCode": {
                            "type": "string",
                            "length": 1
                        },
                        "_caseNumber": {
                            "type": "string",
                            "length": 11
                        },
                        "_folderNumber": {
                            "type": "string",
                            "length": 11
                        }
                    },
# here are my subschemas referenced by the oneOf
                    "definitions": {
                        "success": {
                            "type": "object",
                            "properties": {
                                "Status": {
                                    "type": "object",
                                    "properties": {
                                        "_code": {
                                            "enum": ["C"]
                                        },
                                        "_label": {
                                            "type": "string"
                                        },
                                        "_description": {
                                            "type": "string"
                                        }
                                    },
                                    "required": [
                                        "_code",
                                        "_label",
                                        "_description"
                                    ]
                                },
                                "HealthITDocument": {
                                    "type": "object",
                                    "properties": {
                                        "CaseDocument": {
                                            "type": "object",
                                            "properties": {
                                                "_officeCode": {
                                                    "type": "string",
                                                    "length": 3
                                                },
                                                "_treatmentSourceName": {
                                                    "type": "string",
                                                    "length": 80
                                                },
                                                "_requestId": {
                                                    "type": "string",
                                                    "length": 25
                                                },
                                                "_docCode": {
                                                    "type": "string",
                                                    "length": 4
                                                },
                                                "_docControlId": {
                                                    "type": "string",
                                                    "length": 26
                                                },
                                                "_folderNumber": {
                                                    "type": "string",
                                                    "length": 11
                                                },
                                                "_caseNumber": {
                                                    "type": "string",
                                                    "length": 11
                                                }
                                            },
                                            "required": [
                                                "_officeCode",
                                                "_docCode",
                                                "_docControlId",
                                                "_folderNumber",
                                                "_caseNumber"
                                            ]
                                        },
                                        "_docCode": {
                                            "type": "string",
                                            "length": 4
                                        },
                                        "_caseNumber": {
                                            "type": "string",
                                            "length": 11
                                        },
                                        "_folderNumber": {
                                            "type": "string",
                                            "length": 11
                                        },
                                        "_noRequestDocumentSubType": {
                                            "type": "string",
                                            "length": 1
                                        },
                                        "_responseSubType": {
                                            "type": "string",
                                            "length": 1
                                        }
                                    },
                                    "required": [
                                        "CaseDocument",
                                        "_docCode",
                                        "_caseNumber",
                                        "_folderNumber"
                                    ]
                                },
                                "_caseNumber": {
                                    "type": "string",
                                    "length": 11
                                },
                                "_folderNumber": {
                                    "type": "string",
                                    "length": 11
                                },
                                "_originatingSystemIdentifier": {
                                    "type": "string",
                                    "length": 16
                                }
                            },
                            "required": [
                                "Status",
                                "HealthITDocument",
                                "_caseNumber",
                                "_folderNumber",
                                "_originatingSystemIdentifier"
                            ]
                        },
                        "error": {
                            "type": "object",
                            "properties": {
                                "Status": {
                                    "type": "object",
                                    "properties": {
                                        "_code": {
                                            "enum": ["E"]
                                        },
                                        "_label": {
                                            "type": "string"
                                        },
                                        "_description": {
                                            "type": "string"
                                        }
                                    },
                                    "required": [
                                        "_code",
                                        "_label",
                                        "_description"
                                    ]
                                },
                                "Error": {
                                    "type": "object",
                                    "properties": {
                                        "_code": {
                                            "type": "string",
                                            "length": 2
                                        },
                                        "_label": {
                                            "type": "string",
                                            "length": 32
                                        },
                                        "_description": {
                                            "type": "string",
                                            "length": 254
                                        }
                                    },
                                    "required": [
                                        "_code",
                                        "_label",
                                        "_description"
                                    ]
                                },
                                "HealthITDocument": {
                                    "type": "object",
                                    "properties": {
                                        "CaseDocument": {
                                            "type": "object",
                                            "properties": {
                                                "_officeCode": {
                                                    "type": "string",
                                                    "length": 3
                                                },
                                                "_treatmentSourceName": {
                                                    "type": "string",
                                                    "length": 80
                                                },
                                                "_requestId": {
                                                    "type": "string",
                                                    "length": 25
                                                },
                                                "_docCode": {
                                                    "type": "string",
                                                    "length": 4
                                                },
                                                "_docControlId": {
                                                    "type": "string",
                                                    "length": 26
                                                },
                                                "_folderNumber": {
                                                    "type": "string",
                                                    "length": 11
                                                },
                                                "_caseNumber": {
                                                    "type": "string",
                                                    "length": 11
                                                }
                                            },
                                            "required": [
                                                "_officeCode",
                                                "_docCode",
                                                "_docControlId",
                                                "_folderNumber",
                                                "_caseNumber"
                                            ]
                                        },
                                        "_docCode": {
                                            "type": "string",
                                            "length": 4
                                        },
                                        "_caseNumber": {
                                            "type": "string",
                                            "length": 11
                                        },
                                        "_folderNumber": {
                                            "type": "string",
                                            "length": 11
                                        },
                                        "_noRequestDocumentSubType": {
                                            "type": "string",
                                            "length": 1
                                        },
                                        "_responseSubType": {
                                            "type": "string",
                                            "length": 1
                                        }
                                    },
                                    "required": [
                                        "CaseDocument",
                                        "_docCode",
                                        "_caseNumber",
                                        "_folderNumber"
                                    ]
                                },
                                "_caseNumber": {
                                    "type": "string",
                                    "length": 11
                                },
                                "_folderNumber": {
                                    "type": "string",
                                    "length": 11
                                },
                                "_originatingSystemIdentifier": {
                                    "type": "string",
                                    "length": 16
                                }
                            },
                            "required": [
                                "Status",
                                "Error",
                                "HealthITDocument",
                                "_caseNumber",
                                "_folderNumber",
                                "_originatingSystemIdentifier"
                            ]
                        }
                    },
                    "required": [
                        "HealthITUserRequestNotification",
                        "_caseNumber",
                        "_folderNumber"
                    ]
                },
                "_clientSSN": {
                    "type": "string",
                    "length": 9
                },
                "_folderNumber": {
                    "type": "string",
                    "length": 11
                }
            },
            "required": [
                "Case",
                "_clientSSN",
                "_folderNumber"
            ]
        }
    },
    "required": [
        "Folder"
    ]
}

and here is the example JSON body

{
  "Folder": {
    "Case": {
      "HealthITUserRequestNotification": {
        "Status": {
          "_code": "C",
          "_label": "Complete",
          "_description": ""
        },
        "HealthITDocument": {
          "CaseDocument": {
            "_officeCode": "LH0",
            "_treatmentSourceName": "",
            "_requestId": "",
            "_docCode": "0016",
            "_docControlId": "A1001001A08G22B54441I88333",
            "_folderNumber": "181228905",
            "_caseNumber": "182606496"
          },
          "_docCode": "0016",
          "_caseNumber": "182606496",
          "_folderNumber": "181228905",
          "_noRequestDocumentSubType": "",
          "_responseSubType": ""
        },
        "_caseNumber": "182606496",
        "_folderNumber": "181228905",
        "_originatingSystemIdentifier": ""
      },
      "_adjudicativeLevelCode": "3",
      "_caseNumber": "182606496",
      "_folderNumber": "181228905"
    },
    "_clientSSN": "029327143",
    "_folderNumber": "181228905"
  }
}

ignore the redundant cadeNumber & folderNumber fields, they have nothing to do with this issue. this is just an example i’m using

and the RAML parser error

Example does not conform to schema:Content is not valid according to schema:Reference could not be resolved: <path>/api.raml#/definitions/success <path>/api.raml#/definitions/success, Reference could not be resolved: <path>/api.raml#/definitions/error <path>/api.raml#/definitions/error at line 209 col 13

Can you confirm that the JSON is valid JSON. If yes, let me send that to the guys.

Failing to point nested schema references from dependent schema files in RAML, clearly states that RAML is NOT ENTERPRISE READY. Use it only if you have very limited amount of attributes for web service contract. I don’t know why Mule enforce to use this.

@sivakkannan I am a little baffled by your statement… what is the purpose of it? For all intents and purposes, the original post has been resolved in RAML 1.0. The shortcomings of the JSON Schema issues are handled nicely with RAML 1.0 Types. Be thankful that we at least have RAML as there is no other spec available today that comes close.

We are in need to use multiple JSON schema files and nested JSON types along with RAML. Reason defining types using JSON instead of RAML types is, we need to share the JSON schema files to other applications as the other applications does not support for RAML types. But, RAML does not give complete support for nested JSON schema files. This affects reusable of the JSON schema files. Reusable of schema files is a basic need when you create service contract for an enterprise.

Hi @sivakkannan, thanks for your comment and I understand your concern. RAML does not explicitly call out the support of refs in JSON schema since its not in the scope of a specification like RAML. You will see that with other types of specs as well. If you see that some is not supported; it might be that the tool does not support it. That’s a different story.

So the question is how you currently use RAML and where / when you need to dereference your JSON schema?

I see a lot of confusion about json-schema references. The best solution is to take the time to read the json-schema specification. The schema references in the given example have no resolution scope, so it can’t be correct. To fix this, you should add one or more ‘id’ fields into your schema, see section 7.2 on the linked page to the specs, and then make sure that “#/definitions/success” resolves correctly.

2 Likes

Hi, Is this worked, I am facing same issue, My service is expecting two different message structure A or B. while i declare type with union, it throws Exception, Can you please share, if you found solution?