Daniel@0: /* Part of DML (Digital Music Laboratory) Daniel@0: Copyright 2014-2015 Samer Abdallah, University of London Daniel@0: Daniel@0: This program is free software; you can redistribute it and/or Daniel@0: modify it under the terms of the GNU General Public License Daniel@0: as published by the Free Software Foundation; either version 2 Daniel@0: of the License, or (at your option) any later version. Daniel@0: Daniel@0: This program is distributed in the hope that it will be useful, Daniel@0: but WITHOUT ANY WARRANTY; without even the implied warranty of Daniel@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Daniel@0: GNU General Public License for more details. Daniel@0: Daniel@0: You should have received a copy of the GNU General Public Daniel@0: License along with this library; if not, write to the Free Software Daniel@0: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Daniel@0: */ Daniel@0: Daniel@0: :- module(webby, Daniel@0: [ webcall/3 Daniel@0: , restcall/4 Daniel@0: , parts_path/2 Daniel@0: , http_status/2 Daniel@0: ]). Daniel@0: /** Web API tools Daniel@0: Daniel@0: ---+++ Types Daniel@0: == Daniel@0: web_reader ---> json(-D:dict) Daniel@0: ; nil. Daniel@0: Daniel@0: web_method ---> get(+Params:list(param)) Daniel@0: ; post(+D:post_data) Daniel@0: ; put(+D:post_data) Daniel@0: ; delete(+D:post_data) Daniel@0: . Daniel@0: Daniel@0: post_data ---> form(list(param)) Daniel@0: ; json(dict) Daniel@0: . Daniel@0: Daniel@0: param ---> atom=_. Daniel@0: == Daniel@0: */ Daniel@0: Daniel@0: :- multifile read_reply/2. Daniel@0: Daniel@0: :- use_module(library(http/http_open)). Daniel@0: :- use_module(library(http/http_header)). Daniel@0: :- use_module(library(http/json)). Daniel@0: Daniel@0: parts_path(Parts,Path) :- Daniel@0: atomics_to_string([''|Parts],"/",Path). Daniel@0: Daniel@0: %% webcall(+URL:url_spec, +Opt:options, +R:web_reader) is det. Daniel@0: webcall(URL,Opts,Reader) :- Daniel@0: debug(webby,"HTTP connecting to ~w, ~w",[URL,Opts]), Daniel@0: setup_call_cleanup( Daniel@0: http_open(URL,In,[status_code(SC)|Opts]), Daniel@0: ( set_stream(In,encoding(utf8)), % ! Daniel@0: ( between(200,299,SC) -> read_reply(Reader,In) Daniel@0: ; read_stream_to_codes(In,ErrorDoc), Daniel@0: throw(http_bad_status(SC,codes(ErrorDoc))))), Daniel@0: close(In)). Daniel@0: Daniel@0: read_reply(json(Dict),In) :- json_read_dict(In,Dict). Daniel@0: read_reply(nil,_). Daniel@0: Daniel@0: %% post_data(+D:post_data,-D2:post_data) is det. Daniel@0: post_data(json(Dict),codes('application/json',Codes)) :- !, atom_json_dict(Codes,Dict,[as(codes)]). Daniel@0: post_data(Data,Data). Daniel@0: Daniel@0: %% restcall(+M:web_method, +R:web_reader, +URL:url_spec, +Opts:options) is det. Daniel@0: restcall(get(Params), Rdr, URL, Opts) :- webcall([search(Params)|URL], Opts, Rdr). Daniel@0: restcall(post(D), Rdr, URL, Opts) :- post_data(D,Data), webcall(URL, [method(post),post(Data)|Opts], Rdr). Daniel@0: restcall(delete(D), Rdr, URL, Opts) :- post_data(D,Data), webcall(URL, [method(delete),post(Data)|Opts], Rdr). Daniel@0: restcall(put(D), Rdr, URL, Opts) :- post_data(D,Data), webcall(URL, [method(put),post(Data)|Opts], Rdr). Daniel@0: Daniel@0: status_meaning(200,"OK"). Daniel@0: status_meaning(201,"Created"). Daniel@0: status_meaning(204,"No content"). Daniel@0: status_meaning(304,"Not modified"). Daniel@0: status_meaning(400,"Bad request"). Daniel@0: status_meaning(401,"Unauthorised"). Daniel@0: status_meaning(403,"Forbidden"). Daniel@0: status_meaning(404,"Not found"). Daniel@0: status_meaning(405,"Method not allowed"). Daniel@0: status_meaning(429,"Too many requests"). Daniel@0: status_meaning(500,"Internal server error"). Daniel@0: status_meaning(502,"Bad gateway"). Daniel@0: status_meaning(503,"Service unavailable"). Daniel@0: Daniel@0: http_status(Code,Meaning) :- status_meaning(Code,Meaning), !. Daniel@0: http_status(_,""). Daniel@0: Daniel@0: prolog:message(http_bad_status(SC,codes(Doc))) --> Daniel@0: {http_status(SC,Meaning)}, Daniel@0: ["HTTP call returned status ~w (~w)."-[SC,Meaning]], Daniel@0: ["Reply document was |~s|"-[Doc]].