goinwx.go raw

   1  package goinwx
   2  
   3  import (
   4  	"net/url"
   5  
   6  	"github.com/kolo/xmlrpc"
   7  )
   8  
   9  // API information.
  10  const (
  11  	APIBaseURL        = "https://api.domrobot.com/xmlrpc/"
  12  	APISandboxBaseURL = "https://api.ote.domrobot.com/xmlrpc/"
  13  	APILanguage       = "en"
  14  )
  15  
  16  // Client manages communication with INWX API.
  17  type Client struct {
  18  	// HTTP client used to communicate with the INWX API.
  19  	RPCClient *xmlrpc.Client
  20  
  21  	// API username and password
  22  	username string
  23  	password string
  24  
  25  	lang string
  26  
  27  	common service // Reuse a single struct instead of allocating one for each service on the heap.
  28  
  29  	// Services used for communicating with the API
  30  	Account     *AccountService
  31  	Contacts    *ContactService
  32  	Dnssec      *DNSSecService
  33  	Domains     *DomainService
  34  	Nameservers *NameserverService
  35  }
  36  
  37  type service struct {
  38  	client *Client
  39  }
  40  
  41  // ClientOptions Options of the API client.
  42  type ClientOptions struct {
  43  	Sandbox bool
  44  
  45  	// Language of the return message. (en/de/es)
  46  	Lang string
  47  
  48  	// Base URL for API requests (only for client testing purpose).
  49  	BaseURL *url.URL
  50  }
  51  
  52  // Request The representation of an API request.
  53  type Request struct {
  54  	ServiceMethod string
  55  	Args          map[string]any
  56  }
  57  
  58  // NewClient returns a new INWX API client.
  59  func NewClient(username, password string, opts *ClientOptions) *Client {
  60  	baseURL := getBaseURL(opts).String()
  61  
  62  	rpcClient, _ := xmlrpc.NewClient(baseURL, nil)
  63  
  64  	client := &Client{
  65  		RPCClient: rpcClient,
  66  		username:  username,
  67  		password:  password,
  68  		lang:      APILanguage,
  69  	}
  70  
  71  	if opts != nil && opts.Lang != "" {
  72  		client.lang = opts.Lang
  73  	}
  74  
  75  	client.common.client = client
  76  	client.Account = (*AccountService)(&client.common)
  77  	client.Contacts = (*ContactService)(&client.common)
  78  	client.Dnssec = (*DNSSecService)(&client.common)
  79  	client.Domains = (*DomainService)(&client.common)
  80  	client.Nameservers = (*NameserverService)(&client.common)
  81  
  82  	return client
  83  }
  84  
  85  // NewRequest creates an API request.
  86  func (c *Client) NewRequest(serviceMethod string, args map[string]any) *Request {
  87  	if args != nil {
  88  		args["lang"] = APILanguage
  89  	}
  90  
  91  	return &Request{ServiceMethod: serviceMethod, Args: args}
  92  }
  93  
  94  // Do sends an API request and returns the API response.
  95  func (c *Client) Do(req *Request) (map[string]any, error) {
  96  	var resp Response
  97  
  98  	err := c.RPCClient.Call(req.ServiceMethod, req.Args, &resp)
  99  	if err != nil {
 100  		return nil, err
 101  	}
 102  
 103  	return resp.ResponseData, checkResponse(&resp)
 104  }
 105  
 106  // checkResponse checks the API response for errors, and returns them if present.
 107  func checkResponse(r *Response) error {
 108  	if c := r.Code; c >= 1000 && c <= 1500 {
 109  		return nil
 110  	}
 111  
 112  	return &ErrorResponse{Code: r.Code, Message: r.Message, Reason: r.Reason, ReasonCode: r.ReasonCode}
 113  }
 114  
 115  func getBaseURL(opts *ClientOptions) *url.URL {
 116  	var useSandbox bool
 117  	if opts != nil {
 118  		useSandbox = opts.Sandbox
 119  	}
 120  
 121  	var baseURL *url.URL
 122  
 123  	if useSandbox {
 124  		baseURL, _ = url.Parse(APISandboxBaseURL)
 125  	} else {
 126  		baseURL, _ = url.Parse(APIBaseURL)
 127  	}
 128  
 129  	if opts != nil && opts.BaseURL != nil {
 130  		baseURL = opts.BaseURL
 131  	}
 132  
 133  	return baseURL
 134  }
 135