views:

220

answers:

3

I am using Sphinx to document a webservice that will be deployed in different servers. The documentation is full of URL examples for the user to click and they should just work. My problem is that the host, port and deployment root will vary and the documentation will have to be re-generated for every deployment.

I tried defining substitutions like this:

|base_url|/path
.. |base_url| replace:: http://localhost:8080

But the generated HTML is not what I want (doesn't include "/path" in the generated link):

<a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt;/path

Does anybody know how to work around this?

A: 

I can't help with your question, but you should know that what you are describing (an "API ... full of URL examples") is most definitely not REST. It's simply RPC. A RESTful API can only have one URI in it, the entry point. The other URIs are discovered via hypertext, but the client still can't know anything about how to assemble URIs or what the parts of the URI mean.

See this article by Roy Fielding, the man that specified REST in his dissertation.

Wahnfrieden
Here, reST stands for reStructuredText, the markup used by the Sphinx documentation generator. Moreover, although your statement might be correct about a RESTful API's design, it's irrelevant both to my question and to software documentation in general, which should say more than "here's the entry point, now find your way around".
martin
My mistake, the [rest] tag is generally used for REST. Anyway, a REST API only gives an entry point, but the documentation focuses on describing the media-types, it doesn't say "now find your way around" - it also doesn't give any other URIs, since that is merely RPC and not REST due to all the coupling.
Wahnfrieden
It looks like you could benefit from REST anyway since your API appears to have resource to URI coupling all over the place.
Wahnfrieden
Actually, "here's the entry point, now find your way around" is exactly what the documentation of a REST interface should say. However, it should have a whole lot more to say about the media types that are being passed back and forth.
Darrel Miller
Ok, so I should call my company's marketing department and let them know the documentation's quickstart section won't have clickable examples they can show to potential customers. I'm sure they'll understand all about HATEOS and customers will see it as something good. Irony apart, thank you for the comments.
martin
You can separate the clickable examples from your actual API. You're right though, RPC is easier to implement - it's easier to hard code URIs. Just know that you're building a more brittle API this way though.
Wahnfrieden
+1  A: 

You can write a Sphinx extension that creates a role like

:apilink:`path`

and generates the link from that. I never did this, so I can't help more than giving this pointer, sorry. You should try to look at how the various roles are implemented. Many are very similar to what you need, I think.

tsg
@thoriann: thanks for the pointer and check my answer to see the complete implementation.
martin
@martin: cool, we have a nice sample now.
tsg
+1  A: 

Ok, here's how I did it. First, apilinks.py (the Sphinx extension):

from docutils import nodes, utils

def setup(app):
    def api_link_role(role, rawtext, text, lineno, inliner, options={},
                      content=[]):
        ref = app.config.apilinks_base + text
        node = nodes.reference(rawtext, utils.unescape(ref), refuri=ref,
                               **options)
        return [node], []
    app.add_config_value('apilinks_base', 'http://localhost/', False)
    app.add_role('apilink', api_link_role)

Now, in conf.py, add 'apilinks' to the extensions list and set an appropriate value for 'apilinks_base' (otherwise, it will default to 'http://localhost/'). My file looks like this:

extensions = ['sphinx.ext.autodoc', 'apilinks']
# lots of other stuff
apilinks_base = 'http://host:88/base/'

Usage:

:apilink:`path`

Output:

<a href="http://host:88/base/path"&gt;http://host:88/base/path&lt;/a&gt;
martin