Skip to content

Commit f55d9ea

Browse files
committed
Merge pull request #412 from FindTheBest/master
Python/PHP Multipart-Form request support
2 parents 87be442 + 0f041da commit f55d9ea

File tree

4 files changed

+57
-10
lines changed

4 files changed

+57
-10
lines changed

src/main/resources/php/Swagger.mustache

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ class APIClient {
7777
$headers[] = "api_key: " . $this->apiKey;
7878
}
7979

80-
if (is_object($postData) or is_array($postData)) {
80+
81+
if (strpos($headers['Content-Type'], "multipart/form-data") < 0 and (is_object($postData) or is_array($postData))) {
8182
$postData = json_encode($this->sanitizeForSerialization($postData));
8283
}
8384

src/main/resources/php/api.mustache

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@ class {{classname}} {
7272
}
7373
{{#formParams}}
7474
if(${{paramName}} != null) {
75+
{{#notFile}}
7576
$body['{{paramName}}'] = ${{paramName}};
77+
{{/notFile}}
78+
{{#isFile}}
79+
$body['{{paramName}}'] = '@' . ${{paramName}};
80+
{{/isFile}}
7681
}
7782
{{/formParams}}
7883
if (empty($body)) {

src/main/resources/python/api.mustache

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,11 @@ class {{classname}}(object):
5959
queryParams = {}
6060
headerParams = {}
6161
formParams = {}
62+
files = {}
6263
bodyParam = None
6364

65+
headerParams['Content-type'] = '{{#consumes}}{{mediaType}}{{#hasMore}},{{/hasMore}}{{/consumes}}'
66+
6467
{{#queryParams}}
6568
if ('{{paramName}}' in params):
6669
queryParams['{{paramName}}'] = self.apiClient.toPathValue(params['{{paramName}}'])
@@ -80,10 +83,9 @@ class {{classname}}(object):
8083

8184
{{#formParams}}
8285
if ('{{paramName}}' in params):
83-
formParams['{{paramName}}'] = params['{{paramName}}']
86+
{{#notFile}}formParams['{{paramName}}'] = params['{{paramName}}']{{/notFile}}{{#isFile}}files['{{paramName}}'] = params['{{paramName}}']{{/isFile}}
87+
{{newline}}
8488
{{/formParams}}
85-
if formParams:
86-
headerParams['Content-type'] = 'application/x-www-form-urlencoded'
8789

8890
{{#bodyParam}}
8991
if ('{{paramName}}' in params):
@@ -93,7 +95,7 @@ class {{classname}}(object):
9395
postData = (formParams if formParams else bodyParam)
9496

9597
response = self.apiClient.callAPI(resourcePath, method, queryParams,
96-
postData, headerParams)
98+
postData, headerParams, files=files)
9799

98100
{{#returnType}}
99101
if not response:

src/main/resources/python/swagger.mustache

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import urllib2
1212
import httplib
1313
import json
1414
import datetime
15+
import mimetypes
16+
import random
17+
import string
1518

1619
from models import *
1720

@@ -26,17 +29,17 @@ class ApiClient:
2629
self.apiKey = apiKey
2730
self.apiServer = apiServer
2831
self.cookie = None
32+
self.boundary = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(30))
2933

3034
def callAPI(self, resourcePath, method, queryParams, postData,
31-
headerParams=None):
35+
headerParams=None, files=None):
3236

3337
url = self.apiServer + resourcePath
3438
headers = {}
3539
if headerParams:
3640
for param, value in headerParams.iteritems():
3741
headers[param] = value
3842

39-
#headers['Content-type'] = 'application/json'
4043
headers['api_key'] = self.apiKey
4144

4245
if self.cookie:
@@ -60,12 +63,16 @@ class ApiClient:
6063
elif method in ['POST', 'PUT', 'DELETE']:
6164

6265
if postData:
63-
data = self.sanitizeForSerialization(postData)
66+
postData = self.sanitizeForSerialization(postData)
6467
if 'Content-type' not in headers:
6568
headers['Content-type'] = 'application/json'
66-
data = json.dumps(data)
69+
data = json.dumps(postData)
70+
elif headers['Content-type'] == 'multipart/form-data':
71+
data = self.buildMultipartFormData(postData, files)
72+
headers['Content-type'] = 'multipart/form-data; boundary={0}'.format(self.boundary)
73+
headers['Content-length'] = str(len(data))
6774
else:
68-
data = urllib.urlencode(data)
75+
data = urllib.urlencode(postData)
6976

7077
else:
7178
raise Exception('Method ' + method + ' is not recognized.')
@@ -127,6 +134,38 @@ class ApiClient:
127134
elif type(postData) not in safeToDump:
128135
data = json.dumps(postData.__dict__)
129136

137+
def buildMultipartFormData(self, postData, files):
138+
def escape_quotes(s):
139+
return s.replace('"', '\\"')
140+
141+
lines = []
142+
143+
for name, value in postData.items():
144+
lines.extend((
145+
'--{0}'.format(self.boundary),
146+
'Content-Disposition: form-data; name="{0}"'.format(escape_quotes(name)),
147+
'',
148+
str(value),
149+
))
150+
151+
for name, filepath in files.items():
152+
f = open(filepath, 'r')
153+
filename = filepath.split('/')[-1]
154+
mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
155+
lines.extend((
156+
'--{0}'.format(self.boundary),
157+
'Content-Disposition: form-data; name="{0}"; filename="{1}"'.format(escape_quotes(name), escape_quotes(filename)),
158+
'Content-Type: {0}'.format(mimetype),
159+
'',
160+
f.read()
161+
))
162+
163+
lines.extend((
164+
'--{0}--'.format(self.boundary),
165+
''
166+
))
167+
return '\r\n'.join(lines)
168+
130169
def deserialize(self, obj, objClass):
131170
"""Derialize a JSON string into an object.
132171

0 commit comments

Comments
 (0)