George Petasis: This page contains a small example of how an HTTP REST service can be implemented with
Rivet. I don't know if this is the best way to implement such a service, but it works for me (Although my actual implementation uses TclOO). The reason I have created this page, is that the wiki or
Rivet site have no examples on REST service implementations.
package require json
package require json::write
fconfigure stdout -encoding utf-8
proc returnJSON {json} {
fconfigure stdout -encoding utf-8
::rivet::headers numeric 200
::rivet::headers type {application/json; charset=utf-8}
::rivet::headers add Content-Length [string bytelength $json]
puts $json
}
proc returnREDIRECT {{id {}}} {
fconfigure stdout -encoding utf-8
::rivet::headers numeric 303
set scheme [::rivet::env REQUEST_SCHEME]
set host [::rivet::env HTTP_HOST]
set uri [::rivet::env DOCUMENT_URI]
if {$id eq ""} {
::rivet::headers add Location ${scheme}://${host}/${uri}
} else {
::rivet::headers add Location ${scheme}://${host}/${uri}/$id
}
::rivet::no_body
}
namespace eval service {
proc index {} {
::json::write array \
[read 0] \
[read 1] \
[read 2]
}
proc create {object} {
return id
}
proc read {id} {
::json::write object id [::json::write string $id] \
type [::json::write string sample_object]
}
proc update {id object} {
puts $object
}
proc delete {id} {
}
}
set method [::rivet::env REQUEST_METHOD]
set path [::rivet::env PATH_INFO]
switch -exact $path {
{} - / {
switch -exact $method {
GET {
returnJSON [service::index]
}
POST {
returnREDIRECT [service::create [::rivet::raw_post]]
}
default {
::rivet::headers type {text/plain; charset=utf-8}
::rivet::headers numeric 500
if {$path eq ""} {set path /}
puts "invalid method \"$method\" for endpoint \"$path\":"
puts " valid methods are:"
puts " GET: lists all objects"
puts " POST: creates a new object"
::rivet::abort_page
}
}
}
default {
switch -glob $path {
/*/ {set id [string range $path 1 end-1]}
default {set id [string range $path 1 end]}
}
switch -exact $method {
GET {
returnJSON [service::read $id]
}
PUT {
service::update $id [::rivet::raw_post]
returnREDIRECT
}
DELETE {
service::delete $id
::rivet::headers numeric 204
::rivet::no_body
}
default {
headers type {text/plain; charset=utf-8}
headers numeric 500
if {$path eq ""} {set path /}
puts "invalid method \"$method\" for endpoint \"$path\":"
puts " valid methods are:"
puts " GET: returns the object with id: \"$id\""
puts " PUT: updates the object with id: \"$id\""
puts " DELETE: deletes the object with id: \"$id\""
::rivet::abort_page
}
}
}
}