dnscontrol/vendor/github.com/billputer/go-namecheap/namecheap.go
2016-08-22 18:31:50 -06:00

161 lines
4.2 KiB
Go

// Package namecheap implements a client for the Namecheap API.
//
// In order to use this package you will need a Namecheap account and your API Token.
package namecheap
import (
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
const defaultBaseURL = "https://api.namecheap.com/xml.response"
// Client represents a client used to make calls to the Namecheap API.
type Client struct {
ApiUser string
ApiToken string
UserName string
HttpClient *http.Client
// Base URL for API requests.
// Defaults to the public Namecheap API,
// but can be set to a different endpoint (e.g. the sandbox).
// BaseURL should always be specified with a trailing slash.
BaseURL string
*Registrant
}
type ApiRequest struct {
method string
command string
params url.Values
}
type ApiResponse struct {
Status string `xml:"Status,attr"`
Command string `xml:"RequestedCommand"`
Domains []DomainGetListResult `xml:"CommandResponse>DomainGetListResult>Domain"`
DomainInfo *DomainInfo `xml:"CommandResponse>DomainGetInfoResult"`
DomainDNSHosts *DomainDNSGetHostsResult `xml:"CommandResponse>DomainDNSGetHostsResult"`
DomainDNSSetHosts *DomainDNSSetHostsResult `xml:"CommandResponse>DomainDNSSetHostsResult"`
DomainCreate *DomainCreateResult `xml:"CommandResponse>DomainCreateResult"`
DomainsCheck []DomainCheckResult `xml:"CommandResponse>DomainCheckResult"`
DomainNSInfo *DomainNSInfoResult `xml:"CommandResponse>DomainNSInfoResult"`
DomainDNSSetCustom *DomainDNSSetCustomResult `xml:"CommandResponse>DomainDNSSetCustomResult"`
Errors []ApiError `xml:"Errors>Error"`
}
// ApiError is the format of the error returned in the api responses.
type ApiError struct {
Number int `xml:"Number,attr"`
Message string `xml:",innerxml"`
}
func (err *ApiError) Error() string {
return err.Message
}
func NewClient(apiUser, apiToken, userName string) *Client {
return &Client{
ApiUser: apiUser,
ApiToken: apiToken,
UserName: userName,
HttpClient: http.DefaultClient,
BaseURL: defaultBaseURL,
}
}
// NewRegistrant associates a new registrant with the
func (client *Client) NewRegistrant(
firstName, lastName,
addr1, addr2,
city, state, postalCode, country,
phone, email string,
) {
client.Registrant = newRegistrant(
firstName, lastName,
addr1, addr2,
city, state, postalCode, country,
phone, email,
)
}
func (client *Client) do(request *ApiRequest) (*ApiResponse, error) {
if request.method == "" {
return nil, errors.New("request method cannot be blank")
}
body, _, err := client.sendRequest(request)
if err != nil {
return nil, err
}
resp := new(ApiResponse)
if err = xml.Unmarshal(body, resp); err != nil {
return nil, err
}
if resp.Status == "ERROR" {
errMsg := ""
for _, apiError := range resp.Errors {
errMsg += fmt.Sprintf("Error %d: %s\n", apiError.Number, apiError.Message)
}
return nil, errors.New(errMsg)
}
return resp, nil
}
func (client *Client) makeRequest(request *ApiRequest) (*http.Request, error) {
url, err := url.Parse(client.BaseURL)
if err != nil {
return nil, err
}
p := request.params
p.Set("ApiUser", client.ApiUser)
p.Set("ApiKey", client.ApiToken)
p.Set("UserName", client.UserName)
// This param is required by the API, but not actually used.
p.Set("ClientIp", "127.0.0.1")
p.Set("Command", request.command)
url.RawQuery = p.Encode()
// UGH
//
// Need this for the domain name part of the domains.check endpoint
url.RawQuery = strings.Replace(url.RawQuery, "%2C", ",", -1)
urlString := fmt.Sprintf("%s?%s", client.BaseURL, url.RawQuery)
req, err := http.NewRequest(request.method, urlString, nil)
if err != nil {
return nil, err
}
return req, nil
}
func (client *Client) sendRequest(request *ApiRequest) ([]byte, int, error) {
req, err := client.makeRequest(request)
if err != nil {
return nil, 0, err
}
resp, err := client.HttpClient.Do(req)
if err != nil {
return nil, 0, err
}
defer resp.Body.Close()
buf, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, 0, err
}
return buf, resp.StatusCode, nil
}