api-blueprint icon indicating copy to clipboard operation
api-blueprint copied to clipboard

External assets

Open zdne opened this issue 11 years ago • 43 comments

Add the possibility to use Markdown links wherever an asset is expected (e.g. a payload body or schema).

zdne avatar Aug 14 '13 15:08 zdne

I'm interested in this capability, and would ideally like it added sooner rather than later.

Our particular use case is for documenting APIs where the request and response bodies are binary structures produced by Apache Avro. For these requests/responses, we'd like to be able to have the "Schema" be a link to either the Avro schema definition file, or a generated HTML document describing said Avro schema. It might look something like this:

## POST /myresource
Creates a new myresource.

+ Request (application/vnd.example.myresource+avro)
    + Schema:
        [MyResource.avsc](http://docs.example.com/avro/myresource.avsc)
+ Response 201 (application/vnd.example.myresource+avro)
    + Schema:
        [MyResource.avsc](http://docs.example.com/avro/myresource.avsc)

davidmc24 avatar Oct 21 '13 13:10 davidmc24

:+1:

matthurne avatar Oct 21 '13 13:10 matthurne

@mhurne @davidmc24 Have you thought about representation of this feature in the AST? Would you like to see hyperlink in the AST or blueprint parser should be capable to fetch target url and embed its content to the AST?

netmilk avatar Oct 21 '13 14:10 netmilk

My expectation is that the AST would contain the hyperlink, not the content of said hyperlink. It might be useful for the AST to "know" that it's a hyperlink as opposed to direct content, so that links can be produced in HTML documentation, for example.

In cases where you've chosen to externalize the schema from the API, it's likely because either the schema is too large to make sense to inline in the API documentation, the schema is used by multiple APIs and has its own authoritative documentation, or the schema is a format which isn't appropriate for embedding. While those examples are schema-specific, I expect similar reasons apply to other payload types.

davidmc24 avatar Oct 21 '13 14:10 davidmc24

@davidmc24

I do like it. If it would be just the hyperlink it would be probably fairly easy to implement in the parser.

The bigger challenge however comes with the needed change to the AST and its media-types

Probably to something like this:

{
  "name": "<name>",
  "description": "<description>",
  "headers": {
    "<header>": {
      "value": "<header value>"
    }
  },
  "body": {
    "content": "<body>",
    "href": "<uri>"
  },
  "schema": {
    "content": "<schema>",
    "href": "<uri>"
  }
}

zdne avatar Oct 21 '13 23:10 zdne

Yep, that's exactly the AST I was considering.

davidmc24 avatar Oct 22 '13 01:10 davidmc24

Additionally add additional syntax for external assets to be embedded (not just referenced-linked) by the Drafter apiaryio/snowcrash#57

:[file.json](path/to/file.json)

or

=[file.json](path/to/file.json)

Alternatively using the Mardkown implicit link name:

:[path/to/file.json]()

or

=[path/to/file.json]()

zdne avatar Jan 31 '14 13:01 zdne

Hello, Here's another use case for having external links: I would like to link the definitions/descriptions of attributes in the API to their respective definition in our master glossary used by all documentation. I think this opens the door to keeping all documentation up to date and in sync. Otherwise, I will have to update the API doc. separately, which leave room for definition not to be in sync.

angie2014 avatar May 28 '14 21:05 angie2014

Markdown is an uncomfortably loosely coupled family of mostly compatible extensions, so I'm not sure, but the only case I can think of where a link-like syntax actually means "embed not reference" is the image syntax (using a ! sigil): ![Alt text](/path/to/image.jpg "Optional Title"), which is part of Gruber's original specification. Z's suggestions above all violate this structure (file name in the wrong place). Wouldn't it be better to conform, just use a new sigil on the otherwise existing syntax?

jrep avatar May 30 '14 00:05 jrep

Good point @jrep !

Wouldn't it be better to conform, just use a new sigil on the otherwise existing syntax?

That is my goal.

According to Gruber's following should achieve the same goal:

[label](path/to/image.png)

[alt text][label2]
[label2]: path/to/image.png

[label3][]
[label3]: path/to/image.png

Where label, alt text and label3, in theory, does not have be present but then the elements are not visible after rendering.

I guess my point with

=[path/to/file.json]()

Should be

=[path/to/file.json][]

where the lablel is the actual URL, so proper full definition (so the markdown renders correctly) would be:

=[path/to/file.json][]
[path/to/file.json]: path/to/file.json

Now it would be obviously tedious to write:

[path/to/file.json]: path/to/file.json

Question is – should this (defining the label) be implicitly assumed by the parser? Or should we just ask blueprint writers to use the [alt text](URL) syntax?

zdne avatar Jun 02 '14 12:06 zdne

Couldn't we just use the alt/label part for actually describing what the asset is so the link is human-readable? Writing something like =[file.json](path/to/file.json) seems to be needlessly tedious, but =[Schema for notes](path/to/file.json) seems fine to me - encouraging blueprint writers to make blueprints less cryptic for readers. Actually, assets can be missing or it can be sometimes non-obvious what precisely is linked. alt attributes on images were invented exactly for this case I think.

If someone wants to bypass this and ignore the best practise of describing assets this way, she can always put a dummy text there (such as already mentioned file.json).

I used the = syntax just as an example, the same would apply for !.

honzajavorek avatar Jun 02 '14 13:06 honzajavorek

I feel we should just support markdown with the extra sigil regardless of the syntax used – be it direct link, explicit or implicit label.

If we agree on this only two questions remain:

  1. What sigil to use

  2. Whet style we will use in examples / tutorial

    Note that in my opinion label such as Schema for notes in

    =[Schema for notes](path/to/file.json)
    

is dup as well because most often than not you will use it in a schema section of a Notes resources...

e.g.:

# Notes [/notes]
## GET 
+ Response 200
    + Body
         ...
    + Schema
        =[Schema for Notes](path/to/file.json)

Thoughts?

zdne avatar Jun 02 '14 13:06 zdne

I'm all for supporting all of the standard variants, but this:

=[path/to/file.json][] [path/to/file.json]: path/to/file.json

... is not how I understand Gruber's definition. Rather, I agree with honzajavorek: the stuff in the first [] is in some way a human-readable tag, not a redundant and tiresome duplicate of the link text. So, while it seems to be syntactically valid to include a path there, it's (a) weird, and (b) unhelpful.

If the intent is "any Gruber-valid link form, with a new sigil," then I like that semantic but suggest a less surprising example (of the sort honzajavorek and I have suggested).

jrep avatar Jun 03 '14 00:06 jrep

@jrep @honzajavorek I agree.

zdne avatar Jun 03 '14 09:06 zdne

I think its difficult to compare inclusion of assets to existing pattenrs for either images or links. Isn't it actually combination of those two together?

The problem with image syntax analogy is that in the world of images, alt texts are important, they're usually not duplicate in given context and nobody wants to actually write ![img.jpg](/path/to/img.jpg) - only content managament systems and a "lazy" people do this. Requiring the alt text is teaching a good habit.

But assets don't necessarily need alt texts, that's true. As @zdne mentioned, they'll be always used in such context that it'll be totally clear what's going on here. I agree with that. The problem is, the only analogy to that I can think of are links without labels:

[Google](http://www.google.com) versus...

  • <http://www.google.com> (Gruber)
  • http://www.google.com (today's Markdown reality, I guess)

If we need something hybrid, let's call it "autolink syntax for images", and we want to adhere to Gruber as much as we can, we want something like following:

  • =[Alternative text about assets](/dev/null) ← everyone is familiar with this, this should be in examples (it's like images, makes sense! popping in peoples' heads)
  • =[Alternative text about assets][id] ← for including the same asset onto multiple places
  • =</dev/null> or <=/dev/null> ← autolink syntax (...how would autolink syntax look like for images?), noone knows the Gruber's version of autolink (because links are converted automagically everywhere, even without <s and >s), but in case they really really don't need the alt text and they're annoyed by it, people can learn to use this

Again, using = just as an example. In my opinion those would be the most readable and/or at least Gruber-ish solutions. For example, I consider

[label3][]
[label3]: path/to/image.png

to be rather cryptic for me as a reader and not following the reality of existing Markdown usage. I didn't even know about such possibility, I thought pairing has to be done by the second couple of brackets. (However, I am fully aware this last paragraph is very subjective).

honzajavorek avatar Jun 03 '14 09:06 honzajavorek

@zdne : as to the sigil: I don't much care, but the = we've all been using seems fine.

@zdne: I acknowledge that the most likely text =[IN HERE](schema.json) is redundant for any Blueprint usage I can think of. Just brainstorming, here, but what if we leverage that redundancy to simplify the grammar? That is, replace

# Notes [/notes]
## GET 
+ Response 200
    + Body
         ...
    + Schema
        =[Schema for Notes](path/to/file.json)

with

# Notes [/notes]
## GET 
+ Response 200
    + Body
         ...
    + =[Schema for Notes](path/to/file.json)

@honzajavorek: are you actually suggesting that Blueprint allow/mandate the string "/dev/null" in those places? Or was that just a place-holder?

I never use "reference links," either, but I wouldn't object to Blueprint carrying them forward.

jrep avatar Jun 03 '14 21:06 jrep

@jrep I used /dev/null just as a placeholder :)

Using links directly in section headers does not look bad at all, actually! Of course, it's just a first sight, I didn't really thought about what are the cons of such thing, but... at first sight it seems appealing to me.

honzajavorek avatar Jun 03 '14 21:06 honzajavorek

@jrep I like it.

Taking it even further

# Notes [/notes]
## GET 
+ Response 200
    + =[Body](path/to/body.json)
    + =[Schema](path/to/schema.json)

zdne avatar Jun 04 '14 08:06 zdne

The ability to split the file into separate files and then import them in would be very useful for long verbose API's.

In the interm I manage my blueprint project with grunt. I use grunt-import and my index.source.apib file is made up of mostly @import "/include/section.apib";

Then all I do is run grunt watch and as soon as I save any file grunt will recompile my index.source.apib file into 'index.apib' - which is also being watched by aglio, refreshing my browser to show me the render in real time.

It takes 5 minutes to setup, but it makes life so much nicer! :+1:

alexborisov avatar Aug 29 '14 22:08 alexborisov

@alexborisov that is pretty neat! Thanks for the sharing. As I have said (elsewhere) – we have started the works on a parser harness tool that should take eventually care of this.

Also, for what its worth, here is a script that composes multiple blueprints into one and publish it using the Apiary client gem https://gist.github.com/danvine/11087404

zdne avatar Sep 01 '14 16:09 zdne

@alexborisov, that's a really smart work-around! Do you (or anyone watching this issue) happen to know if there's a Gulp counterpart to grunt-import? The gulp ones I found all target JS and html docs.

skawaguchi avatar Nov 24 '14 02:11 skawaguchi

@skawaguchi You can use gulp-file-include and create a gulp task to watch your json and build the api. The only downside is that you have to have an api.source.md to generate your api.md, but IMO it's a small price to pay.

ghost avatar Feb 24 '15 20:02 ghost

Also for what it's worth checkout @jamesramsay 's Hercule – https://github.com/jamesramsay/hercule

zdne avatar Feb 25 '15 13:02 zdne

Thanks @zdne for the mention. I had similar challenges when writing API documentation and we have been using Hercule internally for the last 3 months.

Hercule uses a simple {{filename.md}} pattern for inclusion.

We have a number of API contexts for different types of API consumers that have nearly identical resources and we were keen to reduce duplication between the different documents. Thus, we have also extended this syntax to also support:

{{entity.json links:role-links.json}}

{
  "id": 123,
  "name": "example",
  "links": {
    {{links}}
  }
}

The {{links}} placeholder can then have the target file specified by one of it's parent files. We've found this helpful for large schemas which are nearly the same.

jamesramsay avatar Feb 25 '15 23:02 jamesramsay

@jamesramsay

I am just wondering why to use {{link}} syntax instead of Markdown's very own [<placeholder>](link) ? as discussed above. For example:

=[gist](gist.apib)

or

:[gist](gist.apib)

it would work similarly, it would render reasonably as markdown, so you would be able to navigate through links, and you could use much richer syntax such as [placeholder][] with `[placeholder] link options...

zdne avatar Feb 27 '15 13:02 zdne

@zdne this is a really great suggestion! Too bad I didn't see this thread 6 months ago.

The {{link}} syntax was based on MultiMarkdown 4's transclusion syntax. It did the trick and I wasn't inventing a new syntax.

At the time I also looked at Marked app (<<[link]) and a couple of other Markdown compilers.

With the advantage of being able to click through the links when viewing the source documentation in Github and improved consistency with the feel of Markdown I've updated hercule to use :[gist](gist.apib). If anyone would like to take it for a spin, it's on NPM.

jamesramsay avatar Mar 04 '15 07:03 jamesramsay

Hey guys, I am using API Blueprint with aglio for our internal project, and since API Blueprint doesn't support file including currently, aglio implements one with the syntax <!-- include(filename.json) -->, thanks to this feature we can split request/resposne JSON data from API document clearly, but when we organizing the seperated JSON data files, we find it still lack of a proper way to reuse the same part, for example, we have a user_model.json:

{
    "username": "alice",
    "comments": [
        {
            "id": 1,
            "content": "hello"
        }
    ]
}

and a comment_model.json:

{
    "id": 1,
    "content": "hello"
}

the comment part in user_model.json is and should always be the same as comment_model.json, if there is a mechanism that allows JSON file to include each other, it would be very easy to maintain their consistency, so that in case the commend model is changed, we don't need to change it everywhere.

I consider it for some time and try making a syntax to support JSON file including, here is my effort, a include sytanx with a Python implementation: https://github.com/reorx/json_include

The syntax would be like, in previous case:

{
    "username": "alice",
    "comments": [
        {
            "...": "include(commend_model.json)"
        }
    ]
}

using { "...": "include(commend_model.json)"} to represent a including to commend_model.json file.

Its not a special case for API Blueprint, but something rather general, to try to think of JSON itself with the include capability, which I think may also be used in API Blueprint.

Please take a look and give some suggestions, currently this json-include is working fine in some of my projects, any thoughts about it would be very appreciated, since I can't decide whether it is good and meaningful or not alone by myself :)

reorx avatar Apr 28 '15 18:04 reorx

Hey @reorx ! Thanks for sharing the idea. Recently we have launched (beta) of MSON – a syntax for describing data (not only) in API Blueprint. The idea is, you describe your data once and then ask for serialization into different formats.

Using your examples it works like this:

# Data Structures

## User 
- username: alice
- comments (array[Comment])

## Comment
- id: 1
- content: hello

and then you can ask to render it as JSON:

# Resource [/r]
## Retrieve [GET]
+ Response (application/json)
    + Attributes (User)

What do you think? Will this help you?

zdne avatar Apr 28 '15 18:04 zdne

Is this feature anywhere in the pipeline? It would be very nice for us. We use Blueprint to describe methods, but have our JSON schema hosted separately. We have to include the schema as links in the method descriptions, since it isn't supported under the request/response element currently. Actually the most ideal thing would be if we could "include" the JSON schema webpage using a link under the request/response element, but it would have to be lazily loaded, to avoid doing hundreds of includes when the documentation page is loaded.

jonathancrosmer avatar Aug 20 '15 14:08 jonathancrosmer

I think that the fact you can't include external references for requests/response body examples and definition schema files is one of the very big downsides that Blueprint has in respect to other API definition languages.

mariusor avatar Nov 17 '15 16:11 mariusor