''JSON-RPC is a stateless, light-weight remote procedure call (RPC) protocol. It uses [JSON] (RFC 4627) as data format, and is transport-independent. It is designed to be simple!'' - from the JSON-RPC specification [http://groups.google.com/group/json-rpc/web/json-rpc-1-2-proposal]. [APN] 20080705 A Tcl implementation of the JSON-RPC client-side API is now part of [TclSOAP]. Most of the server-side calls are implemented, but not integrated with any http servers. [MaxJarek] JSON-RPC is my primary technology for client-server applications. I use Tk GUI on client side and Wibble as JSON-RPC http server. Sample client example: ====== package require JSONRPC JSONRPC::create add -proxy "http://www.raboof.com/projects/jayrock/demo.ashx" \ -params { val1 int val2 int } puts [::add 2 3456] ====== Sample server side example (for wibble::jsonrpc::proxy package): ====== namespace eval ::wibble::json-rpc { proc add {a b} {return [expr {$a+$b}]} } ====== TclSOAP don't support https transport for JSON-RPC. I have created patch for SOAP::https which is waiting in repo. wibble::jsonrpc::proxy is my package thats change Wibble in good (for me) SOA application server. jsonrpc-proxy needs same corrects in Wibble core. I am waiting for new Wibble version then proxy package will be public available. :) [AMG]: Please let me know what changes you would like in the [Wibble] core, and I'll see what I can incorporate directly. For anything that I can't just drop in without breaking compatibility and/or adding prerequisites, I may have ideas on how to modify the core to be more receptive to outside customization. The next version of Wibble, when I have time to work on it, should feature charset support, rather than being tied to ISO8859-1. That's my primary goal. I'm also collecting little fixes and updates. For example, I modified [[getrequest]] to permit application/json-rpc to be parsed by a zone handler, and I modified [[listen]] to work better with [TLS], both thanks to your suggestions and contributions. Another feature I'd like in the next Wibble is support for virtual hosts, by request from [SDW]. [MaxJarek]: Ok, let's start with Wibble 0.2 :). This is initial version. ====== # Simple JSONRPC proxy for Wibble # J. Lewandowski, (MaxJarek) # Available under the Tcl/Tk license. http://tcl.tk/software/tcltk/license.html package provide wibble::jsonrpc::proxy 0.1 namespace eval ::wibble::zone { proc jsonrpc-proxy {namespace state} { dict set state response status 200 dict set state response header content-type "" application/json-rpc charset utf-8 dict with state request {} if {$method eq "POST" && [dict exists $header content-type ""] && [dict get $header content-type ""] eq "application/json-rpc"} { array set json_req [json::json2dict [dehex $rawpost]] # execute method with params catch {set result [eval ${namespace}::$json_req(method) $json_req(params)]} err } else { set err "JSON-RPC error" } if {![info exists result]} { dict set state response content [json::write object id null \ error [json::write object name [json::write string JSONRPCError] message [json::write string $err]]] ::wibble::log "JSON-RPC: $err" } else { dict set state response content [json::write object result [json::write string $result] id $json_req(id)] } sendresponse [dict get $state response] } } ====== Example Wibble startup script: ====== namespace eval ::wibble::json-rpc { proc strlen {a} {return "[string length $a]"} proc date {} {return [clock seconds]} proc add {a b} {return [expr {$a+$b}]} } package require wibble package require json package require json::write package require wibble::jsonrpc::proxy set ::wibble::zonehandlers {} ::wibble::handle /maxgui [list jsonrpc-proxy ::wibble::json-rpc] ::wibble::handle / notfound wibble::listen 8080 vwait forever ====== Example client code: ====== package require JSONRPC JSONRPC::configure -transport http JSONRPC::create add -proxy "http://localhost:8080/maxgui" \ -params { val1 int val2 int } puts [::add 2 3456] ====== If you want any new json-rpc method simple insert new funkcion in ::wibble::json-rpc namespace [AMG]: I don't see any core modifications here. One change I made in my development version of Wibble is to add a [[dict getnull]] command (see [[dict get]] for the implementation), which simplifies this: ====== [dict exists $header content-type ""] && [dict get $header content-type ""] eq "application/json-rpc" ====== to be this: ====== [dict getnull $header content-type ""] eq "application/json-rpc" ====== This piece of code: ====== namespace eval ::wibble::json-rpc { proc strlen {a} {return "[string length $a]"} proc date {} {return [clock seconds]} proc add {a b} {return [expr {$a+$b}]} } ====== can also be written: ====== namespace eval ::wibble::json-rpc { proc strlen {a} {string length $a} proc date {} {clock seconds} proc add {a b} {expr {$a + $b}} } ====== It's mostly [a question of style]. In your code above, I went ahead and modified the line: ====== dict set state response header content-type "" "application/json-rpc; charset=utf-8" ====== to instead read: ====== dict set state response header content-type "" application/json-rpc charset utf-8 ====== This is how header [dict]s are intended to work. The empty string key maps to the value, and the other keys map to the parameters. This way, Wibble is able to read, interpret, and modify the headers without having to run the HTTP encode and decode routines. Sadly, setting the charset here doesn't actually work, since Wibble will still convert your content to ISO8859-1. If the content consists solely of 7-bit ASCII, this has no effect, since 7-bit characters are encoded identically across ISO885-1, [ASCII], and [UTF-8]. But this will corrupt anything else. For now, you're better off omitting the charset, or explicitly setting it to "iso8859-1". Like I said, I intend to fix this in the next release of Wibble, though I'm still trying to figure out how it should work. Here's what I'm thinking, for now anyway. * Wibble will have a table mapping between [HTTP] charset names and Tcl [encoding] names. When parsing the client's `accept-charset` header, Wibble will ignore charsets not present in its table. If nothing remains, or if there was no `accept-charset` to begin with, Wibble will fall back on ISO8859-1. * If there's no `charset` in the `content-type` header, or the `content-type` header is missing altogether, Wibble assumes `content` is a native Tcl string, or that `contentchan` already has its encoding configured such that [[[read]]]ing it will produce a native Tcl string. (Not sure how to handle `contentfile`.) Wibble will then pick the client's favorite charset (according to the `accept-charset` header), configure the socket to encode using that charset, then write the content to it. * If there is a `charset` in the `content-type` header, Wibble assumes `content` or `contentfile` is encoded using that charset, or that `contentchan` is configured without encoding translation and will produce text in that charset when [[read]]. If that charset is among those advertised with nonzero `q`value in the client's `accept-charset` header, Wibble will turn off encoding translation for the socket before writing out the content. Otherwise, Wibble will decode it to a native Tcl string then perform as in the above case. By the way, it's an error for to specify an unsupported `charset` in the `content-type` header. Form submission remains a problem [http://htmlpurifier.org/docs/enduser-utf8.html] [http://web.archive.org/web/20060427015200/ppewww.ph.gla.ac.uk/~flavell/charset/form-i18n.html] [http://wiki.tcl.tk/27382#pagetoca0214e53]. The only approach that makes sense, given the current state of popular web browsers, is to require that all HTML `
`s specify `accept-charset="utf-8"`. This way the browsers will send UTF-8, a known encoding that supports every character. Without an explicit `accept-charset`, browser behavior varies wildly, and in no case is it possible to reliably autodetect the encoding, not without magical knowledge unavailable to Wibble (e.g. the encoding of the page from which the `` was submitted) or ridiculous amounts of effort (e.g. statistical analysis of the byte patterns compared with typical frequencies for various encodings). Sadly, I couldn't find any configurations in which the browser actually bothered to tell the server what encoding it was using. [MaxJarek]: I know about Wibble problem with encoding content but for JSON-RPC i delete this line with ISO8859-1 encoding. Works and i have utf-8 encoding. Header with charset=utf-8 (in wibble::jsonrpc::proxy) is ignored by Wibble but is important for http transport in SOAP::http. I don't know how Wibble encoding content should work. For now i adjusting rpc-proxy for Wibble 0.2 with this ISO8859-1 modification. I noticed also thats JSONRPC package is ASCII characters oriented. I patch this and for now intensively testing with my apllications. <> Acronym