Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
I am doing HTTP wrong
Search
Armin Ronacher
May 13, 2012
Programming
5.3k
23
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
I am doing HTTP wrong
A fresh look at HTTP for agile languages (more importantly: Python)
Armin Ronacher
May 13, 2012
More Decks by Armin Ronacher
See All by Armin Ronacher
Reflections on building cloud and local hybrid machine entities
mitsuhiko
1
190
Agentic Coding: The Future of Software Development with Agents
mitsuhiko
0
930
Do Dumb Things
mitsuhiko
0
1k
No Assumptions
mitsuhiko
0
440
The Complexity Genie
mitsuhiko
0
350
The Catch in Rye: Seeding Change and Lessons Learned
mitsuhiko
0
460
Runtime Objects in Rust
mitsuhiko
0
450
Rust at Sentry
mitsuhiko
0
620
Overcoming Variable Payloads to Optimize for Performance
mitsuhiko
0
320
Other Decks in Programming
See All in Programming
【高い買い物LT会】初任給で話題の国産フィジカルAIを買った話
akagami
PRO
0
160
How I Stole PSI from Android Studio - DroidKaigi2026
worker8
0
130
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
110
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
190
海上で動くGoサーバー: goroutineとchannelでさばく航行データストリーム
atsuki_seo
0
720
AHC070解法紹介
eijirou
0
120
AgentCore CLI で進化した AWS での AI エージェントの作り方 : 必要な機能を必要な時に
icoxfog417
PRO
3
350
20260914 AIエージェント時代のPlatform Engineering LLM基盤とプロダクトの責務境界線
kanfab1
7
2k
The Good Stuff, Not the Slop: Engineering High-Quality Android Apps with Modern AI Tooling
danybony
1
250
AI に Inclusive UI を書かせよう — Design Rules Skill で Compose UI を作り直す
theoriatec2024
1
490
AIエージェント時代のコードレビューを設計する
nogu66
6
2.7k
WebAssembly in Android Apps 〜 WASMはJNIの夢を見るか
keiji
1
110
Featured
See All Featured
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
470
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
430
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
Darren the Foodie - Storyboard
khoart
PRO
4
3.9k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
46k
How to train your dragon (web standard)
notwaldorf
97
6.8k
How to make the Groovebox
asonas
2
2.4k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2.1k
Mobile First: as difficult as doing things right
swwweet
225
10k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
290
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.9k
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
700
Transcript
I am doing HTTP wrong — a presentation by Armin
Ronacher @mitsuhiko
The Web developer's Evolution
echo
request.send_header(…) request.end_headers() request.write(…)
return Response(…)
Why Stop there?
What do we love about HTTP?
Text Based
REST
Cacheable
Content Negotiation
Well Supported
Works where TCP doesn't
Somewhat Simple
Upgrades to custom protocols
Why does my application look like HTTP?
everybody does it
Natural Conclusion
we can do better!
we're a level too low
Streaming: one piece at the time, constant memory usage, no
seeking.
Buffering: have some data in memory, variable memory usage, seeking.
TYPICAL Request / Response Cycle User Agent Proxy Server Application
Stream “Buffered” Dispatcher View
In Python Terms def application(environ, start_response): # Step 1: acquire
data data = environ['wsgi.input'].read(...) # Step 2: process data response = process_data(data) # Step 3: respond start_response('200 OK', [('Content-Type', 'text/plain')]) return [response]
One Level Up s = socket.accept() f = s.makefile('rb') requestline
= f.readline() headers = [] while 1: headerline = f.readline() if headerline == '\r\n': break headers.append(headerline)
Weird Mixture on the app request.headers <- buffered request.form <-
buffered request.files <- buffered to disk request.body <- streamed
HTTP's Limited signalling Strict Request / Response The only communication
during request from the server to the client is closing the connection once you started accepting the body.
Bailing out early def application(request): # At this point, headers
are parsed, everything else # is not parsed yet. if request.content_length > TWO_MEGABYTES: return error_response() ...
Bailing out a little bit later def application(request): # Read
a little bit of data request.input.read(4096) # You just committed to accepting data, now you have to # read everything or the browser will be very unhappy and # Just time out. No more responding with 413 ...
Rejecting Form fields -> memory File uploads -> disk What's
your limit? 16MB in total? All could go to memory. Reject file sizes individually? Needs overall check as well!
The Consequences How much data do you accept? Limit the
overall request size? Not helpful because all of it could be in-memory
It's not just limiting Consider a layered system How many
of you write code that streams? What happens if you pass streamed data through your layers?
A new approach
Dynamic typing made us lazy
we're trying to solve both use cases in one we're
not supporting either well
How we do it Hide HTTP from the apps HTTP
is an implementation detail
Pseudocode user_pagination = make_pagination_schema(User) @export( specs=[('page', types.Int32()), ('per_page', types.Int32())], returns=user_pagination,
semantics='select', http_path='/users/' ) def list_users(page, per_page): users = User.query.paginate(page, per_page) return users.to_dict()
Types are specific user_type = types.Object([ ('username', types.String(30)), ('email', types.Optional(types.String(250))),
('password_hash', types.String(250)), ('is_active', types.Boolean()), ('registration_date', types.DateTime()) ])
Why? Support for different input/output formats keyless transport support for
non-HTTP no hash collision attacks :-) Predictable memory usage
Comes for free Easier to test Helps documenting the public
APIs Catches common errors early Handle errors without invoking code Predictable dictionary ordering
Strict vs Lenient
Rule of Thumb Be strict in what you send, but
generous in what you receive — variant of Postel's Law
Being Generous In order to be generous you need to
know what to receive. Just accepting any input is a security disaster waiting to happen.
Support unsupported types { "foo": [1, 2, 3], "bar": {"key":
"value"}, "now": "Thu, 10 May 2012 14:16:09 GMT" } foo.0=1& foo.1=2& foo.2=3& bar.key=value& now=Thu%2C%2010%20May%202012%2014:16:09%20GMT
Solves the GET issue GET has no body parameters have
to be URL encoded inconsistency with JSON post requests
Where is the streaming?
There is none
there are always two sides to an API
If the server has streaming endpoints — the client will
have to support them as well
For things that need actual streaming we have separate endpoints.
streaming is different
but we can stream until we need buffering
Discard useless stuff { "foo": [list, of, thousands, of, items,
we don't, need], "an_important_key": "we're actually interested in" }
What if I don't make an API?
modern web apps are APIs
Dumb client? Move the client to the server
Q&A
Oh hai. We're hiring http://fireteam.net/careers