Short forum post on REST API

Adam D. Ruppe destructionator at gmail.com
Sun Apr 17 18:23:19 PDT 2011


I just implemented the concept described in that post in my web.d,
and earlier in the week, implemented automatic Javascript bindings
generation.

Here's a live demo:
http://arsdnet.net/apidemo.html

This is the server side implementation:
http://arsdnet.net/apidemo.d

Do not adjust your text editor - it's actually a mere 14 lines long.
You just write D functions.

Most the work is done in the helper modules
http://arsdnet.net/dcode/web.d

Depends on:
http://arsdnet.net/dcode/cgi.d
http://arsdnet.net/dcode/dom.d


(btw the struct members are all static due to a decision decision
I think I've changed my mind on, but haven't changed the code
yet. I think a class would be better though - can slash a lot of
the __traits(compiles) if I just use virtual functions.)

There's other features available in web.d not used here, like
automatic and hookable html form generation, output format
post processing, initialization functions, etc. You can also
accept a Cgi and ReflectionInfo object in the initializer if you
want to do more traditional web things or see what you have
in that struct.

(Originally, the idea was to autogenerate websites, so there's
a lot of code for datatype -> html, html templates, html forms,
etc. All that still works, of course:

http://arsdnet.net/cgi-bin/apidemo/foo

But I've been playing with program access recently, since I actually
prefer the traditional method of making the pages on the whole.
Since they can exist side by side in the same executable, it's
pretty awesome still.)


Anyway, FancyMain just calls three other functions, wrapped up
in a main:

    auto reflection = prepareReflection!(T)(cgi);
    run(cgi, reflection);

ReflectionInfo stores piles of info about your passed object.
All functions (and still to do: enums and structs) are checked
out. Their return type, name, and arguments - both names and types -
are stored. A template also generates a wrapper function that
makes the call from cgi info.

run() takes the cgi pathinfo and get/post data to call the wrapper.
It also catches exceptions to either handle automatically in the
case of html or wrap up for the other system in case of json.


run() also does a little piece of magic. If the path requested
is functions.js... it uses the reflection info to generate a
javascript object that mimics the D struct, along with some
other info:

http://arsdnet.net/cgi-bin/apidemo/functions.js

(See the bottom for the D function wrappers. There's quite a bit
of javascript there that I just wrote in web.d straight up.)

Note how the JS object name matches the D struct name too, and
the argument names match up.

also, if it's compiled in debug mode, the Javascript is made in
debug mode, giving better error messages, etc.


I might write an automatic PHP too, but php can actually call
the api functions without needing a code generator - it has
a feature similar to D's opDispatch. Using web.d's positional
argument support, it can just forward to the server without knowing
anything. (Some vendor's implementations of javascript have this
too, but you can't depend on it, so the codegen is better.)


There's a bunch of helper callbacks there too, to make using
the function return value easier in the async environment.

You can see that in apidemo.html - in the end, it does appendTo(),
which takes the returned string, treats it as html, and appends it
to the given element.

I'm planning on adding better typechecking there - if you return
a Html() or Element in D, it is html. If it's a string, it should
do append text instead. The static types are there - let's use them.




Anyway, enough blabbing. The interesting thing here is what all D
could do to make this work. When I get around to writing my
article, I'll discuss what it can do again, but also go into
how much of a pain it is to do this kind of thing in PHP and other
popular languages for both calling and implementing the web api.

D's built in documentation naturally helps here too. All the stuff
is generated from the same place, so it's easy to doc too.

I saw a php thing that tries to do the same, for example, but
you had to do things just write, had to manually register the
functions, and couldn't just write javascript normally... and, of
course, it's php. Ugh.


More information about the Digitalmars-d-announce mailing list