Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Expands support for json encoded arguments. This lets rest.tcl be used with Gemini and openai REST interfaces. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | trunk |
Files: | files | file ages | folders |
SHA3-256: |
0b3dd048f836fbbc0832b6e731debcfe |
User & Date: | clif 2025-07-16 13:30:15.865 |
Context
2025-07-16
| ||
13:30 | Expands support for json encoded arguments. This lets rest.tcl be used with Gemini and openai REST interfaces. Leaf check-in: 0b3dd048f8 user: clif tags: trunk | |
2024-11-15
| ||
08:12 | Correct a typo in the description of the elliptic function dn (K.Koehler) check-in: 61e6db60d3 user: arjenmarkus tags: trunk | |
Changes
Changes to modules/rest/rest.tcl.
1 2 3 4 5 6 | # rest.tcl -- # # A framework for RESTful web services # # Copyright (c) 2009 Aaron Faupell | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | # rest.tcl -- # # A framework for RESTful web services # # Copyright (c) 2009 Aaron Faupell package require Tcl 8.5 9+ package require http 2.7 package require json package require tdom package require base64 package provide rest 1.8 namespace eval ::rest { namespace export create_interface parameters parse_opts save \ describe substitute } # simple -- |
︙ | ︙ | |||
39 40 41 42 43 44 45 | set body [lindex $opts 1] } else { set body [lindex $args 1] } DetermineMethod config | > > > > > > | < > | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | set body [lindex $opts 1] } else { set body [lindex $args 1] } DetermineMethod config #### CLIF FIX # if query has a space assume it might be a list of key value pairs, # and do the formatting # Unless there's a space and it's a single list element, # then it's more likely a json encoded string, so don't touch it. if {([string first " " $query] > 0) && ([llength $query] > 1)} { set query [::http::formatQuery {*}$query] } elseif {[string first ? $url] > 0 && $query == ""} { # if the url contains a query string and query empty then split it to the correct vars set query [join [lrange [split $url ?] 1 end] ?] set url [lindex [split $url ?] 0] } #### CLIF FIX if {[dict exists $config auth]} { set auth [dict get $config auth] if {[lindex $auth 0] == "basic"} { lappend headers Authorization "Basic [base64::encode [lindex $auth 1]:[lindex $auth 2]]" } elseif {[lindex $auth 0] == "bearer"} { lappend headers Authorization "Bearer [lindex $auth 1]" |
︙ | ︙ | |||
144 145 146 147 148 149 150 151 152 153 154 155 156 157 | # break # } # } #} namespace eval ::$name {} foreach call [array names in] { set config $in($call) set proc [list] if {[dict exists $config copy]} { set config [dict merge $in([dict get $config copy]) $config] } if {[dict exists $config unset]} { | > | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | # break # } # } #} namespace eval ::$name {} foreach call [array names in] { set config $in($call) set proc [list] if {[dict exists $config copy]} { set config [dict merge $in([dict get $config copy]) $config] } if {[dict exists $config unset]} { |
︙ | ︙ | |||
228 229 230 231 232 233 234 | lappend proc {lappend headers Cookie [join [dict get $config cookie] \;]} } _transform $name $call $config proc input_transform query if {[dict exists $config auth] && [lindex [dict get $config auth] 0] == "sign"} { lappend proc "set query \[::${name}::[lindex [dict get $config auth] 1] \$query]" } | > > > > > > > > > > > > > > > | > > > > > > > > | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | lappend proc {lappend headers Cookie [join [dict get $config cookie] \;]} } _transform $name $call $config proc input_transform query if {[dict exists $config auth] && [lindex [dict get $config auth] 0] == "sign"} { lappend proc "set query \[::${name}::[lindex [dict get $config auth] 1] \$query]" } # lappend proc {set query [::http::formatQuery {*}$query]} # CLIF FIX # If there's headers, and if there's content-type, # and if that's application/json, use json format # else use formatQuery if {[dict exists $config headers]} { set headers [string tolower [dict get $config headers]] if {[dict exists $headers content-type]} { set ctype [dict get $headers content-type] switch $ctype { application/json { lappend proc {set query [json::write object-string {*}$query]} } application/x-www-form-urlencoded - default { lappend proc {set query [::http::formatQuery {*}$query]} } } } } else { lappend proc {set query [::http::formatQuery {*}$query]} } # CLIF FIX # if this is an async call (has defined a callback) # then end the main proc here by returning the http token # the rest of the normal result processing will be put in a _callback_NAME # proc which is called by the generic _callback proc if {[dict exists $config callback]} { lappend proc "set t \[::rest::_call \{[list ::${name}::_callback_$call [dict get $config callback]]\} \$headers \$url \$query \$body \$error_body]" |
︙ | ︙ | |||
434 435 436 437 438 439 440 | # EFFECTS: # creates a new namespace and builds api procedures within it # # RETURNS: # the data from the http reply, or an http token if the request was async # proc ::rest::_call {callback headers url query body error_body} { | | | 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | # EFFECTS: # creates a new namespace and builds api procedures within it # # RETURNS: # the data from the http reply, or an http token if the request was async # proc ::rest::_call {callback headers url query body error_body} { puts "_call [list C: $callback\n H: $headers\n U $url\n Q $query\n B $body\n E $error_body]" # get the settings from the calling proc upvar config config set method GET if {[dict exists $config method]} { set method [string toupper [dict get $config method]] } # assume the query should really be the body for post or put requests |
︙ | ︙ | |||
474 475 476 477 478 479 480 | lappend opts -timeout [dict get $config timeout] } #puts "headers $headers" #puts "opts $opts" #puts "geturl $url" #return | > > > | > > > > > > > | > > > > | 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 | lappend opts -timeout [dict get $config timeout] } #puts "headers $headers" #puts "opts $opts" #puts "geturl $url" #return # CLIF FIX if {$headers ne ""} { set t [http::geturl $url -headers $headers {*}$opts] } else { set t [http::geturl $url {*}$opts] } # CLIF FIX set data [http::data $t] set httpCode [http::ncode $t] # if this is an async request return now, otherwise process the # result if {$callback != ""} { return $t } # Generate an error return for a failed request if {![string match 2* $httpCode]} { #parray $t set retList [list HTTP $httpCode] if {[string match {30[123]} $httpCode]} { upvar #0 $t a ### CLIF FIX ### if {[dict exists $a(meta) Location]} { lappend retList [dict get $a(meta) Location] } else { lappend retList "Moved to undefined location" } ### CLIF FIX ### } if {$error_body} {lappend retList $data} return -code error $retList } # copy the token into the calling scope so that the transforms can # access it via uplevel, and we can still call cleanup on the real |
︙ | ︙ |