client.go raw

   1  // Package metaname provides a client for the Metaname API.
   2  package metaname
   3  
   4  import (
   5  	"context"
   6  	"encoding/json"
   7  
   8  	"github.com/AdamSLevy/jsonrpc2/v14"
   9  )
  10  
  11  type iJsonRpc2Client interface {
  12  	Request(context context.Context, host string, method string, params interface{}, result interface{}) error
  13  }
  14  
  15  // A client for the Metaname API.
  16  type MetanameClient struct {
  17  	RpcClient        iJsonRpc2Client
  18  	Host             string
  19  	AccountReference string
  20  	APIKey           string
  21  }
  22  
  23  // A ResourceRecord is a representation of a DNS record.
  24  //
  25  // Aux should be nil for records other than MX and SRV records, where it represents the priority.
  26  // Reference should be nil when supplying a ResourceRecord, but will be populated when retrieving a record.
  27  //
  28  // https://metaname.net/api/1.1/doc#Resource_record_details
  29  type ResourceRecord struct {
  30  	Name      string  `json:"name"`
  31  	Type      string  `json:"type"`
  32  	Aux       *int    `json:"aux"`
  33  	Ttl       int     `json:"ttl"`
  34  	Data      string  `json:"data"`
  35  	Reference *string `json:"reference,omitempty"`
  36  }
  37  
  38  // Create a new MetanameClient with some default values.
  39  func NewMetanameClient(accountReference string, apiKey string) *MetanameClient {
  40  	return &MetanameClient{
  41  		RpcClient:        &jsonrpc2.Client{},
  42  		Host:             "https://metaname.net/api/1.1",
  43  		AccountReference: accountReference,
  44  		APIKey:           apiKey,
  45  	}
  46  }
  47  
  48  // Creates a DNS record in the zone for the given domain and returns a reference that can be used for updating and deleting it.
  49  //
  50  // https://metaname.net/api/1.1/doc#create_dns_record
  51  func (c *MetanameClient) CreateDnsRecord(ctx context.Context, domainName string, record ResourceRecord) (string, error) {
  52  	params := []interface{}{c.AccountReference, c.APIKey, domainName, record}
  53  	var result string
  54  	err := c.RpcClient.Request(ctx, c.Host, "create_dns_record", params, &result)
  55  	return result, err
  56  }
  57  
  58  // Updates the details of a DNS record in a zone.
  59  //
  60  // https://metaname.net/api/1.1/doc#update_dns_record
  61  func (c *MetanameClient) UpdateDnsRecord(ctx context.Context, domainName string, reference string, record ResourceRecord) error {
  62  	params := []interface{}{c.AccountReference, c.APIKey, domainName, reference, record}
  63  	err := c.RpcClient.Request(ctx, c.Host, "update_dns_record", params, nil)
  64  	return ignoreNullResultError(err)
  65  }
  66  
  67  // Delete a DNS record from a zone.
  68  //
  69  // https://metaname.net/api/1.1/doc#delete_dns_record
  70  func (c *MetanameClient) DeleteDnsRecord(ctx context.Context, domainName string, reference string) error {
  71  	params := []interface{}{c.AccountReference, c.APIKey, domainName, reference}
  72  	err := c.RpcClient.Request(ctx, c.Host, "delete_dns_record", params, nil)
  73  	return ignoreNullResultError(err)
  74  }
  75  
  76  // Retrieve all the DNS records in a zone.
  77  //
  78  // https://metaname.net/api/1.1/doc#dns_zone
  79  func (c *MetanameClient) DnsZone(ctx context.Context, domainName string) ([]ResourceRecord, error) {
  80  	params := []interface{}{c.AccountReference, c.APIKey, domainName}
  81  	var result []ResourceRecord
  82  	err := c.RpcClient.Request(ctx, c.Host, "dns_zone", params, &result)
  83  	return result, err
  84  }
  85  
  86  // Create or update a zone.
  87  //
  88  // https://metaname.net/api/1.1/doc#configure_zone
  89  func (c *MetanameClient) ConfigureZone(ctx context.Context, zoneName string, records []ResourceRecord, options interface{}) error {
  90  	params := []interface{}{c.AccountReference, c.APIKey, zoneName, records, options}
  91  	err := c.RpcClient.Request(ctx, c.Host, "configure_zone", params, nil)
  92  	return ignoreNullResultError(err)
  93  }
  94  
  95  // Workaround until https://github.com/AdamSLevy/jsonrpc2/issues/11 is fixed.
  96  type nullSafeResponse struct {
  97  	Result interface{} `json:"result"`
  98  }
  99  
 100  func ignoreNullResultError(err error) error {
 101  	if unexerr, ok := err.(jsonrpc2.ErrorUnexpectedHTTPResponse); ok {
 102  		var res nullSafeResponse
 103  		unmerr := json.Unmarshal(unexerr.Body, &res)
 104  		if unmerr != nil {
 105  			return err
 106  		} else if res.Result == nil {
 107  			return nil
 108  		}
 109  	}
 110  	return err
 111  }
 112