Include external resources(RAML file) in one uber file


#1

Hi ,
I desperately need help on this .

Let’s say we have one RAML file (api.raml) which looks like as shown below

#%RAML 0.8
#api.raml

!include image.raml
!include movie.raml
!include foryou.raml
!include similar.raml

I want to link a one uber file (api.raml) to various resources defined in the individual files . How do I do that ?
Also I want to define global properties in api.raml file such as base URI and security schemes which should apply for all individual resources defined in individual files.

Thanks


#2

Hi @Hu_Tu,
I’ll try to address your doubt in both, theoretical and practical ways.

The idea of “!include” is to encourage the reuse of code as much as possible, but in a structured way.
Having said that, a couple of considerations:
A Top Level RAML file cannot have more than one root element, which makes several includes on the top level not to be supported. More than that, it could result in a not recommended way of structuring your API.

The idea of the uber raml file, is to bring you the possibility of reading your API, so, the structure should be there and the reusable code should be in the includes (this results in the complete opposite approach from the one you are thinking of).

The proposal is to extract the reusable functionalities into different files, and include these in the main raml file.

For example, consider the traits “paged” and "secured"
You could write it like this:

#%RAML 0.8
title: My API
version: v1
#baseUri: http://localhost
baseUri: http://mocksvc.mulesoft.com/mocks/f30492c5-8c8e-47d5-b310-d44dcfafa05a

traits:
  - paged:
      queryParameters: 
        page: 
          description: page number
          type: number        
  - secured:
      queryParameters:
        access_token: 
          description: The token to get authorized
          type: string          

/resource:
  description: A generic resource
  post:
    is: [ secured ] 
    responses:
      200:
        body:
          application/json:
            example: |
              { "status": "ok" }
  get:
    is: [secured, paged]
    responses:
      200:
        body:
          application/json:
            example: | 
              [ {"id": 1, "description":"resource instance 1"}, 
              {"id": 1, "description":"resource instance 1"}]

then, you could extract each trait into a different file:
paged.raml

  queryParameters: 
    page: 
      description: page number
      type: number

secured.raml

queryParameters:
        access_token: 
          description: The token to get authorized
          type: string 

and your api.raml (uber file)

#%RAML 0.8
title: My API
version: v1
#baseUri: http://localhost
baseUri: http://mocksvc.mulesoft.com/mocks/f30492c5-8c8e-47d5-b310-d44dcfafa05a

traits:
  - paged: !include paged.raml     
  - secured: !include secured.raml

/resource:
  description: A generic resource
  post:
    is: [ secured ] 
    responses:
      200:
        body:
          application/json:
            example: |
              { "status": "ok" }
  get:
    is: [secured, paged]
    responses:
      200:
        body:
          application/json:
            example: | 
              [ {"id": 1, "description":"resource instance 1"}, 
              {"id": 1, "description":"resource instance 1"}]

Even more, you could extract the traits list into a traits.raml file

- paged: !include paged.raml
- secured: !include secured.raml

and your api.raml (uber file) could be:

#%RAML 0.8
title: My API
version: v1
#baseUri: http://localhost
baseUri: http://mocksvc.mulesoft.com/mocks/f30492c5-8c8e-47d5-b310-d44dcfafa05a

traits: !include traits.raml

/resource:
  description: A generic resource
  post:
    is: [ secured ] 
    responses:
      200:
        body:
          application/json:
            example: |
              { "status": "ok" }
  get:
    is: [secured, paged]
    responses:
      200:
        body:
          application/json:
            example: | 
              [ {"id": 1, "description":"resource instance 1"}, 
              {"id": 1, "description":"resource instance 1"}]

Additionally, you could describe the entire content of /resource in a separated file and have:

/resource: !include resource.raml

This will surely make your uber file shorter, but it won’t help to the purpose of describing the API for a human that is tryinh to readi that uber file. So basically, I wouldn’t recommend that approach.

I hope you find this helpful.

Cheers!

TW: @nohorbee


#3

hi @nohorbee,
Thank you so much for such a detailed explanation.
I know you are not recommending the approach of

/resource: !include resourcue.raml

But we need that kind of linking in our projects. So if I do this , will it work ?

/movie : !include movie.raml
/image : !include image.raml

#4

Hi @Hu_Tu

You could and it’s supported. (Again: not recommended).

This is the code:

#%RAML 0.8
title: My API
version: v1
#baseUri: http://localhost
baseUri: http://mocksvc.mulesoft.com/mocks/f30492c5-8c8e-47d5-b310-d44dcfafa05a

traits: !include traits.raml

/resource: !include resource.raml
/otherresource: !include otherresource.raml 

resource.raml

description: A generic resource inside
post:
responses:
200:
body:
application/json:
example: |
{ “status”: “ok” }
get:
responses:
200:
body:
application/json:
example: |
[ {“id”: 1, “description”:“resource instance 1”},
{“id”: 1, “description”:“resource instance 1”}]

otherresource.raml

description: Another resource
post:
responses:
200:
body:
application/json:
example: |
{ “status”: “ok” }
get:
responses:
200:
body:
application/json:
example: |
[ {“id”: 1, “description”:“resource instance 1”},
{“id”: 1, “description”:“resource instance 1”}]

Let me ask, btw, what tools are you using to try?
It’s very quick for me to try this code out in the API Designer. Please, visit: http://api-portal.anypoint.mulesoft.com/ and “Start Designing”.

The tools offer autocompletion, syntax correct, etc.

Cheers!

@nohorbee


#5

Yes , I am using the same tool for doing this . But being a newbie to this , I was struggling with tool.

Now with the excellent explanation from you , I guess I can get this going…

Thank you so much and I may bother you with some more questions going forward.


#6

the api designer seems have no code completion in the included file (e.g. resource.raml as above), since it’s not a complete raml file at all…


#7

I posted a feature request (or I think I did) regarding this very issue. In the documentation (https://github.com/raml-org/raml-spec/blob/master/raml-0.8.md#includes) there is mention of a external: !include… which seems like it would do the trick of including multiple raml files into one uber one. As I pointed out in my new issue for raml spec, there needs to be a way to allow multiple smaller apis (each with their own set of resources, includes, schemas, etc) to be combined into one uber RAML file and parsed as if it were one big file. In my company, we have several API Sub projects, but ultimately we have one main API that is a combination of several other smaller APIs. When we build documentation, or an SDK, we want it all in one, not several smaller pieces that a consumer then has to navigate through to figure out which they need.

Is there any progress in the 1.0 spec towards allowing this in some way? The above example of having a “snippet” of a resource in a separate file doesn’t quite cover it. I may very well like to have a smaller API for testing, internal small team consumption etc where the whole API is not needed, but when we publish the API, SDK, etc we want it all combined to be consistent across the smaller APIs that make up the whole.


#8

The example you’ve used shows a problem that would be solved easily if support for composable RAMLs would be done in the way it was originally suggested. That is, you show a commented out baseUri, which could be inferred as one trying to deal with deployments on different hosts. In large environments, there are different teams managing implementation, environments, developing, testing, specification, etc. It means deployment/network endpoints/infrastructure are different than the spec people. Because the RAML without a baseUri (“the spec”), may be the product of a different team, it is then versioned independently. The implementer, testing team, etc. could then build a new RAML on top, containing only the baseUri specific to that implementation. Very much like WSDL imports, interface definition may be separate from protocol bindings and network endpoints. As far as I am concerned, this is a big miss in the current RAML spec.