You can call a web service from PL/SQL using the Oracle-supplied package UTL_HTTP. Here’s a demo of calling a public web service that returns latest city weather by ZIP.
A PL/SQL script to invoke a web service, followed by its execution…
Call a web service from PL/SQL using UTL_HTTP
PL/SQL script that invokes the web service to get latest weather, then reads the response into a CLOB variable. The response can later be converted to XMLType and the values can be extracted using XMLTable.
declare -- String that holds the HTTP request string soap_request varchar2(32767); -- PL/SQL record to represent an HTTP request, -- as returned from the call to begin_request http_req utl_http.req; -- PL/SQL record to represent the output of -- get_response http_resp utl_http.resp; -- HTTP version that can be used in begin_request: 1.0 or 1.1 t_http_version varchar2(10) := 'HTTP/1.1'; t_content_type varchar2(50) := 'text/xml; charset=utf-8'; -- URL of the HTTP request, set after begin_request. t_url varchar2(100) := 'wsf.cdyne.com/WeatherWS/Weather.asmx'; -- Variables to handle the web service response x_clob CLOB; l_buffer VARCHAR2(32767); -- US city ZIP for which the weather data has -- to be fetched via web service l_zip varchar2(10) := '10007'; begin dbms_output.put_line('ZIP: ' || l_zip ); -- Build the HTTP soap request soap_request := '<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <GetCityWeatherByZIP xmlns="http://ws.cdyne.com/WeatherWS/"> <ZIP>' || l_zip || '</ZIP> </GetCityWeatherByZIP> </soap:Body> </soap:Envelope>'; -- Begin a new HTTP request: establish the network -- connection to the target web server or proxy -- server and send the HTTP request line. http_req := utl_http.begin_request(t_url , 'POST' -- method , t_http_version); -- Set HTTP request header attributes. The -- request header is sent to the web server -- as soon as it is set. utl_http.set_header(http_req , 'Content-Type', t_content_type); utl_http.set_header(http_req , 'Content-Length' , length(soap_request)); utl_http.set_header(http_req , 'SOAPAction' , '"http://ws.cdyne.com/WeatherWS/GetCityWeatherByZIP"'); -- Write soap request text data in the HTTP request utl_http.write_text(http_req, soap_request); -- get_response output of record type utl_http.resp. -- http_resp contains a 3-digit status_code, a -- reason_phrase and HTTP version. http_resp := utl_http.get_response(http_req); -- Build a CLOB variable to hold web service response dbms_lob.createtemporary(x_clob, FALSE ); dbms_lob.open( x_clob, dbms_lob.lob_readwrite ); begin loop -- Copy the web service response body -- in a buffer string variable l_buffer utl_http.read_text(http_resp, l_buffer); -- Append data from l_buffer to CLOB variable dbms_lob.writeappend(x_clob , length(l_buffer) , l_buffer); end loop; exception when others then -- Exit loop without exception -- when end-of-body is reached if sqlcode <> -29266 then raise; end if; end; -- Verify the response status and text dbms_output.put_line('Response Status: ' ||http_resp.status_code ||' ' || http_resp.reason_phrase); dbms_output.put_line('Response XML:' || cast(x_clob as varchar2)); utl_http.end_response(http_resp) ; -- x_clob response can now be used for extracting text -- values from specific XML nodes, using XMLExtract end; /
Execution of PL/SQL Script Using UTL_HTTP
When the above script is run, this is what happens:
SQL> declare 2 -- String that holds the HTTP request string 3 soap_request varchar2(32767); 4 5 -- PL/SQL record to represent an HTTP request, 6 -- as returned from the call to begin_request 7 http_req utl_http.req; 8 9 -- PL/SQL record to represent the output of 10 -- get_response 11 http_resp utl_http.resp; 12 13 -- HTTP version that can be used in begin_request: 1.0 or 1.1 14 t_http_version varchar2(10) := 'HTTP/1.1'; 15 16 t_content_type varchar2(50) := 'text/xml; charset=utf-8'; 17 18 -- URL of the HTTP request, set after begin_request. 19 t_url varchar2(100) := 'wsf.cdyne.com/WeatherWS/Weather.asmx'; 20 21 -- Variables to handle the web service response 22 x_clob CLOB; 23 l_buffer VARCHAR2(32767); 24 25 -- US city ZIP for which the weather data has 26 -- to be fetched via web service 27 l_zip varchar2(10) := '10007'; 28 29 begin 30 31 dbms_output.put_line('ZIP: ' || l_zip ); 32 33 -- Build the HTTP soap request 34 soap_request := '<?xml version="1.0" encoding="utf-8"?> 35 <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 36 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 37 <soap:Body> 38 <GetCityWeatherByZIP xmlns="http://ws.cdyne.com/WeatherWS/"> 39 <ZIP>' || l_zip || '</ZIP> 40 </GetCityWeatherByZIP> 41 </soap:Body> 42 </soap:Envelope>'; 43 44 -- Begin a new HTTP request: establish the network 45 -- connection to the target web server or proxy 46 -- server and send the HTTP request line. 47 http_req := utl_http.begin_request(t_url 48 , 'POST' -- method 49 , t_http_version); 50 51 -- Set HTTP request header attributes. The 52 -- request header is sent to the web server 53 -- as soon as it is set. 54 utl_http.set_header(http_req 55 , 'Content-Type', t_content_type); 56 utl_http.set_header(http_req 57 , 'Content-Length' 58 , length(soap_request)); 59 utl_http.set_header(http_req 60 , 'SOAPAction' 61 , '"http://ws.cdyne.com/WeatherWS/GetCityWeatherByZIP"'); 62 63 -- Write soap request text data in the HTTP request 64 utl_http.write_text(http_req, soap_request); 65 66 -- get_response output of record type utl_http.resp. 67 -- http_resp contains a 3-digit status_code, a 68 -- reason_phrase and HTTP version. 69 http_resp := utl_http.get_response(http_req); 70 71 -- Build a CLOB variable to hold web service response 72 dbms_lob.createtemporary(x_clob, FALSE ); 73 dbms_lob.open( x_clob, dbms_lob.lob_readwrite ); 74 75 begin 76 77 loop 78 -- Copy the web service response body 79 -- in a buffer string variable l_buffer 80 utl_http.read_text(http_resp, l_buffer); 81 82 -- Append data from l_buffer to CLOB variable 83 dbms_lob.writeappend(x_clob 84 , length(l_buffer) 85 , l_buffer); 86 end loop; 87 88 exception 89 when others then 90 -- Exit loop without exception 91 -- when end-of-body is reached 92 if sqlcode <> -29266 then 93 raise; 94 end if; 95 end; 96 97 -- Verify the response status and text 98 dbms_output.put_line('Response Status: ' 99 ||http_resp.status_code 100 ||' ' || http_resp.reason_phrase); 101 dbms_output.put_line('Response XML:' 102 || cast(x_clob as varchar2)); 103 104 utl_http.end_response(http_resp) ; 105 106 -- x_clob response can now be used for extracting text 107 -- values from specific XML nodes, using XMLExtract 108 end; 109 / ZIP: 10007 Response Status: 200 OK Response XML:<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetCityWeatherByZIPResp onse xmlns="http://ws.cdyne.com/WeatherWS/"><GetCityWeatherByZIPResult><Success>true< /Success><ResponseText>City Found</ResponseText><State>NY</State><City>New York</City><WeatherStationCity>White Plains</WeatherStationCity><WeatherID>15</WeatherID><Description>N/A</Descriptio n><Temperature>63</Temperature><RelativeHumidity>87</RelativeHumidity><Wind>E7</ Wind><Pressure>29.97S</Pressure><Visibility /><WindChill /><Remarks /></GetCityWeatherByZIPResult></GetCityWeatherByZIPResponse></soap:Body></soap:E nvelope> PL/SQL procedure successfully completed.
A response status of 200 OK indicates that the request has succeeded. The response XML shows the weather details for the input ZIP.
Possible Errors in UTL_HTTP Call
A few errors you might encounter when using UTL_HTTP, and their possible causes.
PLS-00201: identifier ‘UTL_HTTP’ must be declared
You will see the above error when the database user (say [utluser]) executing the PL/SQL code does not have execute permission on UTL_HTTP.
To resolve the error, login as SYS or SYSTEM, and provide the execute permission.
grant execute on sys.utl_http to [utluser];
Log back again as [utluser] and run the PL/SQL code again. It should work this time.
ORA-29273: HTTP request failed or ORA-12535: TNS:operation timed out
This suggests a connection error. Are you behind a firewall or is the web service down? From command prompt, ping the server and verify.
You will receive a response of this form if the connectivity is fine:
Pinging ws.cdyne.com [4.59.146.110] with 32 bytes of data:
Reply from 4.59.146.110: bytes=32 time=269ms TTL=120
Reply from 4.59.146.110: bytes=32 time=275ms TTL=120
Reply from 4.59.146.110: bytes=32 time=259ms TTL=120
Reply from 4.59.146.110: bytes=32 time=272ms TTL=120
Ping statistics for 4.59.146.110:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 259ms, Maximum = 275ms, Average = 268ms
You will receive a response of this form if the connectivity is not OK:
[Pinging ws.cdyne.com [4.59.146.110] with 32 bytes of data:
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Ping statistics for 87.106.3.248:
Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),
In the second case, test the PL/SQL from outside the firewall or ensure that the web service is up.
ORA-24247: network access denied by access control list (ACL)
This error indicates that an essential piece of security setup – ACL configuration – is missing. Look up Access Control List for details on what ACL is and how to set it up.
For Further Reading
Oracle 10G documentation on UTL_HTTP
PSOUG on UTL_HTTP
Keep the Response Body with non-2xx Responses in UTL_HTTP
{ 5 comments… read them below or add one }
Excellent Posting…
Thank you best written article on calling web service from PL/SQL I have found on the internet.
thansk man for posting
Could you please show an example of how to POST .xml file that is larger than varchar2(32767)
Hi,
I got the following error
ORA-12545: Connect failed because target host or object does not exist