Modularization


#1

Hi everyone!
I really like RAML v1.0, especially it’s features for modularization.

I would like to use RAML in our company for documentation of api. But the problem I have, is that the api spec file is becoming quite huge. And I’m not even finished.

I’ve checked several options about how to make the main spec file smaller. But I’m missing a feature that would allow me to separate spec into several smaller modules and import / include resource definitions in the main spec file.

I noticed that one could simply, comment out the top of the raml spec and include this file into resource, but that’s just hack I would like to avoid.

Is there way (supported by raml) to separate resource definitions into several files?
For example

#%RAML v1.0
title: My API
version: 0.1
/api/{version}:
    /places: !include places/places-api.raml
    /about: !include about/about-api.raml

and in places/places-api.raml would be something like:

#%RAML v1.0    Resources
uses: 
  places-lib: !include places/places-lib.raml

/:
  type: places-lib.collection
  get:
    description: returns list of places
  post:
    description: creates new place
  /{place_id}:
      type: places-lib.place-res-type

Because in big projects, the main spec would be huge. Even if I would extract all the docs, types, and other data into libraries.

Thanks for answer!

Regards,
Miro


#2

Is this what you are after?
http://docs.raml.org/specs/1.0/#raml-10-spec-libraries
Extracting related bits into a library?


#3

I know about libraries. But how about resources and nested resources? That’s what I’m after.


#4

You can split that into two files:

resourceDescription.raml

get:
  description: this is a get resource

api.raml

#%RAML 1.0

title: include resource
version: v3

/resource: !include resource1.raml

That is valid RAML syntax (in 1.0 as in 0.8 already) and should be supported by all parser. Nevertheless, as you will realise using the API Workbench, there is no real validation on the resourceDescription.raml as it is not a real fragment. Currently, RAML does not support resource fragments yet, but interesting enough to think about that tbh :wink:


#5

Hmm… our hope has always been that you could just look at a RAML file and see the structure of the API. The number of resources and subresources might be substantial, but it would be monstrous – and there would be sufficient patterns so you could lean a lot on resource types, traits, schemas (now types), etc. to put that main API file on a diet but still have it include the entire resource tree.

And if you find that the API is so huge that even that’s too big, maybe it’s time to break up the API itself into multiple APIs that are then versioned (or otherwise evolved) separately?

Anyway, that’s the reason you don’t see easy ways to break up the resource tree.

Do people feel like they really do need to break up the resource tree and bring it back together into a single API description?


#6

I would say that in programming, people make a lot of effort to keep their files as small as possible (single responsibility principle) which increases readability as well. And RAML si supposed to be in human readable form. YAML helps this purpose a lot. Makes the files clean a readable as I write spec. But the fact that it is supposed to be in one uber file… I don’t know. I think that’s step in other direction.

I understand that RAML forces you to “behave” and to design API in consistent way. But let’s face it. People will always do all kinds of ugly hacking stuff against rules, just to align with their actual state. To fit their needs. ( Just see the post above :smiley: ) And even smaller APIs can produce files big enough to become difficult to read.

I find the option to separate resource tree into smaller chunks reasonable.

Regards,
Miro.


#7

If we speak here about a more micro-service architecture then you would rather have a small set of capabilities per service that is described internally by a RAML. Therefore, you will not have a “big” resource tree at all. If you still want to publish an “Uber” RAML for people to read and understand the documentation for your API, a tool could consolidate all the small RAML into a bigger one. The result are smaller consumable RAML’s internally and externally you might have something bigger.


#8

In my initial look at RAML (0.8), how to effectively break up a specification into readable chunks was a huge deal. From a developer’s perspective, the textual specification is primary; any HTML or interactive tools that improve presentation are really just nice to have (possibly essential for other consumers).

The RAML document describing an API is something that needs to work well with text editors and version control systems. YAML provides a number of tools to make that work out, which helps a lot. Some way to deal with named nodes across more than one file at a time (which I understand YAML doesn’t provide by itself) would be great to have.

That said, I think the addition of libraries is a huge improvement; I look forward to spending some time experimenting more before too long. Being able to factor the resource hierarchy in similar ways would be great, though generous application of !include might be sufficient.

-Fred


#9

AFAIC so far, I’ve been able to keep the resource definition of my RAML (0.8) files tiny compared to the traits and resourceType definitions.

By using a naming convention for my schema files (like new_XXX, XXX and XXX_set), I’m able to reuse common definitions of entity and collection resources. With the aid of custom parameters, I’m even able to inject bits of varying documentation in common traits/resource types.

So I haven’t yet felt compelled to break down a RAML spec into smaller chunks.

(and +1 for @christian_vogel’s proposal for documenting an aggregating facade in front of micro-services)


#10

Can you elaborate more about your approach?
Thanks!

Regards,
Miro


#11

I can’t share any of the specifics but here is something that should illustrate what I’m saying (it doesn’t show custom parameters but you can figure it out from the spec):

      post:
        description: |
          Create a new <<resourcePathName | !singularize>>.
        body:
          schema: new-<<resourcePathName | !singularize>>
        responses:
          201:
            description: |
              New <<resourcePathName | !singularize>> successfully created.
            body:
              schema: created

This can of definition can be shared across any resource that allows POSTing new entities, leaving the actual definition of the resource to be merely just a path, from which doc and schema are inferred.


#12

All right. I see what you mean… thanks for example.

Yes, this is definitely way to go. Create nice and consistent API with nicely defined resources that are reusing types and resources. Unfortunately, our API is monolith with a lot of resources. I won’t go into details, but there’s small probability that it will be refactored anytime soon.

Anyway, I still don’t get why in RAML, you can put almost everything (docs, types, resourcetypes …) into separate files and import it, but you can’t do that with resources. I would not hurt readability for human, it would be equally machine readable.

Thanks for your responses.

Regards,
Miro


#13

So there’s absolutely no repeating pattern in your API, like POST /**/things for creating things, which you could abstract out in a common resource? If that’s the case, your main issue is not that the API is monolithic but that it lacks homogeneity.

At the end of the day, you can always merge multiple RAML specs into one in the resource that you use to expose the spec over HTTP. That’s a workaround, for sure, but could get you going.


#14

I’m sure there are some patterns that could be abstracted, but not in a way, that could significantly reduce complexity. The design is based on verbs at the end of the resource path. So for example

[POST] http://example.com/api/thing/get
[POST] http://example.com/api/thing/set
[GET]  http://example.com/api/otherthing/get
[GET]  http://example.com/api/about
...

Sometime verb get is GET method, sometime POST method. Depending on underlying logic.

Well, maybe merging tool would do the trick. I’ll think about that.

Regards,
Miro


#15

Oh boy, I see :crying_cat_face: