WebCheckout API v0.1 Documentation

Protocol Overview

The WCO-API is a new way to access and edit the state of WebCheckout via HTTP in a RESTful style using JSON.

THE API is very much a work in progress. It should be assumed to be highly unstable. Efforts will be made to update this documentation, however as the API is in active development this document may be out of date.

Latter pages in this document will assume you are familiar with the former sections. Please do read through at least the first 4 sections in their entirety.

It is assumed that the reader has some knowledge of JSON and RESTful APIs in general. This document may include examples, but it is not intended to be a complete how-to guide or an introduction to RESTful APIs.

There is not always complete agreement on what is and is not RESTy. We have no intention of wading into that debate. Our API is being used to progressively modernize our application and as such, during its development, is subject to the needs of a living breathing application and user base. In short, those places where we have strayed from the REST paradigm are likely to have been caused by the need to follow design patterns and use cases that have developed over many years.

Documentation Conventions

Let's get some conventions out of the way. Throughout this document, when ever we need to format a post to the API along with the posted data is formatted as so...

POST URL

	  {
	      "hello": "world"
	  }

Similarly, the status code and the JSON returned by the API is formatted thus...

HTTP 200

	  {
	      "json": "awesome"
	  }
A Note About Case

The language of our core, ANSI Common Lisp, is historically a case insensitive language. Common lisp identifiers are written with hyphens separating words (for example "my-identifier"). On the other hand JavaScript, the anticipated client of the API, is case sensitive, reserving the '-' character for subtraction, and so uses lowerCamelCase ("myIdentifier") for non-quoted symbols. JSON keys are quoted strings, so they can go either way. Don't get me started on HTML element tags and Angular directives.

We opted to pretend in the API that the lisp 'hyphenated case' doesn't exist since it tends to perplex those more familiar with JavaScript. That said, While reading these documents you may find either of the cases or, if we are really trying to trip you up, we may actually use multiple words. So allocationItem, allocation-item, and allocation item may all refer to the same thing.

As we normalize these docs we are going to err on the side of lowerCamelCase. Sorry in advance for any confusion

Namespaces

Namespaces are the highest level separation of REST operations. All operations in the API exist under a namespace, most namespaces correspond to a specific Framework Entity (such as a person or an allocation) However, some special namespaces exist that have their own conventions.

Entities are complex objects in the WebCheckout core and are handled in their own section.

URIs
WebCheckout REST API URIs are formatted as follows.

rest/<namespace>/<optional command or object identifier>

HTTP Encoding

All Messages to and from the REST API should be encoded with the Content-Type "application/json; charset=UTF-8".

All arguments and data are passed to and from the REST API in the HTTP Request and Response payload as UTF-8 Formatted JSON.

HTTP Methods

All operations to the WebCheckout REST API use the HTTP POST operation.

API Response Format
All responses from the REST API will be a JSON object with five values. API Version

The API Version is intended to communicate changes in the API to third party users once the API is published. Currently the API identifies itself as version 0.1 which should not be seen as a canonical value identifying a stable API. When we officially "publish" the API the major number will be an integer greater that 1.

Session The session value identifies the WebCheckout framework session this JSON message was created for. Session information may be used by the user to cache certain information and will remain stable through the life of the session. It will be null if the user has not yet authenticated. Status The status of an API response will be one of seven possible values: Notifications null, or an array of one or more notification messages intended to provide extra information to the user.
	[
	    {
                "message": "Everything is coming up Millhouse", 
                "type": "success"
	    }
        ]
type will be one of the following:
  1. success
  2. warning
  3. error
Payload The payload is dependent on the API Operation and can range from null to deeply nested context-sensitive data. Sessionid The sessionid is a token identifying a unique session to the API. It may or may not be used depending on the style of session management in use. More on that in the sessions section.
HTTP Return Codes

All successful REST API calls will return the HTTP response code 200. Only extra-protocol errors use HTTP response codes.

There are some circumstances when the code is non-200

400 Bad Request A request for a non-existing method

POST rest/person/noSuchCommand

      {
          "sessionid": "1bcb6b07-88b5-4db0-8201-8feaf0ec7ed6"
      }

HTTP 400

      {
          "apiVersion": "0.1",
          "session": "S-17896",
          "status": "error",
          "notifications": null,
          "payload": {
              "message": "Requested command NO-SUCH-COMMAND was not found in namespace PERSON",
              "class": "REST-SERVER:FRAMEWORK-COMMAND-NOT-FOUND"
          },
          "sessionid": "1bcb6b07-88b5-4db0-8201-8feaf0ec7ed6"
      }
404 Not Found A request for a resource in a namespace that does not exist

POST rest/noSuchNamespace/noSuchCommand

      {
          "sessionid": "1bcb6b07-88b5-4db0-8201-8feaf0ec7ed6"
      }

HTTP 404

      {
          "apiVersion": "0.1",
          "session": "S-17896",
          "status": "error",
          "notifications": null,
          "payload": {
              "message": "Requested namespace NO-SUCH-NAMESPACE was not found",
              "class": "REST-SERVER:NAMESPACE-NOT-FOUND"
          },
          "sessionid": "1bcb6b07-88b5-4db0-8201-8feaf0ec7ed6"
      }
405 Method Not Allowed Any use of an HTTP Request method other than POST

GET rest/session/currentSession

      {
          "sessionid": "1bcb6b07-88b5-4db0-8201-8feaf0ec7ed6"
      }

HTTP 405

      {
          "apiVersion": "0.1",
          "session": null,
          "status": "error",
          "notifications": null,
          "payload": {
              "message": "All WCO API commands require the HTTP POST method",
              "class": "REST-SERVER:METHOD-NOT-ALLOWED"
          }
      }
500 Internal Server Error An uncaught fatal error in the application. The equivalent of the gray screen in WebCheckout.

POST rest/session/testError

      {
          "sessionid": "1bcb6b07-88b5-4db0-8201-8feaf0ec7ed6"
      }

HTTP 500

      {
          "apiVersion": "0.1",
          "session": "S-17896",
          "status": "error",
          "notifications": null,
          "payload": {
              "message": "TEST ERROR",
              "backtrace": "Backtrace for: #\n0: ((LAMBDA NIL :IN SB-DEBUG::FUNCALL-WITH-DEBUG-IO-SYNTAX))\n1: (SB-IMPL::CALL-WITH-SANE-IO-SYNTAX #)\n2: (SB-IMPL::%WITH-STANDARD-IO-SYNTAX #)\n3: (SB-DEBUG:PRINT-BACKTRACE :STREAM # :START 0 :FROM :DEBUGGER-FRAME :COUNT 4611686018427387903 :PRINT-THREAD T :PRINT-FRAME-SOURCE NIL :METHOD-FRAME-STYLE NIL)\n4: ((:METHOD REST-SERVER::REST-ERROR-AS-JSON (ERROR)) #) [fast-method]\n5: ((FLET REST-SERVER::RETURN-ERROR :IN HUNCHENTOOT:ACCEPTOR-DISPATCH-REQUEST) #)\n6: (SIGNAL #)\n7: (ERROR \"TEST ERROR\")\n8: ((LAMBDA NIL :IN WCOF::PERFORM))\n9: (WCOF::CALL-WITHOUT-AUTHORIZATION-CHECKING #)\n10: ((LAMBDA (WCOF::FRAMEWORK-TRANSACTION) :IN WCOF::PERFORM) #)\n11: (POSTMODERN::CALL-WITH-TRANSACTION #)\n12: (POSTMODERN::CALL-WITH-LOGICAL-TRANSACTION WCOF::FRAMEWORK-TRANSACTION #)\n13: ((LAMBDA NIL :IN WCOF::PERFORM))\n14: (WCOF::CALL-WITH-DATABASE-CONNECTION # #)\n15: (WCOF::CALL-WITH-POOLED-DATABASE #)\n16: ((:METHOD WCOF::PERFORM (REST-SERVER::TEST-ERROR)) #) [fast-method]\n17: (REST-SERVER::TEST-ERROR)\n18: ((:METHOD REST-SERVER::%INVOKE-FRAMEWORK-COMMAND (HUNCHENTOOT:REQUEST T T)) # # REST-SERVER::TEST-ERROR) [fast-method]\n19: ((:METHOD REST-SERVER::INVOKE-FRAMEWORK-COMMAND (HUNCHENTOOT:REQUEST T T)) # \"SESSION\" \"TEST-ERROR\") [fast-method]\n20: ((:METHOD REST-SERVER::%DISPATCH-METHOD-REQUEST (HUNCHENTOOT:REQUEST)) #) [fast-method]\n21: ((:METHOD HUNCHENTOOT:ACCEPTOR-DISPATCH-REQUEST (REST-SERVER::REST-ACCEPTOR HUNCHENTOOT:REQUEST)) # #) [fast-method]\n22: ((FLET CALL-NEXT-METHOD :IN \"/home/lee/vc/web-co/webco/src/lisp/rest-server/acceptor.lisp\"))\n23: ((LAMBDA NIL :IN HUNCHENTOOT:ACCEPTOR-DISPATCH-REQUEST))\n24: (WCOF::CALL-WITH-CACHED-CONTENTS #)\n25: ((FLET #:DEBUGGABLE-HANDLER-BIND-BODY62 :IN HUNCHENTOOT:ACCEPTOR-DISPATCH-REQUEST))\n26: ((LAMBDA NIL :IN HUNCHENTOOT:ACCEPTOR-DISPATCH-REQUEST))\n27: (WCOF::CALL-WITH-DATABASE-CONNECTION # #)\n28: (WCOF::CALL-WITH-POOLED-DATABASE #)\n29: ((:METHOD HUNCHENTOOT:ACCEPTOR-DISPATCH-REQUEST :AROUND (REST-SERVER::REST-ACCEPTOR HUNCHENTOOT:REQUEST)) # #) [fast-method]\n30: ((:METHOD HUNCHENTOOT:HANDLE-REQUEST (HUNCHENTOOT:ACCEPTOR HUNCHENTOOT:REQUEST)) # #) [fast-method]\n31: ((:METHOD HUNCHENTOOT:PROCESS-REQUEST (T)) #) [fast-method]\n32: ((SB-PCL::GF-DISPATCH HUNCHENTOOT:PROCESS-REQUEST) #)\n33: ((LAMBDA NIL :IN HUNCHENTOOT:PROCESS-CONNECTION))\n34: (HUNCHENTOOT::DO-WITH-ACCEPTOR-REQUEST-COUNT-INCREMENTED # #)\n35: ((:METHOD HUNCHENTOOT:PROCESS-CONNECTION (HUNCHENTOOT:ACCEPTOR T)) # #) [fast-method]\n36: ((FLET CALL-NEXT-METHOD :IN \"/home/lee/vc/web-co/webco/lib/lisp/hunchentoot_1.2.17/acceptor.lisp\"))\n37: ((:METHOD HUNCHENTOOT:PROCESS-CONNECTION :AROUND (HUNCHENTOOT:ACCEPTOR T)) # #) [fast-method]\n38: ((FLET HUNCHENTOOT::PROCESS-CONNECTION% :IN HUNCHENTOOT::HANDLE-INCOMING-CONNECTION%) # #)\n39: ((:METHOD HUNCHENTOOT::HANDLE-INCOMING-CONNECTION% (HUNCHENTOOT:ONE-THREAD-PER-CONNECTION-TASKMASTER T)) # #) [fast-method]\n40: ((LAMBDA NIL :IN HUNCHENTOOT:CREATE-REQUEST-HANDLER-THREAD))\n41: ((LAMBDA NIL :IN BORDEAUX-THREADS::BINDING-DEFAULT-SPECIALS))\n42: ((FLET #:WITHOUT-INTERRUPTS-BODY-1120 :IN SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE))\n43: ((FLET SB-THREAD::WITH-MUTEX-THUNK :IN SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE))\n44: ((FLET #:WITHOUT-INTERRUPTS-BODY-537 :IN SB-THREAD::CALL-WITH-MUTEX))\n45: (SB-THREAD::CALL-WITH-MUTEX # #> NIL T NIL)\n46: (SB-THREAD::INITIAL-THREAD-FUNCTION-TRAMPOLINE # #S(SB-THREAD:SEMAPHORE :NAME \"Thread setup semaphore\" :%COUNT 0 :WAITCOUNT 0 :MUTEX # :QUEUE #) # NIL NIL NIL NIL)\n47: (\"foreign function: call_into_lisp\")\n48: (\"foreign function: new_thread_trampoline\")\n",
              "class": "COMMON-LISP:SIMPLE-ERROR"
          },
          "sessionid": "1bcb6b07-88b5-4db0-8201-8feaf0ec7ed6"
      }