elixir-soap / soap Goto Github PK
View Code? Open in Web Editor NEWSOAP client for Elixir programming language
License: MIT License
SOAP client for Elixir programming language
License: MIT License
Hi, I'm working with soap for the first time and struggling building a request with this library.
I need my request to have a specific namespace to work.
It should look like this:
<SOAP-ENV:Body>
<ns1:PingRequest xmlns:ns1="http://www.abacus.ch/abaconnect/2007.10/core/AbaConnectTypes">
<ns1:Echo>Hello</ns1:Echo>
</ns1:PingRequest>
</SOAP-ENV:Body>
But what I currently get is:
<SOAP-ENV:Body>
<PingRequest>
<Echo>Hello</Echo>
</PingRequest>
</SOAP-ENV:Body>
How can I add the ns1
namespace?
I attached the WSDL file.
Customer.zip
Currently parse_from_url
is using .get!
, causing an exception if the API call fails. It would be easier to handle these scenarios if an error type was returned instead, eg {:error, error}
. I'm happy to take a stab at this in a PR.
def parse_from_url(path, opts \\ []) do
request_opts = Keyword.merge([follow_redirect: true, max_redirect: 5], opts)
%HTTPoison.Response{body: wsdl} = HTTPoison.get!(path, [], request_opts)
parse(wsdl, path, opts)
end
At the moment we have very poor documentation.
It is required to add detailed documentation of all modules and publish it on https://hexdocs.pm
This will help other developers use and contribute to this library
The function returns a list of all actions that can be called from the passed wsdl
{:ok, wsdl} = Soap.init_model("wsdl_path")
SOAP.operations(wsdl)
["sendMessage", ...]
sweet_xml
0.7 was released in July 2021. There are already some libraries like ex_aws
that specify sweet_xml ~> 0.7
in their dependencies, which results in an error when ex_aws
and soap
are used together.
The function spec for Soap.call/4
specifies that the params argument has the type map. In reality, Request.call/4
has the params type as any()
. This results in the following linting error, when we supply {%{}, params}
as the params value, which is valid.
The function call will not succeed.
Soap.call(
any(),
<<84, 114, 97, 99, [107], 66, 121, 65, 105, 114, 98, 105, 108>>,
{%{}, %{<<_::80, _::size(24)>> => _}},
[],
[{:ssl, [{atom(), _}, ...]}, ...]
)
breaks the contract
(wsdl :: map(), operation :: String.t(), params :: map(), headers :: any(), opts :: any()) ::
any()
I believe here's the change that introduced this issue.
c222fd1#diff-bb4eb1a45d57965da347a74dbbf2d7018a13203a09b8a53e0f5bc46b80895763R36
minOccurs
and maxOccurs
I have a WSDL of a SOAP service I need to talk to, but when trying to build a client with it it crashes. The stack trace is so deep I really can't figure out what is going on (maybe this is a SweetXML bug?), but maybe you can take a look? This is Elixir 1.7.3.
WSDL
http://vinsearch.eurotaxglass.com/vin-intl/?wsdl
Error:
test/inventory/autovista_test.exs:14
** (Protocol.UndefinedError) protocol Enumerable not implemented for nil. This protocol is implemented for: DBConnection.PrepareStream, DBConnection.Stream, Date.Range, Ecto.Adapters.SQL.Stream, File.Stream, Function, GenEvent.Stream, HashDict, HashSet, IO.Stream, List, Map, MapSet, Postgrex.Stream, Range, Stream
code: Autovista.vin_check("WVWZZZ3CZCE116344")
stacktrace:
(elixir) /Users/michel/.kiex/builds/elixir-git/lib/elixir/lib/enum.ex:1: Enumerable.impl_for!/1
(elixir) /Users/michel/.kiex/builds/elixir-git/lib/elixir/lib/enum.ex:141: Enumerable.reduce/3
(elixir) lib/stream.ex:933: Stream.do_enum_transform/7
(elixir) lib/stream.ex:857: Stream.do_transform/5
(sweet_xml) lib/sweet_xml.ex:582: anonymous fn/4 in SweetXml.continuation_opts/2
(xmerl) xmerl_scan.erl:568: :xmerl_scan.scan_document/2
(xmerl) xmerl_scan.erl:291: :xmerl_scan.string/2
(sweet_xml) lib/sweet_xml.ex:237: SweetXml.parse/2
(sweet_xml) lib/sweet_xml.ex:421: SweetXml.xpath/2
(sweet_xml) lib/sweet_xml.ex:531: anonymous fn/3 in SweetXml.xmap/3
(elixir) lib/map.ex:791: Map.get_and_update/3
(sweet_xml) lib/sweet_xml.ex:531: SweetXml.xmap/3
(sweet_xml) lib/sweet_xml.ex:530: SweetXml.xmap/3
(soap) lib/soap/wsdl.ex:32: Soap.Wsdl.parse/2
When I try to use any actions from my WSDL file the namespace is missing from the request, thus resulting in an invalid request.
It should look like this:
<env:Body>
<login xmlns:ns1="http://www.abacus.ch/abaconnect/2007.10/core/AbaConnectTypes">
<ns1:UserLogin>
<ns1:Mandant>1</ns1:Mandant>
<ns1:Password>pass</ns1:Password>
<ns1:UserName>user</ns1:UserName>
</ns1:UserLogin>
</login>
</env:Body>
But what I currently get is:
<env:Body>
<login>
<UserLogin>
<Mandant>1</Mandant>
<Password>pass</Password>
<UserName>user</UserName>
</UserLogin>
</login>
</env:Body>
This is my code:
{:ok, wsdl} = Soap.init_model("wsdl/Customer.wsdl", :file)
params = %{
UserLogin: %{
Mandant: "1",
Password: "pass",
UserName: "user"
}
}
{:ok, response} = Soap.call(wsdl, "login", params)
Is this a problem with my wsdl or is it not being added by the lib?
Here is my wsdl
and the xsd
s
wsdl.zip
Trying to parse de following wsdl file
ws-rca-dev.24broker.ro.xml.txt
I get all lists empty
{:ok,
%{
complex_types: [],
endpoint: "",
messages: [],
namespaces: %{},
operations: [],
schema_attributes: %{
element_form_default: "",
target_namespace: "http://ws-rca-dev.24broker.ro/wsrca"
},
soap_version: "1.1",
validation_types: %{}
}}
Do you have an hints for me?
Hi,
I need to configure HTTPoison in Soap.init_model(_, :url) to have a :recv_timeout bigger than the default (5s). Is possible to expose the configuration in some way? Thanks!
Hi,
My company is building mobile services with Elixir. We need a way to talk to a SOAP api. We tried erlang libs, but they all fail to parse the wsdl of the services we need. We tried your lib, but as is written in the README it is not production ready (and doesn't work).
We don't have very good knowledge of soap, but we may be ready to pay for a bit of development service in order to get a soap lib that works with our service.
Here is one of the problematic wsdl files if you want to have a look:
api.wsdl.txt
Would it be possible to discuss something on that subject?
for fix this error . before using soap
** (ArgumentError) could not fetch application environment :globals for application :soap because configuration :globals was not set
(elixir) lib/application.ex:349: Application.fetch_env!/2
(soap) lib/soap/wsdl.ex:120: Soap.Wsdl.soap_version/0
(soap) lib/soap/wsdl.ex:83: Soap.Wsdl.get_operations/1
(soap) lib/soap/wsdl.ex:28: Soap.Wsdl.parse/1
set below config in config.exs
config :soap, :globals,
version: 1.2
Hi,
thanks for SOAP library for Elixir. I just tried to init WSDL and I discovered that all xpaths like:
//#{protocol_ns}:types/xsd:schema/xsd:complexType
expect protocol_ns to have a value. When SOAP is a default namespace, then protocol_ns == [] and all xpaths fail.
I can help with this one if you like.
when using OTP 26, 3 tests fail
1) test string type params can be all digits (Soap.Request.ParamsTest)
test/soap/request/params_test.exs:47
Assertion with == failed
code: assert function_result == xml_body
left: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:tns=\"com.esendex.ems.soapinterface\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><env:Header/><env:Body><tns:sendMessage xmlns=\"com.esendex.ems.soapinterface\"><type>TYPE</type><date>2018-01-19</date><body>BODY</body><recipient>123</recipient></tns:sendMessage></env:Body></env:Envelope>"
right: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:tns=\"com.esendex.ems.soapinterface\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><env:Header/><env:Body><tns:sendMessage xmlns=\"com.esendex.ems.soapinterface\"><body>BODY</body><date>2018-01-19</date><recipient>123</recipient><type>TYPE</type></tns:sendMessage></env:Body></env:Envelope>"
stacktrace:
test/soap/request/params_test.exs:56: (test)
2) test #build_body converts map to Xml-like string successful (Soap.Request.ParamsTest)
test/soap/request/params_test.exs:9
Assertion with == failed
code: assert function_result == xml_body
left: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:tns=\"com.esendex.ems.soapinterface\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><env:Header/><env:Body><tns:sendMessage xmlns=\"com.esendex.ems.soapinterface\"><type>TYPE</type><date>2018-01-19</date><body>BODY</body><recipient>WSPB</recipient></tns:sendMessage></env:Body></env:Envelope>"
right: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:tns=\"com.esendex.ems.soapinterface\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><env:Header/><env:Body><tns:sendMessage xmlns=\"com.esendex.ems.soapinterface\"><body>BODY</body><date>2018-01-19</date><recipient>WSPB</recipient><type>TYPE</type></tns:sendMessage></env:Body></env:Envelope>"
stacktrace:
test/soap/request/params_test.exs:15: (test)
3) test #build_body uses the custom WSDL SOAP version (Soap.Request.ParamsTest)
test/soap/request/params_test.exs:18
Assertion with == failed
code: assert function_result == xml_body
left: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><env:Envelope xmlns:env=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:tns=\"com.esendex.ems.soapinterface\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><env:Header/><env:Body><tns:sendMessage xmlns=\"com.esendex.ems.soapinterface\"><type>TYPE</type><date>2018-01-19</date><body>BODY</body><recipient>WSPB</recipient></tns:sendMessage></env:Body></env:Envelope>"
right: "<?xml version=\"1.0\" encoding=\"UTF-8\"?><env:Envelope xmlns:env=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:tns=\"com.esendex.ems.soapinterface\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><env:Header/><env:Body><tns:sendMessage xmlns=\"com.esendex.ems.soapinterface\"><body>BODY</body><date>2018-01-19</date><recipient>WSPB</recipient><type>TYPE</type></tns:sendMessage></env:Body></env:Envelope>"
stacktrace:
test/soap/request/params_test.exs:24: (test)
It may be caused by OTP 26 no longer guarantees that maps are ordered
Hi there,
With Elixir 1.9.1 I couldn't go further instead I receive this error: "(ArgumentError) could not fetch application environment :globals for application :soap because configuration :globals was not set"
I tried creating a config/config.exs
import Config
config :soap, :globals, version: "1.1"
import_config "#{config_env()}.exs"
And mix.exs file is as follows;
defmodule Countryinfoserv.MixProject do
use Mix.Project
def project do
[
app: :countryinfoserv,
version: "0.1.0",
elixir: "~> 1.9",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger, :soap]
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
{:soap, "~> 1.0"}
]
end
end
Hello, please use this WSDL link http://banktest.ir/gateway/saman/Payments/InitPayment?wsdl
elixir: v1.8.0 , {:soap, "~> 1.0.1"}
defmodule Khatoghalam.Extera.Bank.Saman do
def get_saman_token do
wsdl_url = "http://banktest.ir/gateway/saman/Payments/InitPayment?wsdl"
with {:ok, wsdl} <- Soap.init_model(wsdl_url, :url) do
IO.inspect(wsdl)
else
nil -> {:unknown_error}
_ -> {:unknown_error}
end
end
end
** (Protocol.UndefinedError) protocol Enumerable not implemented for nil. This protocol is implemented for: Ecto.Adapters.SQL.Stream, Postgrex.Stream, DBConnection.Stream, DBConnection.PrepareStream, Scrivener.Page, HashSet, Range, Map, Function, List, Stream, Date.Range, HashDict, GenEvent.Stream, MapSet, File.Stream, IO.Stream
(elixir) /private/tmp/elixir-20190114-93661-1hq8sk/elixir-1.8.0/lib/elixir/lib/enum.ex:1: Enumerable.impl_for!/1
(elixir) /private/tmp/elixir-20190114-93661-1hq8sk/elixir-1.8.0/lib/elixir/lib/enum.ex:141: Enumerable.reduce/3
(elixir) lib/stream.ex:936: Stream.do_enum_transform/7
(elixir) lib/stream.ex:860: Stream.do_transform/5
(sweet_xml) lib/sweet_xml.ex:582: anonymous fn/4 in SweetXml.continuation_opts/2
(xmerl) xmerl_scan.erl:568: :xmerl_scan.scan_document/2
(xmerl) xmerl_scan.erl:291: :xmerl_scan.string/2
(sweet_xml) lib/sweet_xml.ex:237: SweetXml.parse/2
(sweet_xml) lib/sweet_xml.ex:421: SweetXml.xpath/2
(sweet_xml) lib/sweet_xml.ex:531: anonymous fn/3 in SweetXml.xmap/3
(elixir) lib/map.ex:791: Map.get_and_update/3
(sweet_xml) lib/sweet_xml.ex:531: SweetXml.xmap/3
(sweet_xml) lib/sweet_xml.ex:530: SweetXml.xmap/3
(soap) lib/soap/wsdl.ex:37: Soap.Wsdl.parse/3
(khatoghalam) lib/khatoghalam/extera/bank/saman.ex:4: Khatoghalam.Extera.Bank.Saman.get_saman_token/0
How can I fix this ?
I think this def doesn't work
@spec get_schema_attributes(String.t()) :: map()
defp get_schema_attributes(wsdl) do
wsdl
|> xpath(
~x"//*[local-name() = 'schema']",
target_namespace: ~x"./@targetNamespace"s,
element_form_default: ~x"./@elementFormDefault"s
)
end
In the function Soap.Wsdl.get_soap_namespace, the function searches for one of these URLs
@soap_version_namespaces %{
"1.1" => :"http://schemas.xmlsoap.org/wsdl/soap/",
"1.2" => :"http://schemas.xmlsoap.org/wsdl/soap12/"
}
However, older WSDL files do not have any of these lines since there were only one SOAP format back then. An example is: https://schemas.xmlsoap.org/ws/2005/04/discovery/ws-discovery.wsdl
This error, in return, causes program to give timeout error:
** (HTTPoison.Error) :timeout
(httpoison 1.8.2) lib/httpoison.ex:258: HTTPoison.request!/5
(soap 1.1.0) lib/soap/wsdl.ex:23: Soap.Wsdl.parse_from_url/2
iex:3: (file)
If I hack get_soap_namespace function to return 'soap' value as hardcoded return value, things work well, wsdl is parsed correctly.
I have a wsdl url that seems to be leaving several fields empty when calling init_model
: http://services.chromedata.com:80/Description/7a?WSDL
iex> wsdl_path = "http://services.chromedata.com:80/Description/7a?WSDL"
iex> {:ok, wsdl} = Soap.init_model(wsdl_path, :url)
{:ok,
%{
complex_types: [],
endpoint: "",
messages: [],
namespaces: %{},
operations: [],
schema_attributes: %{
element_form_default: "qualified",
target_namespace: "urn:description7a.services.chrome.com"
},
soap_version: "1.1",
validation_types: %{}
}}
This is the task to start validating the response from the SOAP server
Hi, thanks for this module
When I tried to use call
I got this message
{:ok, response} = Soap.call(wsdl, "myOperation", params)
** (BadMapError) expected a map, got: nil
(elixir) lib/map.ex:437: Map.get(nil, :type, nil)
(soap) lib/soap/request/params.ex:193: Soap.Request.Params.add_action_tag_wrapper/3
(soap) lib/soap/request/params.ex:118: Soap.Request.Params.build_soap_body/3
(soap) lib/soap/request/params.ex:25: Soap.Request.Params.build_body/4
(soap) lib/soap/request.ex:17: Soap.Request.call/5
(soap) lib/soap.ex:91: Soap.call/5
what could be the problem?
Regards
Is there a way to pass attributes to elements while passing params
to Soap.call/3
?
Example XML to generate:
<Person gender="male">
<FirstName>Some</FirstName>
<LastName>Name</LastName>
</Person>
Blocked #14
If the user calls a non-existent SOAP action in current wsdl, the library response a meaningful error that there is no such action and a command for viewing all available action.
Example:
Soap.call(wsdl, "NonExistAction", %{}]})
** (ActionError) "NonExistAction" action is not described in this wsdl file.
Use SOAP.operations (wsdl) to list all available actions
The API that we need to use is returning MTOM responses with bigger binary objects (> 100MB). This library currently does not allow me to communicate with it.
Hi,
do you plan to support imported schema?
Example:
<types> <xsd:schema> <xsd:import namespace="http://domain.com/" schemaLocation="https://domain.com/services?xsd=1"/> </xsd:schema> </types>
Thanks!
Hello, when I try to install this , I have an error like this:
โ mix deps.get
Resolving Hex dependencies...
Failed to use "httpoison" (version 1.3.0) because
soap (version 0.1.1) requires ~> 0.13
mix.lock specifies 1.3.0
** (Mix) Hex dependency resolution failed, change the version requirements of your dependencies or unlock them (by using mix deps.update or mix deps.unlock). If you are unable to resolve the conflicts you can try overriding with {:dependency, "~> 1.0", override: true}
how can I fix this ?
Thanks
I saw the previously opened issue #38
Which mentions passing entity attribute params to Soap.call/3
I am unable to to do this with 1.0.1, has this been implemented? Is it still TBD?
Hi,
we waited for your release and tried 1.0.1. We still have problems with your library.
Here is our wsdl file
api.wsdl.txt
When we parse it no operations are found, and therefore we can't call any action:
Erlang/OTP 21 [erts-10.2.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]
Interactive Elixir (1.7.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {:ok, wsdl} = Soap.init_model("api.wsdl.xml", :file)
{:ok,
%{
(... very long output...)
}}
iex(2)> Soap.operations(wsdl)
[]
iex(3)>
Obviously, operations should not be empty.
XSD support custom data types, like these:
<xsd:simpleType name="WSTypeChar2048">
<xsd:restriction base="xsd:string">
<xsd:maxLength value="2048"/>
</xsd:restriction>
</xsd:simpleType>
We must parse them and validate passed native data types
This is the task for receiving a response body parsed into elixirs map
Hi,
the params in the call, are defined in the documentation as: %{key: value},
if i need define map into map,is accepted as valid params?
i try, but i get a error
example:%{key: value, key2: %{key3: value}}
Soap.Wsdl.parse/1
Soap.request.build_headers/2
I'm not sure if this happens for other WSDLs but when loading a WSDL via :url
and it contains schema imports, the code tries to combine the full schema url with the path
resulting in a broken URL.
Lines 130 to 135 in f383095
I believe the fix would be to check if the schema_location
has a scheme and return that if it does but I do not know all of the different possible cases.
@spec get_full_paths(String.t(), String.t(), String.t(), String.t()) :: list(String.t())
defp get_full_paths(wsdl, path, protocol_ns, schema_namespace) do
wsdl
|> get_schema_imports(protocol_ns, schema_namespace)
|> Enum.map(& resolve_schema_imports(path, &1.schema_location))
end
defp resolve_schema_imports(path, location) do
if URI.parse(location).scheme do
location
else
path
|> Path.dirname()
|> Path.join(location)
end
end
I've tried this locally and it worked with :url
and :file
.
Downloading the WSDL and loading it via :file
is a workaround for now.
First of all, thank you for this library!
I spotted an odd behaviour recently, though.
Parsing Salesforce Metadata WSDL (https://raw.githubusercontent.com/developerforce/Force.com-Toolkit-for-PHP/master/soapclient/metadata.wsdl.xml) gives pretty much data, but a list of available operations is empty.
This seems to be incorrect. The same file parsed with Ruby's wasabi
SOAP library gives a correct list.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.