Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,24 @@
import sys
import time


if len(sys.argv) != 5 and len(sys.argv) != 3:
raise Exception("Expected use: python sample.py username password [use_http host:port]")

username = sys.argv[1]
password = sys.argv[2]
use_http = 'False'
domain = 'restapi.ultradns.com'
proxyDict = {
"http": "http://yourproxy.com:port",
"https" "http://yourproxy.com:port"
}

if len(sys.argv) == 5:
use_http = sys.argv[3]
domain = sys.argv[4]

c = ultra_rest_client.RestApiClient(username, password, 'True' == use_http, domain)
c = ultra_rest_client.RestApiClient(username, password, 'True' == use_http, domain, proxyDict)
print 'version %s' % c.version()
print 'status %s' % c.status()
account_details = c.get_account_details()
Expand Down
239 changes: 120 additions & 119 deletions ultra_rest_client/connection.py
Original file line number Diff line number Diff line change
@@ -1,119 +1,120 @@
# Copyright 2000 - 2013 NeuStar, Inc.All rights reserved.
# NeuStar, the Neustar logo and related names and logos are registered
# trademarks, service marks or tradenames of NeuStar, Inc. All other
# product names, company names, marks, logos and symbols may be trademarks
# of their respective owners.
__author__ = 'Jon Bodner'

# store the URL and the access/refresh tokens as state
import requests

class AuthError(Exception):
def __init__(self, message):
self.message = message

def __str__(self):
return repr(self.message)


class RestError(Exception):
def __init__(self, message):
self.message = message

def __str__(self):
return repr(self.message)


class RestApiConnection:
def __init__(self, use_http=False, host="restapi.ultradns.com"):
self.use_http = use_http
self.host = host
self.access_token = ""
self.refresh_token = ""

def _get_connection(self):
if self.use_http:
return "http://"+ self.host
else:
return "https://"+ self.host

# Authentication
# We need the ability to take in a username and password and get
# an auth token and a refresh token. If any request fails due
# to an invalid auth token, refresh must be automatically invoked, the
# new auth token and refresh token stored, and the request tried again
# with the new auth token.
def auth(self, username, password):
h1 = self._get_connection()
payload = {"grant_type":"password", "username":username, "password":password}
r1 = requests.post(h1+"/v1/authorization/token",data=payload)
if r1.status_code == requests.codes.OK:
json_body = r1.json()
self.access_token = json_body[u'accessToken']
self.refresh_token = json_body[u'refreshToken']
else:
raise AuthError(r1.json())

def _refresh(self):
h1 = self._get_connection()
payload = {"grant_type":"refresh_token","refresh_token":self.refresh_token}
r1 = requests.post(h1+"/v1/authorization/token", data=payload)
if r1.status_code == requests.codes.OK:
json_body = r1.json()
self.access_token = json_body[u'accessToken']
self.refresh_token = json_body[u'refreshToken']
else:
raise AuthError(r1.json())

def _build_headers(self, content_type):
result = {"Accept": "application/json",
"Authorization": "Bearer " + self.access_token}
if content_type != "":
result["Content-type"] = content_type
return result

def get(self, uri, params=None):
if params is None:
params = {}
return self._do_call(uri, "GET", params=params)

def post_multi_part(self, uri, files):
#use empty string for content type so we don't set it
return self._do_call(uri, "POST", files=files, content_type="")

def post(self, uri, json=None):
if json is not None:
return self._do_call(uri, "POST", body=json)
else:
return self._do_call(uri, "POST")

def put(self, uri, json):
return self._do_call(uri, "PUT", body=json)

def patch(self, uri, json):
return self._do_call(uri, "PATCH", body=json)

def delete(self, uri):
return self._do_call(uri, "DELETE")

def _do_call(self, uri, method, params=None, body=None, retry=True, files=None, content_type = "application/json"):
h1 = self._get_connection()
r1 = requests.request(method, h1+uri, params=params, data=body, headers=self._build_headers(content_type), files=files)
# bad access token = status 400,
# body = {"errorCode":60001,"errorMessage":"invalid_grant:token not found, expired or invalid"}
if r1.status_code == requests.codes.NO_CONTENT:
return {}
json_body = r1.json()
# if this is a background task, add the task id to the body
if r1.status_code == requests.codes.ACCEPTED:
json_body['task_id'] = r1.headers['x-task-id']
if type(json_body) is dict:
if retry and u'errorCode' in json_body and json_body[u'errorCode'] == 60001:
self._refresh()
json_body = self._do_call(uri, method, params, body, False)
#disabling error raising for now, because it only happens for batch
#because all other errors are returned in a list, not in a dict
#should have been raising errors for those, too, but haven't been
#elif r1.status_code >= requests.codes.BAD_REQUEST:
# raise RestError(json_body)
return json_body
# Copyright 2000 - 2013 NeuStar, Inc.All rights reserved.
# NeuStar, the Neustar logo and related names and logos are registered
# trademarks, service marks or tradenames of NeuStar, Inc. All other
# product names, company names, marks, logos and symbols may be trademarks
# of their respective owners.
__author__ = 'Jon Bodner'

# store the URL and the access/refresh tokens as state
import requests

class AuthError(Exception):
def __init__(self, message):
self.message = message

def __str__(self):
return repr(self.message)


class RestError(Exception):
def __init__(self, message):
self.message = message

def __str__(self):
return repr(self.message)


class RestApiConnection:
def __init__(self, proxy, use_http=False, host="restapi.ultradns.com"):
self.use_http = use_http
self.host = host
self.access_token = ""
self.refresh_token = ""
self.proxy = proxy

def _get_connection(self):
if self.use_http:
return "http://"+ self.host
else:
return "https://"+ self.host

# Authentication
# We need the ability to take in a username and password and get
# an auth token and a refresh token. If any request fails due
# to an invalid auth token, refresh must be automatically invoked, the
# new auth token and refresh token stored, and the request tried again
# with the new auth token.
def auth(self, username, password):
h1 = self._get_connection()
payload = {"grant_type":"password", "username":username, "password":password}
r1 = requests.post(h1+"/v1/authorization/token",data=payload, proxies=self.proxy)
if r1.status_code == requests.codes.OK:
json_body = r1.json()
self.access_token = json_body[u'accessToken']
self.refresh_token = json_body[u'refreshToken']
else:
raise AuthError(r1.json())

def _refresh(self):
h1 = self._get_connection()
payload = {"grant_type":"refresh_token","refresh_token":self.refresh_token}
r1 = requests.post(h1+"/v1/authorization/token", data=payload, proxies=self.proxy)
if r1.status_code == requests.codes.OK:
json_body = r1.json()
self.access_token = json_body[u'accessToken']
self.refresh_token = json_body[u'refreshToken']
else:
raise AuthError(r1.json())

def _build_headers(self, content_type):
result = {"Accept": "application/json",
"Authorization": "Bearer " + self.access_token}
if content_type != "":
result["Content-type"] = content_type
return result

def get(self, uri, params=None):
if params is None:
params = {}
return self._do_call(uri, "GET", params=params)

def post_multi_part(self, uri, files):
#use empty string for content type so we don't set it
return self._do_call(uri, "POST", files=files, content_type="")

def post(self, uri, json=None):
if json is not None:
return self._do_call(uri, "POST", body=json)
else:
return self._do_call(uri, "POST")

def put(self, uri, json):
return self._do_call(uri, "PUT", body=json)

def patch(self, uri, json):
return self._do_call(uri, "PATCH", body=json)

def delete(self, uri):
return self._do_call(uri, "DELETE")

def _do_call(self, uri, method, params=None, body=None, retry=True, files=None, content_type = "application/json"):
h1 = self._get_connection()
r1 = requests.request(method, h1+uri, params=params, data=body, headers=self._build_headers(content_type), files=files, proxies=self.proxy)
# bad access token = status 400,
# body = {"errorCode":60001,"errorMessage":"invalid_grant:token not found, expired or invalid"}
if r1.status_code == requests.codes.NO_CONTENT:
return {}
json_body = r1.json()
# if this is a background task, add the task id to the body
if r1.status_code == requests.codes.ACCEPTED:
json_body['task_id'] = r1.headers['x-task-id']
if type(json_body) is dict:
if retry and u'errorCode' in json_body and json_body[u'errorCode'] == 60001:
self._refresh()
json_body = self._do_call(uri, method, params, body, False)
#disabling error raising for now, because it only happens for batch
#because all other errors are returned in a list, not in a dict
#should have been raising errors for those, too, but haven't been
#elif r1.status_code >= requests.codes.BAD_REQUEST:
# raise RestError(json_body)
return json_body
Loading