Merge pull request #416 from FindTheBest/develop_2.0

PHP/Python Enhancements
This commit is contained in:
Tony Tam 2015-02-08 22:15:34 -08:00
commit 781c9f7d83
4 changed files with 88 additions and 10 deletions

View File

@ -37,6 +37,16 @@ class APIClient {
$this->apiServer = $apiServer; $this->apiServer = $apiServer;
} }
/**
* @param integer $seconds Number of seconds before timing out [set to 0 for no timeout]
*/
public function setTimeout($seconds) {
if (!is_numeric($seconds)) {
throw new Exception('Timeout variable must be numeric.');
}
$this->curl_timout = $seconds;
}
/** /**
* @param string $resourcePath path to method endpoint * @param string $resourcePath path to method endpoint
@ -65,14 +75,16 @@ class APIClient {
$headers[] = "api_key: " . $this->apiKey; $headers[] = "api_key: " . $this->apiKey;
} }
if (is_object($postData) or is_array($postData)) { if (strpos($headers['Content-Type'], "multipart/form-data") < 0 and (is_object($postData) or is_array($postData))) {
$postData = json_encode($this->sanitizeForSerialization($postData)); $postData = json_encode($this->sanitizeForSerialization($postData));
} }
$url = $this->apiServer . $resourcePath; $url = $this->apiServer . $resourcePath;
$curl = curl_init(); $curl = curl_init();
curl_setopt($curl, CURLOPT_TIMEOUT, 5); if ($this->curl_timout) {
curl_setopt($curl, CURLOPT_TIMEOUT, $this->curl_timout);
}
// return the result on success, rather than just TRUE // return the result on success, rather than just TRUE
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

View File

@ -44,6 +44,7 @@ class {{classname}} {
$method = "{{httpMethod}}"; $method = "{{httpMethod}}";
$queryParams = array(); $queryParams = array();
$headerParams = array(); $headerParams = array();
$formParams = array();
$headerParams['Accept'] = '{{#produces}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/produces}}'; $headerParams['Accept'] = '{{#produces}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/produces}}';
$headerParams['Content-Type'] = '{{#consumes}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/consumes}}'; $headerParams['Content-Type'] = '{{#consumes}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/consumes}}';
@ -60,12 +61,21 @@ class {{classname}} {
$resourcePath = str_replace("{" . "{{paramName}}" . "}", $resourcePath = str_replace("{" . "{{paramName}}" . "}",
$this->apiClient->toPathValue(${{paramName}}), $resourcePath); $this->apiClient->toPathValue(${{paramName}}), $resourcePath);
}{{/pathParams}} }{{/pathParams}}
{{#formParams}}
if (${{paramName}} != null) {
$formParams[{{paramName}}] = {{#isFile}}'@' . {{/isFile}}${{paramName}}
}{{/formParams}}
{{#bodyParams}}// body params {{#bodyParams}}// body params
$body = null; $body = null;
if (isset(${{paramName}})) { if (isset(${{paramName}})) {
$body = ${{paramName}}; $body = ${{paramName}};
}{{/bodyParams}}
$body = $body ?: $formParams;
if (strpos($headerParams['Content-Type'], "application/x-www-form-urlencoded") > -1) {
$body = http_build_query($body);
} }
{{/bodyParams}}
// make the API Call // make the API Call
$response = $this->apiClient->callAPI($resourcePath, $method, $response = $this->apiClient->callAPI($resourcePath, $method,

View File

@ -58,6 +58,10 @@ class {{classname}}(object):
queryParams = {} queryParams = {}
headerParams = {} headerParams = {}
formParams = {}
files = {}
bodyParam = None
$headerParams['Accept'] = '{{#produces}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/produces}}'; $headerParams['Accept'] = '{{#produces}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/produces}}';
$headerParams['Content-Type'] = '{{#consumes}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/consumes}}'; $headerParams['Content-Type'] = '{{#consumes}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/consumes}}';
@ -78,10 +82,20 @@ class {{classname}}(object):
replacement) replacement)
{{/pathParams}} {{/pathParams}}
postData = (params['body'] if 'body' in params else None) {{#formParams}}
if ('{{paramName}}' in params):
{{#notFile}}formParams['{{paramName}}'] = params['{{paramName}}']{{/notFile}}{{#isFile}}files['{{paramName}}'] = params['{{paramName}}']{{/isFile}}
{{/formParams}}
{{#bodyParam}}
if ('{{paramName}}' in params):
bodyParam = params['{{paramName}}']
{{/bodyParam}}
postData = (formParams if formParams else bodyParam)
response = self.apiClient.callAPI(resourcePath, method, queryParams, response = self.apiClient.callAPI(resourcePath, method, queryParams,
postData, headerParams) postData, headerParams, files=files)
{{#returnType}} {{#returnType}}
if not response: if not response:

View File

@ -12,6 +12,9 @@ import urllib2
import httplib import httplib
import json import json
import datetime import datetime
import mimetypes
import random
import string
from models import * from models import *
@ -26,9 +29,10 @@ class ApiClient:
self.apiKey = apiKey self.apiKey = apiKey
self.apiServer = apiServer self.apiServer = apiServer
self.cookie = None self.cookie = None
self.boundary = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(30))
def callAPI(self, resourcePath, method, queryParams, postData, def callAPI(self, resourcePath, method, queryParams, postData,
headerParams=None): headerParams=None, files=None):
url = self.apiServer + resourcePath url = self.apiServer + resourcePath
headers = {} headers = {}
@ -36,7 +40,6 @@ class ApiClient:
for param, value in headerParams.iteritems(): for param, value in headerParams.iteritems():
headers[param] = value headers[param] = value
#headers['Content-type'] = 'application/json'
headers['api_key'] = self.apiKey headers['api_key'] = self.apiKey
if self.cookie: if self.cookie:
@ -60,9 +63,16 @@ class ApiClient:
elif method in ['POST', 'PUT', 'DELETE']: elif method in ['POST', 'PUT', 'DELETE']:
if postData: if postData:
headers['Content-type'] = 'application/json' postData = self.sanitizeForSerialization(postData)
data = self.sanitizeForSerialization(postData) if 'Content-type' not in headers:
data = json.dumps(data) headers['Content-type'] = 'application/json'
data = json.dumps(postData)
elif headers['Content-type'] == 'multipart/form-data':
data = self.buildMultipartFormData(postData, files)
headers['Content-type'] = 'multipart/form-data; boundary={0}'.format(self.boundary)
headers['Content-length'] = str(len(data))
else:
data = urllib.urlencode(postData)
else: else:
raise Exception('Method ' + method + ' is not recognized.') raise Exception('Method ' + method + ' is not recognized.')
@ -124,6 +134,38 @@ class ApiClient:
elif type(postData) not in safeToDump: elif type(postData) not in safeToDump:
data = json.dumps(postData.__dict__) data = json.dumps(postData.__dict__)
def buildMultipartFormData(self, postData, files):
def escape_quotes(s):
return s.replace('"', '\\"')
lines = []
for name, value in postData.items():
lines.extend((
'--{0}'.format(self.boundary),
'Content-Disposition: form-data; name="{0}"'.format(escape_quotes(name)),
'',
str(value),
))
for name, filepath in files.items():
f = open(filepath, 'r')
filename = filepath.split('/')[-1]
mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
lines.extend((
'--{0}'.format(self.boundary),
'Content-Disposition: form-data; name="{0}"; filename="{1}"'.format(escape_quotes(name), escape_quotes(filename)),
'Content-Type: {0}'.format(mimetype),
'',
f.read()
))
lines.extend((
'--{0}--'.format(self.boundary),
''
))
return '\r\n'.join(lines)
def deserialize(self, obj, objClass): def deserialize(self, obj, objClass):
"""Derialize a JSON string into an object. """Derialize a JSON string into an object.