Sign In

Internet Performance Delivered right to your inbox

DynECT Managed DNS API: Get Started Using CURL, Java or Python

This is a guest post from Sunny Gleason from SunnyCloud Consulting.

Are you ready to create the next great ‘Net sensation? With Dyn, getting off on the right foot is easy, as they are the world’s leading provider of high availability DNS and Email Delivery services with a global network of 17 points of presence (and growing!) and 100% uptime.

In this article, we’ll go through the steps of creating a new domain and configuring web site and mail records using the DynECT APIs. We think it’s pretty awesome that anyone can go through the steps of setting up a domain completely automatically via the APIs, but for those who prefer the cozy comfort of web user interfaces, there is copious documentation available in the Dyn Knowledge Base.

Signing up for DynECT Managed DNS Service

To harness the full power of Dyn’s APIs, sign up for an account at Dyn.com. In our case, we chose to sign up for the DynECT DNS Lite 5 Plan.

Registering your domain

Before we can publish our new site, we’ll need to find a unique domain name of our very own. For the purposes of this article, we’ll use the domain *example.com*. It’s easy to register or transfer a domain using Dyn: just follow the instructions here.

When buying a domain, consider names that are easy to speak and easy to spell. Many businesses buy additional domains to cover common typos, as well as alternative top-level domains (TLDs) such as .CO, .NET, .ORG, .BIZ and .US. If you purchase the domain with Dyn, the user interface will walk you through the process of assigning Dyn nameservers as you go.

If you have already registered the domain with an alternative provider, don’t dismay! You can still tap into Dyn’s global DNS network, but you will just need to update the name servers for each domain so that they point to Dyn’s servers. Detailed instructions for updating name server entries for AWS Route53, GoDaddy, Network Solutions, and other providers will be available soon in the Dyn Knowledge Base. (In the meantime, if you need help, just contact their Enterprise Concierge team.)

For our example domain configuration, there should be four domains similar to this (where NN below will be changed to a numeric id for your account):

– ns1.pNN.dynect.net, ns2.pNN.dynect.net, ns3.pNN.dynect.net, ns4.pNN.dynect.net

With these four separate domain name servers specified for your domain name, you can be assured that your customers have four highly reliable ways to reach the DynECT DNS servers.

Congratulations on your new domain! Now we can move on to the good stuff and bring the site to life.

Prelude: Creating a Session Token

In order to make calls to the DynECT API, we need to create a session token. (We wouldn’t want just anybody accessing your DNS records, would we?) Creating a session token for secure, time-limited access to the DynECT Managed DNS API is easy:

CURL:

curl -v -v -X POST -H "Content-Type: application/json" \ https://api2.dynect.net/REST/Session/ \ -d '{"customer_name":"yourcustomer","user_name":"youruser","password":"yourpass"}'

Python

import sys
from dynect.DynectDNS import DynectRest
try:
 
 import json
except ImportError:
 
 try:
 
 import simplejson as json
 
 except ImportError:
 
 sys.exit("Could not find json or simplejson libraries.")
 
dyn = DynectRest()
 
creds = {
 'customer_name': 'yourcustomer',
 'user_name': 'youruser',
 'password': 'yourpass',
}
 
def request_dyn(dyn, uri, method, args):
response = dyn.execute(uri, method, args)
if response['status'] != 'success':
 
 sys.exit("Error executing " + uri + " " + method + " " + json.dumps(args) + " " + json.dumps(response))

Java:

import org.jclouds.ContextBuilder;
import org.jclouds.dynect.v3.DynECTApi;
import org.jclouds.dynect.v3.domain.CreatePrimaryZone;
import org.jclouds.dynect.v3.domain.CreateRecord;
import org.jclouds.dynect.v3.domain.rdata.AData;
import org.jclouds.dynect.v3.domain.rdata.CNAMEData;
import org.jclouds.dynect.v3.domain.rdata.MXData;
import org.jclouds.dynect.v3.features.RecordApi;
import org.jclouds.dynect.v3.features.ZoneApi;
import org.jclouds.providers.ProviderMetadata;
import org.jclouds.providers.Providers;

public class GettingStartedWithDynect {
    public static void main(String[] args) throws Exception {
        ProviderMetadata meta = Providers.withId("dynect");
        ContextBuilder ctx = ContextBuilder.newBuilder(meta);
        ctx.credentials("yourcustomer:youruser", "yourpass");

        DynECTApi dyn = ctx.buildApi(DynECTApi.class);

        ZoneApi zone = dyn.getZoneApi();

Where ‘yourcustomer’, ‘youruser’, and ‘yourpass’ are replaced with the values specific to your account. Since we’re using the “https” API endpoint for all API access, we know that the communication is secure. Also note that we’ve specified JSON as the content type. If you need to use XML, that’s also available via the API.

If all goes well (and it always does), the server will respond with JSON that resembles the following:

{"status": "success", "data": {"token": "A_VERY_LONG_BASE64_STRING==", \"version": "3.4.0"}, "job_id": 354999338, "msgs": [{"INFO": "login: Login successful", \"SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}

Take note of the shiny new session token above, represented by the text “A_VERY_LONG_BASE64_STRING==”! In future API requests, we will provide an “Auth-Token” header with the value corresponding to “A_VERY_LONG_BASE64_STRING==”.

If you are using Ruby, Python, or Java, the client libraries will take care of all of this session stuff for you. I mean, who doesn’t want to save time?

Creating a Zone

So now that we have a session token as well as a newly registered domain, the next step is to create our very own DNS Zone. Think of it as a file that contains all of the name records for our domain, which we can access via Dyn’s APIs. To invoke the REST endpoint and create a new zone, we issue a POST request to /REST/Zone/:zone as follows:

CURL:

curl -v -v -X POST -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/Zone/example.com \ -d '{"rname":"myadmin@example.com","serial_style":"epoch","ttl":"60"}'

Python:

request_dyn(dyn, '/Zone/example.com', 'POST', {'rname':'admin@example.com','ttl':60,'domain':'example.com'})

Java:

zone.scheduleCreate(CreatePrimaryZone.builder()
    .contact("admin@example.com").defaultTTL(60).fqdn("example.com")
    .build());

RecordApi records = dyn.getRecordApiForZone("example.com");

Where example.com in the URL above is substituted with your domain name, and the myadmin@example.com is replaced with your administrative email.

The DynECT web service will respond with something resembling the following:

{"status": "success", "data": {"zone_type": "Primary", "serial_style": "epoch", "serial": 0,
 "zone": "example.com"}, "job_id": 35504949, "msgs": [{"INFO": "create: New zone example.com
 created. Publish it to put it on our server.", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}, 
 {"INFO": "setup: If you plan to provide your own secondary DNS for the zone, allow notify requests
 from these IP addresses on your nameserver: 204.13.249.66, 208.78.68.66, 2600:2001:0:1::66,
 2600:2003:0:1::66", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}

What’s up with that? It sounds like the server hasn’t applied our changes yet. This is actually a good thing! Behind the scenes, DynECT is batching up our changes so that it can apply all of them in one go. Since we’re working with a brand new domain that we haven’t told anyone about yet, we’ll execute the PUBLISH command right away by sending a PUT to the /REST/Zone/:zone endpoint:

CURL:

curl -v -v -X PUT -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/Zone/example.com \ -d '{"publish":true}'

Python:

request_dyn(dyn, '/Zone/example.com', 'PUT', {'publish':'true'})

Java:

zone.publish("example.com");

The server responds with:

{"status": "success", "data": {"zone_type": "Primary", "serial_style": "epoch",
 "serial": 1369010993, "zone": "example.com"}, "job_id": 3550120202, "msgs":
 [{"INFO": "publish: example.com published", "SOURCE": "BLL", "ERR_CD": null, "LVL":
 "INFO"}]}

Now, we’re all set! Our new zone is live and ready to create more records.

Creating server records: if your new Web Site is hosted on AWS EC2

In this section, we presume that your web site is hosted on Amazon Web Services EC2 using an Elastic IP, something like “50.17.216.232”. We assume that you have already configured the web application to serve requests, something along the lines of this or this.

On the DNS side, here’s a quick sketch of what we’re trying to do:

* Set up zone apex “A record”
* Set up WWW “CNAME record”

The first thing we’ll want to do is set up a “zone apex” record: this is what people use when the address “http://example.com” is entered in a browser. The type of record we’ll use is called an A record because the value corresponds to an internet address.

CURL:

curl -v -v -X POST -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/ARecord/example.com/example.com. \ -d '{"rdata":{"address":"50.17.216.232"}}'

Python:

request_dyn(dyn, '/ARecord/example.com/example.com.', 'POST',{'rdata':{'address':'1.2.3.5'}})

Java:

records.scheduleCreate(CreateRecord.<AData> builder().type("A")
       .fqdn("example.com.").rdata(AData.a("1.2.3.5")).build());

The server responds with the following:

{"status": "success", "data": {"zone": "example.com", "ttl": 60, "fqdn": "example.com.",
 "record_type": "A", "rdata": {"address": "50.17.216.232"}, "record_id": 0}, "job_id": 355020202,
 "msgs": [{"INFO": "add: Record added", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}

Now that that’s all set, we just need to set up a record for “www.example.com”, since that’s what many folks still use for standard web sites. In this case, we’ll use a CNAME record so that we can “point to” the A record we just created. CNAME stands for canonical name – meaning that the canonical name for “www.example.com.” is “example.com.”. Don’t mind the extra periods at the end of those domain names – they are necessary to tell the DNS system that we are talking about fully qualified domain names (FQDNs), not DNS prefixes.

CURL:

curl -v -v -X POST -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/CNAMERecord/example.com/www.example.com. \ -d '{"rdata":{"cname":"example.com."}}'

Python:

request_dyn(dyn, '/CNAMERecord/example.com/www.example.com .', 'POST', {'rdata':{'cname':'example.com.'}})

Java:

records.scheduleCreate(CreateRecord.<CNAMEData> builder().type("CNAME")
       .fqdn("www.example.com.").rdata(CNAMEData.cname("example.com."))
       .build());

The server responds with something resembling the following:

/REST/Job/3550245985

Now that those entries are submitted, we just need to publish the zone, and we’ll be all set!

CURL:

curl -v -v -X PUT -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/Zone/example.com \ -d '{"publish":true}'

Python:

request_dyn(dyn, '/Zone/example.com', 'PUT', {'publish':'true'})

Java:

zone.publish("example.com");

Of course, the server responds with:

{"status": "success", "data": {"zone_type": "Primary", "serial_style": "epoch",
 "serial": 1369012261, "zone": "example.com"}, "job_id": 355024404, "msgs":
 [{"INFO": "publish: example.com published", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}

Not bad for a first-timer!

Creating server records: if your web site is hosted in Heroku

If your web site is hosted in Heroku, it’s a slightly different scenario than AWS EC2. We can’t use zone apex A record because Heroku doesn’t like that, as described here. Also, our Heroku app has its own “heroku name” that we’ll need to point to so that things work properly.

Before we go too far, we should follow the Heroku instructions to set up our Heroku app “example.herokuapp.com” to allow requests from the non-Heroku name “myapp.example.com”. (Usually Heroku apps have a predefined name like “whistling-swan-8029.herokuapp.com” instead of “example.herokuapp.com”).

The Heroku command for adding custom domain access should look something like:

heroku domains:add myapp.example.com

Now that the Heroku stuff is all set, we need to configure “myapp.example.com” to point to the Heroku addresses corresponding to “example.herokuapp.com”.

CURL:

curl -v -v -X POST -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \
https://api2.dynect.net/REST/CNAMERecord/example.com/myapp.example.com. \ -d '{"rdata":{"cname":"example.herokuapp.com."}}'

Python:

request_dyn(dyn, '/CNAMERecord/example.com/myapp.example.com.','POST',{'rdata':{'cname':'example.herokuapp.com.'}})

Java:

records.scheduleCreate(CreateRecord.<CNAMEData> builder().type("CNAME")
 .fqdn("myapp.example.com.")
 .rdata(CNAMEData.cname("example.herokuapp.com.")).build());

The server responds with:

{"status": "success", "data": {"zone": "example.com", "ttl": 60, "fqdn": "myapp.example.com.",
 "record_type": "CNAME", "rdata": {"cname":"example.herokuapp.com."}, "record_id": 0},
 "job_id": 355039414, "msgs": [{"INFO": "add: Record added", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}

This is great! But what about example.com? We’d like to configure it so that our visitors to http://example.com are sent correctly to Heroku. To achieve this, we use the HTTP Redirect service in the DynECT API.

CURL:

curl -v -v -XPOST -H "Content-Type: application/json" -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/HTTPRedirect/example.com/example.com \ -d '{"code":301,"keep_uri":"Y","url":"http://myapp.example.com/"}'

Python:

request_dyn(dyn, '/HTTPRedirect/example.com/example.com', 'POST',{'code':301,'keep_uri':'Y','url':'http://myapp.example.com/ '})

Java:

// NOTE: JClouds doesn't have HTTPRedirect service support yet - stay
// tuned!

The server responds with:

{"status": "success", "data": {"url": "http://myapp.example.com/", "code": "301",
 "keep_uri": "Y", "fqdn": "example.com", "zone": "example.com"}, "job_id": 355035784,
 "msgs": [{"INFO": "add: Service added", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}

Note: in this case, we observed that the second instance of example.com in the REST url above should not be a FQDN (no trailing period). This seems to be specific to the HTTP Redirect endpoint.

Now that those entries are submitted, we just need to publish the zone, and we’ll be all set!

CURL:

curl -v -v -X PUT -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/Zone/example.com \ -d '{"publish":true}'

Python:

request_dyn(dyn, '/Zone/example.com', 'PUT', {'publish':'true'})

Java:

zone.publish("example.com");

Of course, the server responds with:

{"status": "success", "data": {"zone_type": "Primary", "serial_style": "epoch",
 "serial": 1369012261, "zone": "example.com"}, "job_id": 355024428, "msgs":
 [{"INFO": "publish: example.com published", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}

Pretty awesome! And if we ever need to change the DNS entries due to a Heroku or AWS issue, we can do it via the API!

Epilogue: Creating MX records

For the final part of our DNS API adventure, we’ll set up some quick DNS entries so that we can receive mail using Google Apps (GMail). We think you’ll agree that the toughest part of that is setting up the Google Apps account!

Signing up for Google Apps starts here.

During the sign-up process, you’ll be asked to verify that you own the domain (which you can do using the DynECT Managed DNS web interface), and then told to configure DNS entries similar to these here.

In our case, there are 5 entries to configure, similar to as follows:

CURL:

curl -v -v -X POST -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" https://api2.dynect.net/REST/MXRecord/example.com/example.com. \ -d '{"rdata":{"exchange":"ASPMX.L.GOOGLE.COM.","preference":"10"}}'
curl -v -v -X POST -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/MXRecord/example.com/example.com. \ -d '{"rdata":{"exchange":"ALT1.ASPMX.L.GOOGLE.COM.","preference":"20"}}'
curl -v -v -X POST -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/MXRecord/example.com/example.com. \ -d '{"rdata":{"exchange":"ALT2.ASPMX.L.GOOGLE.COM.","preference":"20"}}'
curl -v -v -X POST -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/MXRecord/example.com/example.com. \ -d '{"rdata":{"exchange":"ASPMX2.GOOGLEMAIL.COM.","preference":"30"}}'
curl -v -v -X POST -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/MXRecord/example.com/example.com. \ -d '{"rdata":{"exchange":"ASPMX3.GOOGLEMAIL.COM.","preference":"30"}}'

Python:

request_dyn(dyn, '/MXRecord/example.com/example.com.','POST',{'rdata':{'exchange':'ASPMX.L.GOOGLE.COM.','preference':10}})
request_dyn(dyn, '/MXRecord/example.com/example.com.','POST',{'rdata':{'exchange':'ALT1.ASPMX.L.GOOGLE.COM.','preference':20}})
request_dyn(dyn, '/MXRecord/example.com/example.com.','POST',{'rdata':{'exchange':'ALT2.ASPMX.L.GOOGLE.COM.','preference':20}})
request_dyn(dyn, '/MXRecord/example.com/example.com.','POST',{'rdata':{'exchange':'ASPMX2.GOOGLEMAIL.COM.','preference':30}})
request_dyn(dyn, '/MXRecord/example.com/example.com.','POST',{'rdata':{'exchange':'ASPMX3.GOOGLEMAIL.COM.','preference':30}})

Java:

records.scheduleCreate(CreateRecord.<MXData> builder().type("MX")
 .fqdn("example.com.").rdata(MXData.mx(10, "ASPMX.L.GOOGLE.COM."))
 .build());
records.scheduleCreate(CreateRecord.<MXData> builder().type("MX")
 .fqdn("example.com.")
 .rdata(MXData.mx(20, "ALT1.ASPMX.L.GOOGLE.COM.")).build());
records.scheduleCreate(CreateRecord.<MXData> builder().type("MX")
 .fqdn("example.com.")
 .rdata(MXData.mx(20, "ALT2.ASPMX.L.GOOGLE.COM.")).build());
records.scheduleCreate(CreateRecord.<MXData> builder().type("MX")
 .fqdn("example.com.")
 .rdata(MXData.mx(30, "ASPMX2.GOOGLEMAIL.COM.")).build());
records.scheduleCreate(CreateRecord.<MXData> builder().type("MX")
 .fqdn("example.com.")
 .rdata(MXData.mx(30, "ASPMX3.GOOGLEMAIL.COM.")).build());

NOTE: be sure to use the most recent entries from the Google Apps documentation! It is possible that this blog entry references old values, and we wouldn’t want you to lose any email!

Once these are set, we publish them using the following:

CURL:

curl -v -v -X PUT -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/Zone/example.com \ -d '{"publish":true}'

Python:

request_dyn(dyn, '/Zone/example.com', 'PUT', {'publish':'true'})

Java:

zone.publish("example.com");

The server responds with the following:

{"status": "success", "data": {"zone_type": "Primary", "serial_style": "epoch",
 "serial": 1369012200, "zone": "example.com"}, "job_id": 355024428, "msgs":
 [{"INFO": "publish: example.com published", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}

And we’re done!

Wrapping Up

That was fun! If you’re one of those people who like to leave things as we found them, you may consider explicitly logging out your session. If you haven’t already, don’t forget to publish your changes before you do this!

CURL:

curl -v -v -X DELETE -H "Content-Type: application/json" \ -H "Auth-Token: A_VERY_LONG_BASE64_STRING==" \ https://api2.dynect.net/REST/Session/

Python:

request_dyn(dyn, '/Session/', 'DELETE', None)

The server will respond with something like this:

{"status": "success", "data": {}, "job_id": 355460268, "msgs":
 [{"INFO": "logout: Logout successful", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}

Now, we are assured that no one else may use the session token again.

We hope you’ve enjoyed this trip through the DynECT API, as we configured a zone and set up A records, CNAME records, MX records, and HTTP redirect service for our very own domain.


Share Now

Whois: Dyn Guest Blogs

Dyn offers the platform for some of the greatest minds on the Internet to contribute their thoughts via guest blogs. Follow on Twitter and Facebook.