1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: J.Wielemaker@vu.nl 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2007-2015, University of Amsterdam 7 VU University Amsterdam 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 17 2. Redistributions in binary form must reproduce the above copyright 18 notice, this list of conditions and the following disclaimer in 19 the documentation and/or other materials provided with the 20 distribution. 21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 POSSIBILITY OF SUCH DAMAGE. 34*/ 35 36:- if(current_predicate(is_dict/1)). 37:- module(http_json, 38 [ reply_json/1, % +JSON 39 reply_json/2, % +JSON, Options 40 reply_json_dict/1, % +JSON 41 reply_json_dict/2, % +JSON, Options 42 http_read_json/2, % +Request, -JSON 43 http_read_json/3, % +Request, -JSON, +Options 44 http_read_json_dict/2, % +Request, -Dict 45 http_read_json_dict/3 % +Request, -Dict, +Options 46 ]). 47:- else. 48:- module(http_json, 49 [ reply_json/1, % +JSON 50 reply_json/2, % +JSON, Options 51 http_read_json/2, % +Request, -JSON 52 http_read_json/3 % +Request, -JSON, +Options 53 ]). 54:- endif. 55:- use_module(http_client). 56:- use_module(http_header). 57:- use_module(http_stream). 58:- use_module(json). 59:- use_module(library(option)). 60:- use_module(library(error)). 61:- use_module(library(lists)). 62:- use_module(library(memfile)). 63 64:- multifile 65 http_client:http_convert_data/4, 66 http:post_data_hook/3, 67 json_type/1. 68 69:- public 70 json_type/1. 71 72:- predicate_options(http_read_json/3, 3, 73 [ content_type(any), 74 false(ground), 75 null(ground), 76 true(ground), 77 value_string_as(oneof([atom, string])), 78 json_object(oneof([term,dict])) 79 ]). 80:- predicate_options(reply_json/2, 2, 81 [ content_type(any), 82 status(integer), 83 json_object(oneof([term,dict])), 84 pass_to(json:json_write/3, 3) 85 ]).
term
or dict
. If the value is dict
,
json_read_dict/3 is used.145http_clienthttp_convert_data(In, Fields, Data, Options) :- 146 memberchk(content_type(Type), Fields), 147 is_json_type(Type), 148 !, 149 ( memberchk(content_length(Bytes), Fields) 150 -> setup_call_cleanup( 151 ( stream_range_open(In, Range, [size(Bytes)]), 152 set_stream(Range, encoding(utf8)) 153 ), 154 json_read_to(Range, Data, Options), 155 close(Range)) 156 ; set_stream(In, encoding(utf8)), 157 json_read_to(In, Data, Options) 158 ). 159 160 161is_json_type(String) :- 162 http_parse_header_value(content_type, String, 163 media(Type, _Attributes)), 164 json_type(Type), 165 !. 166 167:- if(current_predicate(is_dict/1)). 168json_read_to(In, Data, Options) :- 169 memberchk(json_object(dict), Options), 170 !, 171 json_read_dict(In, Data, Options). 172:- endif. 173json_read_to(In, Data, Options) :- 174 json_read(In, Data, Options).
185json_type(application/jsonrequest). 186json_type(application/json).
http_post(URL, json(Term), Reply, Options) http_post(URL, json(Term, Options), Reply, Options)
If Options are passed, these are handed to json_write/3. In addition, this option is processed:
dict
, json_write_dict/3 is used to write the
output. This is default if json(Dict)
is passed.208:- if(current_predicate(is_dict/1)). 209httppost_data_hook(json(Dict), Out, HdrExtra) :- 210 is_dict(Dict), 211 !, 212 http:post_data_hook(json(Dict, [json_object(dict)]), 213 Out, HdrExtra). 214:- endif. 215httppost_data_hook(json(Term), Out, HdrExtra) :- 216 http:post_data_hook(json(Term, []), Out, HdrExtra). 217httppost_data_hook(json(Term, Options), Out, HdrExtra) :- 218 option(content_type(Type), HdrExtra, 'application/json'), 219 setup_call_cleanup( 220 ( new_memory_file(MemFile), 221 open_memory_file(MemFile, write, Handle) 222 ), 223 ( format(Handle, 'Content-type: ~w~n~n', [Type]), 224 json_write_to(Handle, Term, Options) 225 ), 226 close(Handle)), 227 setup_call_cleanup( 228 open_memory_file(MemFile, read, RdHandle, 229 [ free_on_close(true) 230 ]), 231 http_post_data(cgi_stream(RdHandle), Out, HdrExtra), 232 close(RdHandle)). 233 234:- if(current_predicate(is_dict/1)). 235json_write_to(Out, Term, Options) :- 236 memberchk(json_object(dict), Options), 237 !, 238 json_write_dict(Out, Term, Options). 239:- endif. 240json_write_to(Out, Term, Options) :- 241 json_write(Out, Term, Options).
term
(default) to generate a classical Prolog
term or dict
to exploit the SWI-Prolog version 7 data type
extensions. See json_read_dict/3.260http_read_json(Request, JSON) :- 261 http_read_json(Request, JSON, []). 262 263http_read_json(Request, JSON, Options) :- 264 select_option(content_type(Type), Options, Rest), 265 !, 266 delete(Request, content_type(_), Request2), 267 request_to_json([content_type(Type)|Request2], JSON, Rest). 268http_read_json(Request, JSON, Options) :- 269 request_to_json(Request, JSON, Options). 270 271request_to_json(Request, JSON, Options) :- 272 option(method(Method), Request), 273 option(content_type(Type), Request), 274 ( data_method(Method) 275 -> true 276 ; domain_error(method, Method) 277 ), 278 ( is_json_type(Type) 279 -> true 280 ; domain_error(mimetype, Type) 281 ), 282 http_read_data(Request, JSON, Options). 283 284data_method(post). 285data_method(put). 286data_method(patch). 287 288:- if(current_predicate(is_dict/1)).
296http_read_json_dict(Request, Dict) :- 297 http_read_json_dict(Request, Dict, []). 298 299http_read_json_dict(Request, Dict, Options) :- 300 merge_options([json_object(dict)], Options, Options1), 301 http_read_json(Request, Dict, Options1). 302 303:- endif.
Content-type
is application/json;
charset=UTF8
. charset=UTF8
should not be required
because JSON is defined to be UTF-8 encoded, but some
clients insist on it.term
(classical json representation) or dict
to use the new dict representation. If omitted and Term
is a dict, dict
is assumed. SWI-Prolog Version 7.327:- if(current_predicate(is_dict/1)). 328reply_json(Dict) :- 329 is_dict(Dict), 330 !, 331 reply_json_dict(Dict). 332:- endif. 333reply_json(Term) :- 334 format('Content-type: application/json; charset=UTF-8~n~n'), 335 json_write(current_output, Term). 336 337:- if(current_predicate(is_dict/1)). 338reply_json(Dict, Options) :- 339 is_dict(Dict), 340 !, 341 reply_json_dict(Dict, Options). 342:- endif. 343reply_json(Term, Options) :- 344 reply_json2(Term, Options).
355:- if(current_predicate(is_dict/1)). 356reply_json_dict(Dict) :- 357 format('Content-type: application/json; charset=UTF-8~n~n'), 358 json_write_dict(current_output, Dict). 359 360reply_json_dict(Dict, Options) :- 361 merge_options([json_object(dict)], Options, Options1), 362 reply_json2(Dict, Options1). 363:- endif. 364 365 366reply_json2(Term, Options) :- 367 select_option(content_type(Type), Options, Rest0, 'application/json'), 368 ( select_option(status(Code), Rest0, Rest) 369 -> format('Status: ~d~n', [Code]) 370 ; Rest = Rest0 371 ), 372 format('Content-type: ~w~n~n', [Type]), 373 json_write_to(current_output, Term, Rest)
HTTP JSON Plugin module
This module inserts the JSON parser for documents of MIME type
application/jsonrequest
andapplication/json
requested through thehttp_client.pl
library.Typically JSON is used by Prolog HTTP servers. This module supports two JSON representations: the classical representation and the new representation supported by the SWI-Prolog version 7 extended data types. Below is a skeleton for handling a JSON request, answering in JSON using the classical interface.
When using dicts, the conversion step is generally not needed and the code becomes:
This module also integrates JSON support into the http client provided by
http_client.pl
. Posting a JSON query and processing the JSON reply (or any other reply understood by http_read_data/3) is as simple as below, where Term is a JSON term as described injson.pl
and reply is of the same format if the server replies with JSON.json.pl
describes how JSON objects are represented in Prolog terms.json_convert.pl
converts between more natural Prolog terms and json terms. */