Skip to content

Instantly share code, notes, and snippets.

@estebistec
Last active May 15, 2016 21:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save estebistec/b6667ecaea0ff20c4356ca6d8c5b1f58 to your computer and use it in GitHub Desktop.
Save estebistec/b6667ecaea0ff20c4356ca6d8c5b1f58 to your computer and use it in GitHub Desktop.
morepath #70: Content negotiation: Look at accept header in request
# -*- coding: utf-8 -*
import morepath
import reg
from morepath import generic
from webob.acceptparse import MIMEAccept
from webob.exc import HTTPNotAcceptable
class MediaTypeIndex(reg.KeyIndex):
@property
def offered_types(self):
return self.d.keys()
def permutations(self, key):
if isinstance(key, str):
key = MIMEAccept(key)
yield key.best_match(self.offered_types)
DEFAULT_RESPONSE_TYPE = 'text/html'
class App(morepath.App):
pass
@App.predicate(generic.view, name='accept', default=DEFAULT_RESPONSE_TYPE,
index=MediaTypeIndex,
after=morepath.LAST_VIEW_PREDICATE)
def accept_header_predicate(request):
return request.accept
@App.predicate_fallback(generic.view, accept_header_predicate)
def media_type_not_found(self, request):
raise HTTPNotAcceptable()
@App.path(path='')
class Root(object):
pass
@App.html(model=Root, accept='text/html')
def hello_world(self, request):
return "<p>Hello world!</p>"
@App.view(model=Root, accept='text/*')
def hello_world_any_text(self, request):
return self.hello_world(request)
@App.json(model=Root, accept='application/json')
def hello_world_json(self, request):
return {'message': "Hello world!"}
# Example 2: Another resource model with different media type offerings
# NOTE Including, not having the predicate-wide default
@App.path(path='/health')
class HealthCheck(object):
pass
@App.json(model=HealthCheck, accept="application/json")
def health_check(self, request):
return {"health_status": "GOOD"}
@App.json(model=HealthCheck, accept="application/hal+json")
def health_check_hal(self, request):
return {"health_status": "GOOD", "_links": {"self": {"url": request.link(self)}}}
if __name__ == '__main__':
morepath.autocommit()
morepath.run(App())
* Rebuilt URL to: http://127.0.0.1:5000/
* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.43.0
> Accept: text/html
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Sun, 15 May 2016 21:53:19 GMT
< Server: WSGIServer/0.2 CPython/3.5.1
< Content-Type: text/html; charset=UTF-8
< Content-Length: 19
<
{ [19 bytes data]
100 19 100 19 0 0 9200 0 --:--:-- --:--:-- --:--:-- 19000
* Closing connection 0
<p>Hello world!</p>* Rebuilt URL to: http://127.0.0.1:5000/
* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.43.0
> Accept: application/json
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Sun, 15 May 2016 21:53:19 GMT
< Server: WSGIServer/0.2 CPython/3.5.1
< Content-Type: application/json
< Content-Length: 27
<
{ [27 bytes data]
100 27 100 27 0 0 7642 0 --:--:-- --:--:-- --:--:-- 13500
* Closing connection 0
{"message": "Hello world!"}* Rebuilt URL to: http://127.0.0.1:5000/
* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.43.0
> Accept: application/something-else
>
* HTTP 1.0, assume close after body
< HTTP/1.0 406 Not Acceptable
< Date: Sun, 15 May 2016 21:53:19 GMT
< Server: WSGIServer/0.2 CPython/3.5.1
< Content-Length: 140
< Content-Type: text/plain; charset=UTF-8
<
{ [140 bytes data]
100 140 100 140 0 0 26007 0 --:--:-- --:--:-- --:--:-- 35000
* Closing connection 0
406 Not Acceptable
The resource could not be generated that was acceptable to your browser (content of type application/something-else.
* Rebuilt URL to: http://127.0.0.1:5000/
* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.43.0
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Sun, 15 May 2016 21:53:19 GMT
< Server: WSGIServer/0.2 CPython/3.5.1
< Content-Type: text/html; charset=UTF-8
< Content-Length: 19
<
{ [19 bytes data]
100 19 100 19 0 0 9254 0 --:--:-- --:--:-- --:--:-- 19000
* Closing connection 0
<p>Hello world!</p>* Rebuilt URL to: http://127.0.0.1:5000/
* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.43.0
> Accept: application/*;q=0.5, text/*;q=0.5
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Sun, 15 May 2016 21:53:19 GMT
< Server: WSGIServer/0.2 CPython/3.5.1
< Content-Type: text/html; charset=UTF-8
< Content-Length: 19
<
{ [19 bytes data]
100 19 100 19 0 0 7609 0 --:--:-- --:--:-- --:--:-- 9500
* Closing connection 0
<p>Hello world!</p>* Rebuilt URL to: http://127.0.0.1:5000/
* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.43.0
> Accept: application/hal+json;q=1, application/json;q=0.8
>
* HTTP 1.0, assume close after body
< HTTP/1.0 406 Not Acceptable
< Date: Sun, 15 May 2016 21:53:19 GMT
< Server: WSGIServer/0.2 CPython/3.5.1
< Content-Length: 226
< Content-Type: application/json; charset=utf-8
<
{ [226 bytes data]
100 226 100 226 0 0 21705 0 --:--:-- --:--:-- --:--:-- 22600
* Closing connection 0
{"message": "The resource could not be generated that was acceptable to your browser\n(content of type application/hal+json;q=1, application/json;q=0.8. <br /><br />\n", "code": "406 Not Acceptable", "title": "Not Acceptable"}* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /health HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.43.0
> Accept: application/*;q=0.5, text/*;q=0.5
>
* HTTP 1.0, assume close after body
< HTTP/1.0 406 Not Acceptable
< Date: Sun, 15 May 2016 21:53:19 GMT
< Server: WSGIServer/0.2 CPython/3.5.1
< Content-Length: 147
< Content-Type: text/plain; charset=UTF-8
<
{ [147 bytes data]
100 147 100 147 0 0 55408 0 --:--:-- --:--:-- --:--:-- 73500
* Closing connection 0
406 Not Acceptable
The resource could not be generated that was acceptable to your browser (content of type application/*;q=0.5, text/*;q=0.5.
* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /health HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.43.0
> Accept: application/json
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Sun, 15 May 2016 21:53:19 GMT
< Server: WSGIServer/0.2 CPython/3.5.1
< Content-Type: application/json
< Content-Length: 25
<
{ [25 bytes data]
100 25 100 25 0 0 9245 0 --:--:-- --:--:-- --:--:-- 12500
* Closing connection 0
{"health_status": "GOOD"}* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /health HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.43.0
> Accept: application/hal+json;q=1, application/json;q=0.8
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Date: Sun, 15 May 2016 21:53:19 GMT
< Server: WSGIServer/0.2 CPython/3.5.1
< Content-Type: application/json
< Content-Length: 86
<
{ [86 bytes data]
100 86 100 86 0 0 27634 0 --:--:-- --:--:-- --:--:-- 43000
* Closing connection 0
{"_links": {"self": {"url": "http://127.0.0.1:5000/health"}}, "health_status": "GOOD"}* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /health HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.43.0
> Accept: text/html
>
* HTTP 1.0, assume close after body
< HTTP/1.0 406 Not Acceptable
< Date: Sun, 15 May 2016 21:53:19 GMT
< Server: WSGIServer/0.2 CPython/3.5.1
< Content-Length: 230
< Content-Type: text/html; charset=UTF-8
<
{ [230 bytes data]
100 230 100 230 0 0 70921 0 --:--:-- --:--:-- --:--:-- 76666
* Closing connection 0
<html>
<head>
<title>406 Not Acceptable</title>
</head>
<body>
<h1>406 Not Acceptable</h1>
The resource could not be generated that was acceptable to your browser
(content of type text/html. <br /><br />
</body>
</html>* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /health HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.43.0
> Accept: application/something-else
>
* HTTP 1.0, assume close after body
< HTTP/1.0 406 Not Acceptable
< Date: Sun, 15 May 2016 21:53:19 GMT
< Server: WSGIServer/0.2 CPython/3.5.1
< Content-Length: 140
< Content-Type: text/plain; charset=UTF-8
<
{ [140 bytes data]
100 140 100 140 0 0 54116 0 --:--:-- --:--:-- --:--:-- 70000
* Closing connection 0
406 Not Acceptable
The resource could not be generated that was acceptable to your browser (content of type application/something-else.
* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> GET /health HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.43.0
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 406 Not Acceptable
< Date: Sun, 15 May 2016 21:53:19 GMT
< Server: WSGIServer/0.2 CPython/3.5.1
< Content-Length: 117
< Content-Type: text/plain; charset=UTF-8
<
{ [117 bytes data]
100 117 100 117 0 0 47560 0 --:--:-- --:--:-- --:--:-- 58500
* Closing connection 0
406 Not Acceptable
The resource could not be generated that was acceptable to your browser (content of type */*.
curl http://127.0.0.1:5000 -H 'Accept: text/html' -v
curl http://127.0.0.1:5000 -H 'Accept: application/json' -v
curl http://127.0.0.1:5000 -H 'Accept: application/something-else' -v
curl http://127.0.0.1:5000 -H 'Accept: */*' -v
curl http://127.0.0.1:5000 -H 'Accept: application/*;q=0.5, text/*;q=0.5' -v
curl http://127.0.0.1:5000 -H 'Accept: application/hal+json;q=1, application/json;q=0.8' -v
curl http://127.0.0.1:5000/health -H 'Accept: application/*;q=0.5, text/*;q=0.5' -v
curl http://127.0.0.1:5000/health -H 'Accept: application/json' -v
curl http://127.0.0.1:5000/health -H 'Accept: application/hal+json;q=1, application/json;q=0.8' -v
curl http://127.0.0.1:5000/health -H 'Accept: text/html' -v
curl http://127.0.0.1:5000/health -H 'Accept: application/something-else' -v
curl http://127.0.0.1:5000/health -H 'Accept: */*' -v
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment