source: project/wiki/eggref/4/xml-rpc @ 15227

Last change on this file since 15227 was 15227, checked in by sjamaan, 10 years ago

Document new Chicken 4 xml-rpc egg

File size: 13.4 KB
Line 
1[[tags: egg]]
2
3== xml-rpc
4
5[[toc:]]
6
7=== Description
8
9A library for [[http://www.xmlrpc.com|XML-RPC]] client/servers.
10
11=== Author
12
13[[/users/peter-bex|Peter Bex]] (inspired by and
14using code from [[/eggref/3/xml-rpc|an earlier egg]] by
15[[/users/felix-winkelmann|Felix Winkelmann]])
16
17=== Requirements
18
19* [[http-client]]
20* [[ssax]]
21* [[sxpath]]
22* [[base64]]
23
24=== Documentation
25
26This implementation of XML-RPC is extended to allow returning multiple
27values. Errors during the execution of a server-method are propagated
28to the client as "fault" responses.
29
30==== Client
31
32Usage:
33  (use xml-rpc-client)
34
35<procedure>(xml-rpc-server uri)</procedure>
36
37Returns a procedure that, when called with the name of a remote
38XML-RPC method, will return a procedure that passes its arguments
39to the XML-RPC server which is given in {{uri}} (which can be an URI
40object or a string representing an URI).
41
42To determine how XML-RPC types are mapped to Scheme types and
43vice-versa, see [[#Low-level|below]].  It's important that you read
44this, because there is some ambiguity in how lists are mapped (either
45to arrays or to structs).
46
47For lower-level access to the client (implementing custom handlers,
48for example), you can use the following procedures:
49
50<procedure>(xml-rpc-methodcall method-name args)</procedure>
51
52Constructs an SXML representation of a method call to the procedure
53{{method-name}} with an arguments list of {{args}}.
54
55<procedure>(xml-rpc-response->values response-sxml)</procedure>
56
57This procedure accepts as {{response-sxml}} the SXML representation of
58a server's response, and either returns the values returned by the
59procedure call encoded in the response, or throws an exception of type
60{{exn xml-rpc}} in case the response contains invalid data.
61
62==== Server
63
64The server is still under construction. The building blocks for
65creating your own server are in place already:
66
67Usage:
68  (require-extension xml-rpc-server)
69
70<procedure>(xml-rpc-call->xml-rpc-response call-sxml procedures)</procedure>
71
72This procedure converts an XML-RPC procedure call described by
73{{call-sxml}} into an SXML representation of the result.  The
74procedure is looked up in {{procedures}}, invoked, and its return
75values are converted into the appropriate SXML structure describing
76a {{methodResponse}}.  If an error occurs inside the procedure,
77the procedure does not exist, or the XML is invalid, a
78{{methodResponse}} encoding the {{fault}} is constructed instead.
79
80{{procedures}} is an alist of procedure name (symbols) to procedure
81(lambda) mappings. The procedures are called with exactly the
82arguments that are sent by the client, encoded in the call
83({{call-sxml}}). They will be converted to regular Scheme values
84before the procedure is invoked.
85
86To determine how XML-RPC types are mapped to Scheme types and
87vice-versa, see [[#Low-level|below]].  It's important that you read
88this, because there is some ambiguity in how lists are mapped (either
89to arrays or to structs).
90
91<examples>
92<example>
93<init>
94(use xml-rpc-server)
95</init>
96<expr>
97(xml-rpc-call->xml-rpc-response
98  `(*TOP*
99     (*PI* xml "version=\"1.0\"")
100     (methodCall
101     (methodName "scheme.makeList")
102       (params
103         (param (value (int "1")))
104         (param (value (int "2")))
105         (param (value (int "3"))))))
106  `((scheme.makeList . ,list)))
107</expr>
108<result>
109(methodResponse
110  (params
111    (param (value
112             (array
113               (data
114                 (value (i4 "1"))
115                 (value (i4 "2"))
116                 (value (i4 "3"))))))))
117</result>
118</example>
119</examples>
120
121<procedure>(call-xml-rpc-proc call-sxml procedures)</procedure>
122
123This procedure accepts as {{call-sxml}} the SXML representation of a
124procedure call from a client and calls it, returning its values.
125
126This is exactly like {{xml-rpc-call->xml-rpc-response}}, except it
127does not construct an SXML result tree. Instead, the return values are
128those returned by the procedure being called.  In case the procedure
129could not be found or if the call contains an invalid XML structure,
130an exception of type {{(exn xml-rpc)}} is thrown.  The {{xml-rpc}}
131part of the condition contains a {{code}} property which contains the
132fault code. This is {{1}} in case the procedure could not be found and
133{{2}} in case the XML is bad.
134
135<examples>
136<example>
137<init>
138(use xml-rpc-server)
139</init>
140<expr>
141(call-xml-rpc-proc
142  `(*TOP*
143     (*PI* xml "version=\"1.0\"")
144     (methodCall
145      (methodName "Math.add")
146      (params
147       (param (value (int "1")))
148       (param (value (int "2")))
149       (param (value (int "3"))))))
150   `((Math.add . ,+)))
151</expr>
152<result>
1536
154</result>
155</example>
156</examples>
157
158==== Low-level
159
160Sometimes you want complete control over how Scheme values are mapped
161to XML-RPC values and vice versa.  For that, use this module.
162
163Usage:
164  (use xml-rpc-lolevel)
165
166===== Scheme to XML-RPC
167
168<parameter>(xml-rpc-unparsers [alist])</parameter>
169
170This parameter controls how Scheme values are encoded into XML-RPC
171values. The keys of this alist are predicate procedures, the values
172are conversion procedures.  If the predicate procedure returns true
173for its argument, it's a datatype that will be converted to SXML by
174the matching conversion procedure.
175
176Defaults to:
177
178<enscript highlight=scheme>
179`((,vector? . ,vector->xml-rpc-array)
180  (,(conjoin number? exact?) . ,number->xml-rpc-int)
181  (,number? . ,number->xml-rpc-double)
182  (,boolean? . ,boolean->xml-rpc-boolean)
183  (,string? . ,->xml-rpc-string)
184  (,symbol? . ,->xml-rpc-string)
185  (,u8vector? . ,u8vector->xml-rpc-base64)
186  (,blob? . ,blob->xml-rpc-base64)
187  (,hash-table? . ,hash-table->xml-rpc-struct)
188  ;; see below for an explantation of this predicate
189  (,nonempty-symbol-keyed-alist? . ,alist->xml-rpc-struct)
190  (,list? . ,list->xml-rpc-array))
191</enscript>
192
193Order matters in this alist; the converter corresponding to the first
194predicate returning a true value is used.
195
196The SXML returned by these conversion procedures is the element
197''inside'' the {{value}} element.
198
199<examples>
200<example>
201<init>
202(use xml-rpc-lolevel)
203</init>
204<expr>
205(number->xml-rpc-int 1)
206</expr>
207<result>
208(i4 "1")
209</result>
210</example>
211</examples>
212
213<procedure>(value->xml-rpc-fragment value)</procedure>
214
215This procedure converts any Scheme value to SXML for its XML-RPC
216representation.  It looks up the conversion procedure in the
217{{xml-rpc-unparsers}} parameter.
218
219<procedure>(nonempty-symbol-keyed-alist? obj)</procedure>
220
221Returns {{#t}} when {{obj}} is a ''nonempty'' list of pairs, each of
222which has a symbol as {{car}}.
223
224The idea behind this predicates is that it helps to do "The Right
225Thing" when you call an XML-RPC procedure. You can pass in regular
226lists or alists, and it will try to make the right decision whether
227to convert your lists to structs or arrays.
228
229The predicate returns true for nonempty lists only because it's much
230more likely that you will have empty regular lists than empty alists.
231However, it's important to be aware of this because you might end up
232with an empty alist. For absolute safety, remove this predicate from
233the parameter and use only hash-tables.
234
235* <procedure>(list->xml-rpc-array list)</procedure>
236* <procedure>(vector->xml-rpc-array vector)</procedure>
237* <procedure>(number->xml-rpc-int number)</procedure>
238* <procedure>(number->xml-rpc-double number)</procedure>
239* <procedure>(boolean->xml-rpc-boolean boolean)</procedure>
240* <procedure>(u8vector->xml-rpc-base64 u8vector)</procedure>
241* <procedure>(blob->xml-rpc-base64 blob)</procedure>
242* <procedure>(alist->xml-rpc-struct alist)</procedure>
243* <procedure>(hash-table->xml-rpc-struct hash-table)</procedure>
244
245These procedures pretty much do the obvious thing: they encode a
246Scheme object of the given type to an SXML representation for use in
247the XML-RPC request.  Again, the return values look like {{(i4 "1")}}
248and {{(string "foo")}}, ''not'' like {{(value (string "foo"))}}.
249Inside arrays and structs, the {{value}} is automatically wrapped
250around the right values.
251
252<procedure>(->xml-rpc-string obj)</procedure>
253
254This procedure converts the {{obj}} to string with {{->string}} and
255then encodes it in SXML as an XML-RPC string value.  This is useful
256for passing symbols, regular strings or numbers to procedures
257expecting string representation.
258
259<procedure>(vector->xml-rpc-iso8601 time-vector)</procedure>
260
261This procedure encodes a "time vector" (10-element vector, as returned
262by eg [[/man/4/Unit posix#seconds-local-time|seconds->local-time]]) to
263an iso8601 string representing the same date.  Currently this
264procedure is not in the parameter list by default, because it's
265impossible to differentiate between a regular vector that just happens
266to be 10 elements long and a "time-vector". The same problem exists
267for integers and the "seconds since the epoch" representation of time.
268
269Using [[srfi-19]] is a solution to this problem, as it provides a
270distinct datatype for date/time objects. But you would have to make
271your own conversion routines in this case.
272
273===== XML-RPC to Scheme
274
275<parameter>(xml-rpc-parsers [alist])</parameter>
276
277This parameter controls how XML-RPC values are decoded back into
278Scheme values. The keys of this alist are symbols, the values are
279conversion procedures.  If the name of a predicate procedure returns true for
280its argument, it's a datatype that will be converted to SXML by the
281matching conversion procedure.
282
283Defaults to:
284
285<enscript highlight=scheme>
286`((i4 . ,xml-rpc-int->number)
287  (int . ,xml-rpc-int->number)
288  (double . ,xml-rpc-double->number)
289  (boolean . ,xml-rpc-boolean->number)
290  (string . ,xml-rpc-string->string)
291  (base64 . ,xml-rpc-base64->u8vector)
292  (dateTime.iso8601 . ,xml-rpc-datetime->vector)
293  (array . ,xml-rpc-array->vector)
294  (struct . ,xml-rpc-struct->hash-table))
295</enscript>
296
297The SXML arguments to these conversion procedures is the element
298''inside'' the {{value}} element. In other words, the element name
299(or {{car}})of its SXML argument is equal to its key in this alist.
300
301<procedure>(xml-rpc-fragment->value sxml-fragment)</procedure>
302
303This procedure converts an SXML representation of an XML-RPC value to
304its Scheme representation.  It looks up the conversion procedure in
305the {{xml-rpc-parsers}} parameter.
306
307<examples>
308<example>
309<init>(use xml-rpc-lolevel)</init>
310<expr>
311(xml-rpc-fragment->value '(i4 "1"))
312</expr>
313<result>
3141
315</result>
316</example>
317</examples>
318
319* <procedure>(xml-rpc-int->number sxml-fragment)</procedure>
320* <procedure>(xml-rpc-double->number sxml-fragment)</procedure>
321* <procedure>(xml-rpc-boolean->number sxml-fragment)</procedure>
322* <procedure>(xml-rpc-string->string sxml-fragment)</procedure>
323* <procedure>(xml-rpc-array->vector sxml-fragment)</procedure>
324* <procedure>(xml-rpc-array->list sxml-fragment)</procedure>
325* <procedure>(xml-rpc-struct->alist sxml-fragment)</procedure>
326* <procedure>(xml-rpc-struct->hash-table sxml-fragment)</procedure>
327* <procedure>(xml-rpc-base64->string sxml-fragment)</procedure>
328* <procedure>(xml-rpc-base64->u8vector sxml-fragment)</procedure>
329* <procedure>(xml-rpc-base64->blob sxml-fragment)</procedure>
330* <procedure>(xml-rpc-datetime->vector sxml-fragment)</procedure>
331
332Convert the given {{sxml-fragment}} to the corresponding Scheme value.
333
334=== Examples
335
336Fetch time from xml-rpc.org:
337
338<enscript highlight=scheme>
339(require-extension xml-rpc-client)
340
341(define time-server
342  (xml-rpc-server "http://xml-rpc.org/RPC2") )
343 
344(define get-current-time
345  (time-server "currentTime.getCurrentTime") )
346 
347(print (time->string (get-current-time)))
348</enscript>
349
350A simple "hello" server: (this does not currently function and will be changed)
351
352<enscript highlight=scheme>
353(require-extension xml-rpc-server)
354 
355(define-remote-method (hello var)
356  (sprintf "Hello, ~A!" var) )
357 
358((start-server 4242))
359</enscript>
360
361You can access it using this client:
362
363<enscript highlight=scheme>
364(require-extension xml-rpc-client)
365 
366(define srv (xml-rpc-server "http://localhost:4242/RPC2"))
367(define hello (srv "hello"))
368 
369(print "-> " (hello "you"))
370</enscript>
371
372Then run it as follows:
373
374  % csi -script hello.scm &
375  % csi -script client.scm
376 
377  -> Hello, you!
378
379=== Changelog
380
381* 2.0 Reimplementation in Chicken 4, based on [[http-client]]
382
383=== License
384
385  Copyright (c) 2009, Peter Bex
386  Parts Copyright (c) Felix Winkelmann
387  All rights reserved.
388 
389  Redistribution and use in source and binary forms, with or without
390  modification, are permitted provided that the following conditions are
391  met:
392 
393    Redistributions of source code must retain the above copyright
394    notice, this list of conditions and the following disclaimer.
395 
396    Redistributions in binary form must reproduce the above copyright
397    notice, this list of conditions and the following disclaimer in the
398    documentation and/or other materials provided with the distribution.
399 
400    Neither the name of the author nor the names of its contributors may
401    be used to endorse or promote products derived from this software
402    without specific prior written permission.
403 
404  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
405  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
406  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
407  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
408  HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
409  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
410  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
411  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
412  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
413  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
414  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
415  DAMAGE.
Note: See TracBrowser for help on using the repository browser.