This repository has been archived by the owner on Dec 15, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/master' into feature-docs
- Loading branch information
Showing
7 changed files
with
210 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
from negotiator import ContentNegotiator, AcceptParameters, ContentType | ||
import json | ||
|
||
|
||
class OutputRegistry(object): | ||
|
||
def __init__(self, defaultOutputFormat): | ||
self._outputFormats = {} | ||
self._outputFormatsPreference = [] | ||
self.defaultOutputFormat = defaultOutputFormat | ||
|
||
def getFormat(self, request): | ||
|
||
defaultOutput = AcceptParameters( | ||
ContentType(self.defaultOutputFormat, params='q=0')) | ||
|
||
acceptable = [defaultOutput] + [AcceptParameters(ContentType(x)) for x in self._outputFormatsPreference] | ||
|
||
cn = ContentNegotiator(defaultOutput, acceptable) | ||
if request.requestHeaders.hasHeader("Accept"): | ||
kwargs = {"accept": request.requestHeaders.getRawHeaders("Accept")[0]} | ||
else: | ||
kwargs = {} | ||
|
||
accp = cn.negotiate(**kwargs) | ||
|
||
return str(accp.content_type) if accp else None | ||
|
||
|
||
def renderAutomaticResponse(self, request, status, data): | ||
|
||
f = self.getFormat(request) | ||
return self._outputFormats[f](status, data) | ||
|
||
|
||
def register(self, acceptHeader, func): | ||
""" | ||
Register an output format. | ||
""" | ||
self._outputFormats[acceptHeader] = func | ||
self._outputFormatsPreference.append(acceptHeader) | ||
|
||
def JSendJSONOutputFormat(status, data): | ||
""" | ||
Implements the JSend output format, serialised to JSON. | ||
""" | ||
|
||
resp = { | ||
"status": status, | ||
"data": data | ||
} | ||
|
||
return json.dumps(resp) | ||
|
||
def DebuggableJSendJSONOutputFormat(status, data): | ||
|
||
resp = { | ||
"status": status, | ||
"data": data | ||
} | ||
|
||
return json.dumps(resp, sort_keys=True, indent=4, separators=(',', ': ')) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
from twisted.trial.unittest import TestCase | ||
|
||
from saratoga import api, outputFormats | ||
from saratoga.test.test_api import APIImpl, APIDef | ||
|
||
class SaratogaAcceptHeaderTests(TestCase): | ||
|
||
def setUp(self): | ||
|
||
def respJSON(status, data): | ||
return "JSON" | ||
|
||
def respYAML(status, data): | ||
return "YAML" | ||
|
||
o = outputFormats.OutputRegistry("application/json") | ||
o.register("application/yaml", respYAML) | ||
o.register("application/json", respJSON) | ||
o.register("application/debuggablejson", | ||
outputFormats.DebuggableJSendJSONOutputFormat) | ||
|
||
self.api = api.SaratogaAPI(APIImpl, APIDef, outputRegistry = o) | ||
|
||
def test_noneGiven(self): | ||
|
||
def rendered(request): | ||
self.assertEqual( | ||
request.getWrittenData(), | ||
"JSON" | ||
) | ||
self.assertEqual(request.code, 200) | ||
|
||
return self.api.test("/v1/example").addCallback(rendered) | ||
|
||
def test_nonDefaultGiven(self): | ||
|
||
def rendered(request): | ||
self.assertEqual( | ||
request.getWrittenData(), | ||
"YAML" | ||
) | ||
self.assertEqual(request.code, 200) | ||
|
||
return self.api.test("/v1/example", | ||
headers={"Accept": ["application/yaml"]} | ||
).addCallback(rendered) | ||
|
||
def test_unknownDefaultGiven(self): | ||
|
||
def rendered(request): | ||
self.assertEqual( | ||
request.getWrittenData(), | ||
"406 Not Acceptable, please use one of: application/yaml, appli" | ||
"cation/json, application/debuggablejson" | ||
) | ||
self.assertEqual(request.code, 406) | ||
|
||
return self.api.test("/v1/example", | ||
headers={"Accept": ["application/whatever"]} | ||
).addCallback(rendered) | ||
|
||
def test_debuggableJSend(self): | ||
|
||
def rendered(request): | ||
self.assertEqual( | ||
request.getWrittenData(), | ||
'{\n "data": {},\n "status": "success"\n}' | ||
) | ||
self.assertEqual(request.code, 200) | ||
|
||
return self.api.test("/v1/example", | ||
headers={"Accept": ["application/debuggablejson"]} | ||
).addCallback(rendered) | ||
|
||
def test_listDefaultGiven(self): | ||
|
||
def rendered(request): | ||
self.assertEqual( | ||
request.getWrittenData(), | ||
'JSON' | ||
) | ||
self.assertEqual(request.code, 200) | ||
|
||
return self.api.test("/v1/example", | ||
headers={"Accept": ["text/html,application/xhtml+xm" | ||
"l,application/xml;q=0.9," | ||
"*/*;q=0.8"]} | ||
).addCallback(rendered) | ||
|
||
def test_qualityPreferencesGiven(self): | ||
|
||
def rendered(request): | ||
self.assertEqual( | ||
request.getWrittenData(), | ||
'YAML' | ||
) | ||
self.assertEqual(request.code, 200) | ||
|
||
return self.api.test("/v1/example", | ||
headers={"Accept": ["text/html,application/xhtml+xm" | ||
"l,application/json;q=0.7," | ||
"application/yaml;q=0.8"]} | ||
).addCallback(rendered) | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,4 +37,5 @@ deps = | |
mock | ||
jsonschema | ||
httpsig | ||
negotiator | ||
commands = trial saratoga |