Java DNS API, Wikipedia and twitter marathon in one package

Some time ago, I was solving the problem of automatically buying a domain. It was necessary to arrange in the form of a library (jar and settings file), which would be used in a corporate Java application. I started looking for DNS providers with the public API. It is desirable that the APIs be simpler and the domains cheaper - this balance was not easy to find.
Many options have been considered, some of which can be found here: stackoverflow . Subsequently, I narrowed the circle to the following applicants:

Many advised the latter, but this is a hosting provider, and I needed only DNS - I did not find the opportunity not to buy a server there.

The first has, in my opinion, a very convenient API - authentication can pass through the HTTP Header X-DNSimple-Token in general , but there is also a traditional approach with http basic authorization. The request format is very simple - short urls. Answers can be received in JSON (XML is also available) - in general, everything pleases the eye, except for the price - the .com domain costs $ 14 / y there . Knowledgeable people will understand that this is unacceptable.

When I started to deal with http://www.namecheap.com/- everything turned out to be pretty good. And on the part of the buyer - the prices are normal, it has been on the market for more than 10 years (dnsimple.com via who is gave Creation date: 07 Apr 2010 17:32:00 - it’s too small, plus the domain IDs when I created them through the API were in area 3000). And from the programmer: requests in XML, but the structure is not very confusing. Authentication through parameters in the url itself is nothing complicated.

What I liked most was that they had the only sandbox that was the only one of them. When registering in a test environment, you have $ 9,000 in your account and you can really test the purchase, renew, reactivate, etc. functions. for the domain. In DNsimple, for example, I did not find the opportunity to use the test environment without entering a credit card number - but what is this sandbox that cannot work without real data?

In addition, when editing a domain’s host records , they have the ability to set non-standard values ​​(not only A, CNAME, AAAA, etc.) - there is also a “ URL ” - this allows you to redirect from your domain to a certain URL (arbitrary), and this is how once it was required for the task, and in the absence of such an option, it would be necessary to invent something from the customer’s server. Not all DNS providers have this feature.

And this provider quite often distributes discount coupons ( the API has the ability to use these coupons ) and organizes promotions (about one of them - at the end of the article). For example, there have recently been discounts for everyone who transfers their domains from GoDaddy, in connection with the latter's SOPA positions.

Let's move on to the code

It is fully laid out in the public domain: github.com who needs to use it (customer by drum).

The DNSProvider interface has a specific implementation: NamecheapProvider, where the main functions for working with domains are present - purchase, update records, reactivation. There is a package of models where objects of the main entities are located: Domain, DomainRecord, RecordType. Everything else is query classes, and xml response parsers.

Base request class:
public abstract class DNSBaseRequest {
    private List params = new ArrayList();
    protected DNSBaseRequest(Properties properties) {
        params.add(new BasicNameValuePair("ApiUser", properties.getProperty("api.login")));
        params.add(new BasicNameValuePair("ApiKey", properties.getProperty("api.key")));
        params.add(new BasicNameValuePair("UserName", properties.getProperty("api.login")));
        params.add(new BasicNameValuePair("ClientIp", properties.getProperty("client.ip")));
        //each class has its own command - his purpose
        params.add(new BasicNameValuePair("Command", getCommand()));
    }
    protected abstract String getCommand();
....
}


Each request class implements its own getCommand , which corresponds to its purpose:

public class DomainReactivateRequest extends DNSBaseRequest{
    public DomainReactivateRequest(String domainName, Properties properties) {
        super(properties);
        addParam(new BasicNameValuePair("DomainName", domainName));
    }
    @Override
    protected String getCommand() {
        return "namecheap.domains.reactivate";
    }
}


Parser Interface:
public interface XmlResponseParser {
    T parse(String xml);
}


And an example implementation to get a list of domains from your account:
public class DomainsListParser extends DefaultHandler implements XmlResponseParser> {
    private static final Logger log = LoggerFactory.getLogger(DomainsListParser.class);
    private SAXParser parser;
    private ArrayList result;
    public DomainsListParser() throws Exception{
        SAXParserFactory factory = SAXParserFactory.newInstance();
        parser = factory.newSAXParser();
        result = new ArrayList();
    }
    public ArrayList parse(String xml) {
        try {
            parser.parse(new InputSource(new StringReader(xml)), this);
        } catch(Exception e){
            log.error("Error in parsing string.", e);
        }
        return result;
    }
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if ("Domain".equalsIgnoreCase(qName)){
            Domain domain = new Domain(Long.parseLong(attributes.getValue("ID")), attributes.getValue("Name"));
            domain.setCreateDate(attributes.getValue("Created"));
            domain.setExpireDate(attributes.getValue("Expires"));
            result.add(domain);
        }
    }
}


With each other, requesting and parsing the answer reduces the class to generics:
public class ProviderOperator {
    private static final Logger log = LoggerFactory.getLogger(ProviderOperator.class);
    private DNSRequestProcessor dnsRequestProcessor;
    public ProviderOperator(DNSRequestProcessor dnsRequestProcessor) {
        this.dnsRequestProcessor = dnsRequestProcessor;
    }
    public  T process(DNSBaseRequest dnsRequest, XmlResponseParser parser, S defaultResult) {
        T result = defaultResult;
        try {
            String xml = dnsRequestProcessor.get(dnsRequest);
            log.debug("Response: {}", xml);
            result = parser.parse(xml);
        } catch (Exception e) {
            log.error("Error in parse", e);
        }
        return result;
    }
}


Which takes them through parameters and returns the result of parsing the xml response.

To expand the functionality, you need to add a function to the interface, create a request class, a response parser class, and combine them through a call to ProviderOperator, respectively. NamecheapProvider functions.

Finally, an interesting story

www.namecheap.com has a tradition - every year they organize a Twitter marathon on a specific topic. Within 48 hours, 48 ​​questions are asked. Every hour the correct answer to the previous question is given and the next one is asked. The winners have money in the account (for buying domains) and a pair of iPad2 - the most popular prize of most quizzes. This year the marathon decided to coincide with the super bowl. I'm not good at American sports, but I decided to answer a question for fun. Number three sounded something like this:

"In what year was Bart Starr elected to the Wisconsin Athletic Hall of Fame"

- Without hesitation, he went to Wikipedia to look at his biography. In a separate review, it was written that this happened in 1980. I tweeted this number in response. An hour later, the tweet with the correct answer upset me a bit - 1981. Well, whoever doubted, I thought that the dates on Wikipedia are not accurate. But still I decided to go there again and see - I was even more upset. 1981. It was really written there. I thought it was time to pack pills to improve vision, increase attention and speed up the brain - in general, everything that is prescribed to the elderly, and went into other things.

However, after a couple of hours an interesting tweet arrived from the organizer of the marathon, approximately of the following content:

“Dear participants, we consider it UNACCEPTABLE to edit Wikipedia to misinform rivals - this is contrary to the spirit of fair play. Convicted of fraud will be disqualified. ”

I was delighted - it means early to buy medicine.

UPD Thank you all for reporting a broken backlight.

Also popular now: