Home > todoservice

todoservice

Todoservice is a project mainly written in C, based on the AGPL-3.0 license.

A not-quite-RESTful todo API implemented as C CGI with Redis backend

todoservice

A toy implementation of a not-quite-RESTful "todo" service implemented as a CGI program with Redis as a data store.

Why? I wanted a simple service like this that could be used over a network, and get all the things that come for nearly-free with HTTP (authentication, encryption, proxy support, etc.)

Also, freedom and data ownership! The Affero licensing means you are free to change the source as you like (with a share-alike condition). And when you run your own data servers instead of using hosted solutions, you regain privacy and the power that is lost when we let others take care of our data.

This is a very simple API for a to-do list. A "todo" is simply an ASCII string (with no supporting metadata like completion info, etc.) The API allows for GET/PUT/POST/DELETE for todos.

Some sample apache configurations are included in example/apache_vhosts.

A serviceable shell client lives in example/client.

Although the service isn't quite RESTful, it could be made so without too much work.

A true RESTful implementation would take the hypermedia constraint a little more seriously. While this API exposes all GETtable resources as links, it should also have a POST form at the /todos URL, and PUT/DELETE forms at the /todo/{ID} URLs. This would make the service self-describing, and clients could discover the possible interactions, rather than having them hard-coded and tightly-coupled.

Redis is used as the data store. By default, the CGI script will expect Redis to be listening at localhost:6379, and use database 0, but this can be adjusted if necessary. Run ./configure --help to see how to override the defaults.

A decent battery of unit tests is included, mostly just to guard what URIs return what error codes with which methods and under which conditions. "make check" will run them.

Although only ASCII-encodable todos are supported at this point, multibyte todos could be implemented without too much work. Redis doesn't care about encoding, so it would mostly be a matter of setting the response headers correctly.

Dependencies

Build-time

credis - http://code.google.com/p/credis/

Run-time

redis - http://code.google.com/p/redis/ Apache - presumably, but any CGI-capable web server should do

td client

xsltproc - part of libxslt from http://www.xmlsoft.org/ curl - http://curl.haxx.se/

Installation

the usual: ./configure make sudo make install

... will do, although a preliminary ./configure --help ... is always instructive

The CGI binary "todoservice" is installed into /usr/libexec. See the example apache vhost configurations.

The test client "td" is installed into /usr/bin. Try "td --help" for a little guidance.

URI Specification

Test Req Resp Case Method Code Type Type URI Condition/Description


  1. GET 200 xhtml / Links (<a...>) to /todos and /version

  2. HEAD 200 /

  3. OPTIONS200 /

    • 405 /
  4. GET 200 xhtml /version API version, see below

  5. HEAD 200 /version

  6. OPTIONS200 /version

    • 405 /version
  7. GET 200 xhtml /todos Returns list of links to items Includes HTML form for POSTing

  8. HEAD 200 /todos

  9. OPTIONS200 /todos
    120 GET 500 /todos Server error, database issue 123 HEAD 500 /todos

  10. POST 201 form xhtml /todos Returns link to new item Duplicate todo content okay

  11. POST 201 form xhtml /todos Also empty content okay, but CONTENT_LENGTH and CONTENT_TYPE are still required

  12. POST 400 /todos Posted todo in wrong format

  13. POST 413 /todos Request body larger than MAX_ENTITY_LENGTH

  14. POST 415 /todos Wrong content-type 150 POST 500 /todos Server error, database issue

    • 405 /todos
  15. GET 200 xhtml /todos/{ID}

  16. GET 404 /todos/{ID} No such item 220 GET 500 /todos/{ID} Server error, database issue

  17. HEAD 200 /todos/{ID}

  18. HEAD 404 /todos/{ID} 224 HEAD 500 /todos/{ID}

  19. OPTIONS200 /todos/{ID}

  20. OPTIONS404 /todos/{ID} 228 OPTIONS500 /todos/{ID}

  21. PUT 200 form /todos/{ID}

  22. PUT 200 form /todos/{ID} Empty content okay

  23. PUT 400 /todos/{ID} Posted todo in wrong format

  24. PUT 404 /todos/{ID} No such item ... note, we don't allow PUTting a new resource, we'll require POSTing to the parent resource

  25. PUT 413 /todos/{ID} Request body larger than MAX_ENTITY_LENGTH

  26. PUT 415 /todos/{ID} Wrong content-type 260 PUT 500 /todos/{ID} Server error, database issue

  27. DELETE 200 /todos/{ID} 290 DELETE 500 /todos/{ID} Server error, database issue

    • 405 /todos/{ID}
    • 404 /todos/*/...
  28. 404 *

Notes:

  • {ID} is a human-readable, slugified string of the first token of the todo text, or the first N tokens that will make the URI unique. If a subsequent PUT changes the first tokens of the todo text, the URI will not change. The URI will have an appended index (e.g. /todos/pay-bills-2) in the case of duplicates or any other case where uniqueness can't be guaranteed by the text of the todo alone.

  • /version returns the API version, which is not the product version. We copy the versioning scheme used by libtool: major,minor,age where:

    • major bump means the API changed
    • minor bump means the internals changed (no API changes)
    • age bump measures backward-compatibility (can only occur with a major bump)
  • Content types: xhtml = application/xhtml+xml form = application/x-www-form-urlencoded

  • The . after the test case (ex. "900." ) means a unit test exists for this case.

Redis Schema

ids - set of IDs (described above)

id:foo:text - the text of the todo with ID 'foo'. Does not include a null-terminator character.
Future releases will contain other attributes like date, tags, state, etc.

Previous:g2