filename | date | version |
---|---|---|
trRESTXQ |
2014-04-07 |
0.2 |
Cette page présente un des services d'application web. Elle décrit comment utiliser l'API RESTXQ de BaseX.
RESTXQ, introduit par [Adam Retter][1], est une nouvelle API qui facilite l'utilisation de XQuery comme un langage de traitement côté serveur pour le web. RESTXQ s'inspire de l'API JAX-RS pour Java : elle définit un ensemble prédéfini d'annotations XQuerry 3.0 qui font correspondre des requêtes HTTP à des fonctions XQuery, qui à leur tour génèrent et retournent des réponses HTTP.
Notez que certaines extensions présentées dans cette documentation sont spécifiques à BaseX ; il est possible qu'elles soient intégrées dans des versions futures du brouillon de RESTXQ.
Les fonctionnalités diffèrent du brouillon RESTXQ :
- les types
multipart
sont supportés, y comprismultipart/form-data
- une annotation
%rest:error
peut être employée pour repérer les erreurs XQuery - les erreurs du servlet peuvent être redirigées vers d'autres pages RESTXQ
- un Module RESTXQ fournit des fonctions d'aide
- les paramètres sont implicitement convertis dans le type de l'argument de la fonction
Le service RESTXQ est accessible via http://localhost:8984/, et le serveur HTTP est démarré avec les crédits d'administration (voir ici).
Toutes les annotations RESTXQ sont assignées à l'espace de nom http://exquery.org/ns/restxq
, qui est statiquement lié au préfixe rest
. Une fonction ressource est une fonction XQuery qui a été marquée par des annotations RESTXQ. Lorsqu'une requête HTTP arrive, une fonction ressource correspondant aux contraintes indiquées par ses annotations sera invoquée.
Lorsqu'une URL RESTXQ est requétée, le répertoire du module RESTXQPATH et ses sous-répertoires seront parcourus pour des fonctions disposant d'annotations RESTXQ dans les modules de bibliothèque (détectés par l'extension .xqm
) et les modules principaux (détectés par .xq
). Dans les expressions principales, le module principal ne sera jamais évalué. Tous les modules seront mis en cache et parcouru une nouvelle fois quand leur timestamp change.
Un module RESTXQ simple est présenté ci-dessous. Il fait partie d'une installation propre et est disponible à http://localhost:8984/.
(: simplified version of the function found in webapp/restxq.xqm :)
module namespace page = 'http://basex.org/examples/web-page';
declare %rest:path("hello/{$world}")
%rest:GET
%rest:header-param("User-Agent", "{$agent}")
function page:hello($world as xs:string, $agent as xs:string*) {
<response>
<title>Hello { $world }!</title>
<info>You requested this page with { $agent }.</info>
</response>
};
Si l'on se rend à l'URI http://localhost:8984/hello/World, le résultat sera similaire à :
<response>
<title>Hello World!</title>
<time>The current time is: 18:42:02.306+02:00</time>
</response>
Le module RESTXQ contient également une autre fonction :
declare
%rest:path("/form")
%rest:POST
%rest:form-param("message","{$message}", "(no message)")
%rest:header-param("User-Agent", "{$agent}")
function page:hello-postman(
$message as xs:string,
$agent as xs:string*)
as element(response)
{
<response type='form'>
<message>{ $message }</message>
<user-agent>{ $agent }</user-agent>
</response>
};
Si vous postez quelque chose (par exemple en utilisant curl ou un formulaire embarqué dans http://localhost:8984/...
curl -i -X POST --data "message='CONTENT'" http://localhost:8984/form
... le résultat ressemblera à :
HTTP/1.1 200 OK
Content-Type: application/xml; charset=UTF-8
Content-Length: 107
Server: Jetty(8.1.11.v20130520)
<response type="form">
<message>'CONTENT'</message>
<user-agent>curl/7.31.0</user-agent>
</response>
Cette section montre comment les annotations peuvent être employés pour manipuler et traiter des requêtes HTTP.
Les contraintes restreignent les requêtes HTTP qu'une fonction ressource peut traiter.
Une fonction ressource doit avoir une seule annotation de chemin qui prend une seule chaîne comme argument. La fonction sera appelée si une URL correspond aux segments de chemin et au motif de l'argument. Les motifs de chemin (path templates) contiennent des variables entre accolades, et alignent les segments correspondants du chemin de la requête aux arguments de la fonction ressource.
L'exemple suivant contient une annotation de chemin avec trois segments et deux motifs. Un des arguments de la fonction est spécifié plus loin avec un type de données qui signifie que la valeur pour $variable
sera convertie en xs:integer
avant d'être liée :
declare %rest:path("/a/path/{$with}/some/{$variable}")
function page:test($with, $variable as xs:integer) { ... };
Les deux annotations suivantes peuvent être employées pour restreindre des fonctions à des types de contenus particuliers :
- HTTP Content Types : une fonction sera invoquée seulement si l'en-tête HTTP
Content-Type
de la requête correspond à l'un des types mime renseigné. Par exemple :
%rest:consumes("application/xml", "text/xml")
- ** HTTP Accept** : une fonction sera invoquée seulement si l'en-tête HTTP
Accept
de la requête correspond à l'un des types mime définis. Par exemple :
%rest:produces("application/atom+xml")
Par défaut, les deux types mime sont */*
. Notez que cette annotation n'affectera pas le type de contenu (content-type) de la réponse HTTP. Pour cela, vous devrez ajouter une annotation %output:media-type
.
Les annotations de méthodes HTTP équivalent à toutes les méthodes de requête HTTP hormis TRACE et CONNECT. Zéro ou plusieurs méthodes peuvent être employées pour une fonction ; si aucune n'est spécifiée, la fonction sera invoquée pour chaque méthode.
La fonction suivante sera appelée si les méthodes de requêtes GET ou POST sont employées :
declare %rest:GET %rest:POST %rest:path("/post")
function page:post() { "This was a GET or POST request" };
Les annotations POST et PUT peuvent optionnellement prendre un littéral chaîne de caractères pour faire correspondre le corps de la requête HTTP à un argument de la fonction. Encore une fois, la variable cible doit être comprise entre accolades :
declare %rest:PUT("{$body}") %rest:path("/put")
function page:put($body) { "Request body: " || $body };
Si un type de contenu (content-type) est spécifié dans la requête, le contenu est converti dans le type XQuery suivant :
Content-Type | XQuery type
application/json
, application/jsonml+json
| document-node()
(conversion décrite dans le module JSON)
text/html
| document-node()
(conversion décrite dans le module HTMl)
text/comma-separated-values
| document-node()``
text/xml,
application/xml|
document-node() `text/*` | `xs:string
autres | xs:base64Binary
multipart/*` | sequence (voir le paragraphe suivant)
Un début de support pour les types de contenu (content-type) multipart
a été ajouté. Les parties d'un message multipart sont représentées comme une séquence, et chaque partie est convertie en un item XQuery comme décrit dans le dernier paragraphe.
Une fonction qui est capable de manipuler des types multipart est identique à d'autres fonctions RESTXQ :
declare
%rest:path("/multipart")
%rest:POST("{$data}")
%rest:consumes("multipart/mixed") (: optional :)
function page:multipart($data as item()*)
{
"Number of items: " || count($data)
};
Veuillez noter que le support des types multipart est encore expérimental, il pourrait changer dans une version future de BaseX. Vos retours sont bienvenus.
Les annotations suivantes peuvent êtrees pou employér lier des valeurs de requête à des arguments de fonction. Les valeurs seront implicitement converties vers le type de l'argument.
La valeur du premier paramètre, si elle est trouvée dans le composant de requête, sera assignée à la variable spécifiée comme second paramètre. Si aucune valeur n'est spécifiée dans la requête HTTP, tous les paramètres additionnels seront liés à la variable (si aucun paramètre additionnel n'est donné, une séquence vide sera liée) :
declare
%rest:path("/params")
%rest:query-param("id", "{$id}")
%rest:query-param("add", "{$add}", 42, 43, 44)
function page:params($value as xs:string?, $answer as xs:integer+)
{
<result id="{ $id }" sum="{ sum($add) }"/>
};
Les paramètres de formulaire sont spécifiés de la même manière que les paramètres de requête. Leurs valeurs sont extraites depuis les requêtes GET ou POST.
%rest:form-param("parameter", "{$value}", "default")
Des fichiers peuvent être chargés sur le serveur en utilisant le type de contenu multipart/form-data
(l'attribut multiple
de HTML5 permet le chargement de plusieurs fichiers).
<form action="/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="files" multiple="multiple"/>
<input type="submit"/>
</form>
Le contenu des fichiers est placé dans un map, le nom du fichier servant de key. L'exemple suivant montre comment les fichiers chargés peuvent être stockés dans un répertoire temporaire :
declare
%rest:POST
%rest:path("/upload")
%rest:form-param("files", "{$files}")
function page:upload($files)
{
for $name in map:keys($files)
let $content := $files($name)
let $path := file:temp-dir() || $name
return (
file:write-binary($path, $content),
<file name="{ $name }" size="{ file:size($path) }"/>
)
};
Les paramètres d'en-tête sont spécifiés de la même manière que les paramètres de requête :
%rest:header-param("User-Agent", "{$user-agent}")
%rest:header-param("Referer", "{$referer}", "none")
Les paramètres de cookies sont spécifiés de la même manière que les paramètres de requête :
%rest:cookie-param("username", "{$user}")
%rest:cookie-param("authentification", "{$auth}", "no_auth")
Par défaut, une requête réussie reçoit le code de statut HTTP 200
(OK) et est suivie du contenu correspondant. Une requête erronée mène à un code d'erreur et un message d'erreur optionnel (par exemple 404
pour "resource not found").
Les réponses personnalisées peuvent être construites au sein de XQuery en retournant un élément rest:response
, un nœud fils http:response
qui correspond à la syntaxe du module Client HTTP de la spécification EXPath, et plusieurs nœuds fils optionnels qui seront sérialisés comme habituellement. Une fonction qui réagit sur une ressource inconnue peut ressembler à ce qui suit :
declare %rest:path("") function page:error404() {
<rest:response>
<http:response status="404" message="I was not found.">
<http:header name="Content-Language" value="en"/>
<http:header name="Content-Type" value="text/html; charset=utf-8"/>
</http:response>
</rest:response>
};
Les deux éléments XML rest:forward
et rest:redirect
peuvent être utilisés dans le contexte d'Applications Web, plus précisément dans le contexte de RESTXQ. Ces nœuds permettent par exemple plusieurs Mises à jour XQuery dans une rangée, par la redirection vers le chemin RESTXQ de fonctions mises à jour. Tous deux relient une URL et un chemin RESTXQ. L'URL encadrée doit être encodé correctement via la fonction fn:encode-for-uri()
.
Il est à noter qu'actuellement ces éléments ne font pas parti de la spécification RESTXQ.
Usage: encadre la location comme suit:
<rest:forward>{ $location }</rest:forward>
// Reprendre la traduction //