soap

package module
v0.27.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 25, 2025 License: MIT Imports: 16 Imported by: 0

README

SOAP Go

PkgGoDev GoReportCard CI

A Go SDK and CLI tool for SOAP web services.

Features

  • Support for SOAP 1.1, WSDL 1.1, and XSD 1.0
  • Code generation from WSDL files
  • Documentation generation

Developing

See AGENTS.md.

CLI tool

The soap CLI tool can generate code, documentation, and call SOAP APIs on the fly.

$ soap

  Multi-tool for SOAP APIs

  USAGE

    soap [command] [--flags]  

  CODE GENERATION

    gen [--flags]         Generate code for a SOAP API

  DOCUMENTATION

    doc [--flags]         Display documentation for a SOAP API

  NETWORK OPERATIONS

    call [--flags]        Call a SOAP action

  UTILS

    completion [command]  Generate the autocompletion script for the specified shell
    help [command]        Help about any command

  FLAGS

    -h --help             Help for soap
    -v --version          Version for soap
Installing
go install github.com/way-platform/soap-go/cmd/soap@latest

Prebuilt binaries for Linux, Windows, and Mac are available from the Releases.

License

This SDK is published under the MIT License.

Security

Security researchers, see the Security Policy.

Code of Conduct

Be nice. For more info, see the Code of Conduct.

Documentation

Overview

Package soap provides primitives for SOAP (Simple Object Access Protocol).

Index

Examples

Constants

View Source
const Namespace = "http://schemas.xmlsoap.org/soap/envelope/"

Namespace is the standard SOAP 1.1 envelope namespace

Variables

This section is empty.

Functions

func DefaultCheckRetry added in v0.27.0

func DefaultCheckRetry(err error, request *http.Request, response *http.Response) bool

DefaultCheckRetry implements the default retry logic for HTTP requests.

Types

type Body added in v0.21.0

type Body struct {
	XMLName xml.Name

	// Content as raw XML for maximum flexibility
	// This allows both simple payloads and complex nested structures
	Content []byte `xml:",innerxml"`

	// Additional attributes for extensibility
	Attrs []xml.Attr `xml:",any,attr"`
}

Body represents a SOAP body containing the main message payload. As per SOAP 1.1 spec section 4.3, it contains body entries.

type Client added in v0.22.0

type Client struct {
	// contains filtered or unexported fields
}

Client represents a generic SOAP HTTP client that can handle any type of SOAP request. It works with Envelope types and provides a clean abstraction over HTTP transport.

func NewClient added in v0.22.0

func NewClient(opts ...ClientOption) (*Client, error)

NewClient creates a new SOAP client with the specified options. Returns an error if the configuration is invalid.

func (*Client) Call added in v0.22.0

func (c *Client) Call(ctx context.Context, action string, requestEnvelope *Envelope, opts ...ClientOption) (*Envelope, error)

Call executes a SOAP request with the provided action, envelope, and call-specific options.

type ClientOption added in v0.22.0

type ClientOption func(*clientConfig)

ClientOption configures a Client using the functional options pattern. Can be used both during client creation and per-call.

func WithCheckRetry added in v0.27.0

func WithCheckRetry(checkRetry func(error, *http.Request, *http.Response) bool) ClientOption

WithCheckRetry sets a custom retry check function. If not provided, uses DefaultCheckRetry for generic HTTP retry logic.

func WithDebug added in v0.22.0

func WithDebug(debug bool) ClientOption

WithDebug enables debug mode, which will dump HTTP requests and responses to stderr. This works the same as the debug mode in the soapcall package.

func WithEndpoint added in v0.22.0

func WithEndpoint(endpoint string) ClientOption

WithEndpoint sets the default SOAP endpoint URL. This can be overridden per call if needed in the future.

func WithInterceptor added in v0.27.0

func WithInterceptor(interceptor func(http.RoundTripper) http.RoundTripper) ClientOption

WithInterceptor adds a request interceptor for the Client.

func WithMaxRetries added in v0.27.0

func WithMaxRetries(retries int) ClientOption

WithMaxRetries sets the maximum number of retries for a request. Defaults to 3.

func WithTimeout added in v0.27.0

func WithTimeout(timeout time.Duration) ClientOption

WithTimeout sets the timeout for the SOAP client.

func WithXMLDeclaration added in v0.22.0

func WithXMLDeclaration(include bool) ClientOption

WithXMLDeclaration controls whether XML declaration is automatically added to requests. Defaults to true. Set to false if your SOAP service doesn't expect or allow XML declarations.

type Detail added in v0.21.0

type Detail struct {
	// Content as raw XML to accommodate any application-specific fault data
	Content []byte `xml:",innerxml"`

	// Additional attributes for extensibility
	Attrs []xml.Attr `xml:",any,attr"`
}

Detail represents application-specific fault detail information.

type Envelope added in v0.21.0

type Envelope struct {
	XMLName xml.Name

	// Optional encoding style as per SOAP 1.1 spec section 4.1.1
	EncodingStyle string `xml:"encodingStyle,attr,omitempty"`

	// Optional header as per SOAP 1.1 spec section 4.2
	Header *Header `xml:"Header,omitempty"`

	// Mandatory body as per SOAP 1.1 spec section 4.3
	Body Body `xml:"Body"`

	// Additional attributes for extensibility as per SOAP 1.1 spec section 4.1
	Attrs []xml.Attr `xml:",any,attr"`
}

Envelope represents a SOAP envelope with flexible namespace support. It can handle any namespace prefix and URI, making it compatible with various SOAP implementations. The XMLName field determines the actual element name and namespace used in marshaling/unmarshaling.

Example (Basic)

ExampleEnvelope_basic demonstrates creating a basic SOAP envelope with just a body.

// Create a simple SOAP envelope using the new API
envelope, err := soap.NewEnvelope(soap.WithBody([]byte(`<GetWeather><city>London</city></GetWeather>`)))
if err != nil {
	log.Fatal(err)
}
xmlData, err := xml.MarshalIndent(envelope, "", "  ")
if err != nil {
	log.Fatal(err)
}
fmt.Println(string(xmlData))
Output:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body><GetWeather><city>London</city></GetWeather></soapenv:Body>
</soapenv:Envelope>
Example (Extensibility)

ExampleEnvelope_extensibility demonstrates using custom attributes for extensibility.

envelope, err := soap.NewEnvelope(soap.WithBody([]byte(`<ProcessOrder><orderId>12345</orderId></ProcessOrder>`)))
if err != nil {
	log.Fatal(err)
}

// Add custom attributes to the body for extensibility
envelope.Body.Attrs = []xml.Attr{
	{Name: xml.Name{Local: "priority"}, Value: "high"},
}

// Add custom attributes to the envelope for extensibility
envelope.Attrs = append(envelope.Attrs, []xml.Attr{
	{Name: xml.Name{Local: "version"}, Value: "1.2"},
	{Name: xml.Name{Local: "trace", Space: "http://example.com/trace"}, Value: "enabled"},
}...)

xmlData, err := xml.MarshalIndent(envelope, "", "  ")
if err != nil {
	log.Fatal(err)
}

fmt.Println(string(xmlData))
Output:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" version="1.2" xmlns:trace="http://example.com/trace" trace:trace="enabled">
  <soapenv:Body priority="high"><ProcessOrder><orderId>12345</orderId></ProcessOrder></soapenv:Body>
</soapenv:Envelope>
Example (RealWorld)

ExampleEnvelope_realWorld demonstrates creating a SOAP envelope for real-world use.

// Create a SOAP envelope for a weather service request using the new API
envelope, err := soap.NewEnvelope(soap.WithBody([]byte(`<GetTemperature xmlns="http://weather.example.com/"><city>Paris</city></GetTemperature>`)))
if err != nil {
	log.Fatal(err)
}

// Marshal to XML (this is what gets sent to SOAP services)
xmlData, err := xml.MarshalIndent(envelope, "", "  ")
if err != nil {
	log.Fatal(err)
}

fmt.Println(string(xmlData))
Output:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body><GetTemperature xmlns="http://weather.example.com/"><city>Paris</city></GetTemperature></soapenv:Body>
</soapenv:Envelope>
Example (WithEncodingStyle)

ExampleEnvelope_withEncodingStyle demonstrates setting encoding style.

envelope, err := soap.NewEnvelope(soap.WithBody([]byte(`<GetStockPrice><symbol>AAPL</symbol></GetStockPrice>`)))
if err != nil {
	log.Fatal(err)
}

// Set encoding style for advanced use cases
envelope.EncodingStyle = "http://schemas.xmlsoap.org/soap/encoding/"
xmlData, err := xml.MarshalIndent(envelope, "", "  ")
if err != nil {
	log.Fatal(err)
}
fmt.Println(string(xmlData))
Output:

<soapenv:Envelope encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body><GetStockPrice><symbol>AAPL</symbol></GetStockPrice></soapenv:Body>
</soapenv:Envelope>
Example (WithHeader)

ExampleEnvelope_withHeader demonstrates creating a SOAP envelope with headers.

// Create header entries
mustUnderstand := true
authHeader := soap.HeaderEntry{
	XMLName:        xml.Name{Local: "Authentication", Space: "http://example.com/auth"},
	MustUnderstand: &mustUnderstand,
	Actor:          "http://example.com/gateway",
	Content:        []byte(`<token>abc123xyz</token><user>john.doe</user>`),
}
transactionHeader := soap.HeaderEntry{
	XMLName: xml.Name{Local: "Transaction", Space: "http://example.com/tx"},
	Content: []byte(`<id>tx-456</id>`),
}
// Create envelope with headers using the new API
envelope, err := soap.NewEnvelope(soap.WithBody([]byte(`<GetUserProfile><userId>12345</userId></GetUserProfile>`)))
if err != nil {
	log.Fatal(err)
}

// Add headers manually for advanced use cases
envelope.Header = &soap.Header{
	XMLName: xml.Name{Local: "soapenv:Header"},
	Entries: []soap.HeaderEntry{authHeader, transactionHeader},
}
xmlData, err := xml.MarshalIndent(envelope, "", "  ")
if err != nil {
	log.Fatal(err)
}
fmt.Println(string(xmlData))
Output:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <Authentication xmlns="http://example.com/auth" mustUnderstand="true" actor="http://example.com/gateway"><token>abc123xyz</token><user>john.doe</user></Authentication>
    <Transaction xmlns="http://example.com/tx"><id>tx-456</id></Transaction>
  </soapenv:Header>
  <soapenv:Body><GetUserProfile><userId>12345</userId></GetUserProfile></soapenv:Body>
</soapenv:Envelope>

func NewEnvelope added in v0.22.0

func NewEnvelope(opts ...EnvelopeOption) (*Envelope, error)

NewEnvelope creates a new SOAP envelope with the specified options.

type EnvelopeOption added in v0.22.0

type EnvelopeOption func(*envelopeConfig)

EnvelopeOption is a function that configures an Envelope.

func WithBody added in v0.22.0

func WithBody(body any) EnvelopeOption

WithBody sets the body for the Envelope.

func WithNamespace added in v0.22.0

func WithNamespace(prefix, namespace string) EnvelopeOption

WithNamespace sets the namespace for the Envelope.

type Error added in v0.27.0

type Error struct {
	// StatusCode is the HTTP status code of the response.
	StatusCode int

	// ResponseBody is the raw HTTP response body.
	ResponseBody []byte

	// Envelope is the SOAP envelope that was received, nil if parsing failed.
	Envelope *Envelope

	// Fault is the SOAP fault, nil if no fault was present.
	Fault *Fault
}

Error contains HTTP and SOAP fault information.

func (*Error) Error added in v0.27.0

func (e *Error) Error() string

Error implements the error interface.

type Fault added in v0.21.0

type Fault struct {
	XMLName xml.Name

	// FaultCode is mandatory and provides algorithmic fault identification
	FaultCode string `xml:"faultcode"`

	// FaultString is mandatory and provides human-readable fault description
	FaultString string `xml:"faultstring"`

	// FaultActor is optional and identifies the fault source
	FaultActor string `xml:"faultactor,omitempty"`

	// Detail is optional and contains application-specific error information
	Detail *Detail `xml:"detail,omitempty"`
}

Fault represents a SOAP fault element as per SOAP 1.1 spec section 4.4.

Example

ExampleFault demonstrates creating and handling SOAP faults.

// Create a fault
fault := soap.Fault{
	FaultCode:   "Client",
	FaultString: "Invalid authentication credentials",
	FaultActor:  "http://example.com/auth-service",
	Detail: &soap.Detail{
		Content: []byte(`<error><code>AUTH001</code><message>Token expired</message></error>`),
	},
}
faultXMLData, _ := xml.Marshal(fault)
envelope, err := soap.NewEnvelope(soap.WithBody(faultXMLData))
if err != nil {
	log.Fatal(err)
}
xmlData, err := xml.MarshalIndent(envelope, "", "  ")
if err != nil {
	log.Fatal(err)
}
fmt.Println(string(xmlData))
Output:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body><Fault><faultcode>Client</faultcode><faultstring>Invalid authentication credentials</faultstring><faultactor>http://example.com/auth-service</faultactor><detail><error><code>AUTH001</code><message>Token expired</message></error></detail></Fault></soapenv:Body>
</soapenv:Envelope>

func (*Fault) String added in v0.27.0

func (f *Fault) String() string

String returns a comprehensive string representation of the SOAP fault for logging.

type Header struct {
	XMLName xml.Name

	// Header entries - flexible content allowing any XML
	Entries []HeaderEntry `xml:",any"`

	// Additional attributes for extensibility
	Attrs []xml.Attr `xml:",any,attr"`
}

Header represents a SOAP header containing header entries. Each header entry can have mustUnderstand and actor attributes as per SOAP 1.1 spec section 4.2.

type HeaderEntry added in v0.21.0

type HeaderEntry struct {
	XMLName xml.Name

	// MustUnderstand attribute as per SOAP 1.1 spec section 4.2.3
	// Values: true (1) means mandatory, false (0) or nil means optional
	MustUnderstand *bool `xml:"mustUnderstand,attr,omitempty"`

	// Actor attribute as per SOAP 1.1 spec section 4.2.2
	// Specifies the intended recipient of this header entry
	Actor string `xml:"actor,attr,omitempty"`

	// Content as raw XML for maximum flexibility
	Content []byte `xml:",innerxml"`

	// Additional attributes for extensibility
	Attrs []xml.Attr `xml:",any,attr"`
}

HeaderEntry represents a single header entry with SOAP-specific attributes. Implements the mustUnderstand and actor semantics from SOAP 1.1 spec sections 4.2.2 and 4.2.3.

Example (MustUnderstand)

ExampleHeaderEntry_mustUnderstand demonstrates the mustUnderstand attribute usage.

// Header that MUST be understood by the receiver
mustUnderstand := true
criticalHeader := soap.HeaderEntry{
	XMLName:        xml.Name{Local: "Security", Space: "http://example.com/security"},
	MustUnderstand: &mustUnderstand,
	Content:        []byte(`<signature>digital_signature_here</signature>`),
}

// Header that's optional
optionalHeader := soap.HeaderEntry{
	XMLName: xml.Name{Local: "Metadata", Space: "http://example.com/meta"},
	Content: []byte(`<version>2.0</version>`),
	// MustUnderstand is nil, so it's optional
}

envelope, err := soap.NewEnvelope(soap.WithBody([]byte(`<SecureOperation><data>sensitive</data></SecureOperation>`)))
if err != nil {
	log.Fatal(err)
}

// Add headers manually for advanced use cases
envelope.Header = &soap.Header{
	XMLName: xml.Name{Local: "soapenv:Header"},
	Entries: []soap.HeaderEntry{criticalHeader, optionalHeader},
}

xmlData, err := xml.MarshalIndent(envelope, "", "  ")
if err != nil {
	log.Fatal(err)
}

fmt.Println(string(xmlData))
Output:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <Security xmlns="http://example.com/security" mustUnderstand="true"><signature>digital_signature_here</signature></Security>
    <Metadata xmlns="http://example.com/meta"><version>2.0</version></Metadata>
  </soapenv:Header>
  <soapenv:Body><SecureOperation><data>sensitive</data></SecureOperation></soapenv:Body>
</soapenv:Envelope>

Directories

Path Synopsis
cmd
soap module
internal
Package wsdl implements the WSDL 1.1 specification.
Package wsdl implements the WSDL 1.1 specification.
Package xsd implements the XSD 1.0 specification.
Package xsd implements the XSD 1.0 specification.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL