Add a Python (Flask) example - #6
Merged
Merged
Conversation
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A fifth example: the same payment, on Flask.
python-flask-js/implements exactly the sevenroutes of the server contract, with the same status codes, the same OAuth base string and the
same
sha1callback checksum as the other four.The model here is
nodejs-express-js, notgo-js— it is the other example built on aframework with a router and a static mount, so every handler is a transcription of one of its.
Two runtime dependencies, both unavoidable: Flask, which is the subject, and
cryptography, because Python has no RSA in the standard library. The gateway calls go through
urllib.requestand the tests throughunittest, so nothing is installed for either.Port 3004, prefix
/hosted-fields-examples-python.python app.pyfor development, gunicornunder systemd behind nginx in
deploy/.What the fifth language cost
scripts/sync-shared.sh: one line;e2e-tests/src/apps.ts: one registry entry. No spec changes;go-js/,nodejs-express-js/,php-js/ornextjs/.One small harness improvement came with it:
playwright.config.tshadapp.name === 'nextjs' ? 300_000 : 60_000for the readiness timeout, which a third slow-startingapp would have turned into a chain of name checks. It is now a
startTimeoutfield onAppUnderTest, so each entry states its own.Four places Python pushes back, and what was done about them
urlopenraises on every 4xx, and a gateway rejection is a 4xx carrying the JSON bodywith
error-message._postreadserror.read()anderror.codeoff theHTTPErroranddecodes them like any other reply; letting it propagate would turn every decline into a
502.Checked end to end: the
sale-errorscenario answers200with the gateway's message.errorhandler(Exception)would swallow Werkzeug'sNotFoundand answer502toevery 404, so the two handlers that call the gateway catch for themselves, as Go and PHP do.
quote's default issafe='/', which would leave the slashes in a URL-as-parameterunescaped and break the signature. The encoder is
quote(value, safe=''), and there is a testvector for exactly that.
json.dumpshas to be toldseparators=(',', ':')andensure_ascii=Falseto emit whatJSON.stringifydoes, soconfig.jsis the same script the other examples hand the page.Two things recorded rather than hidden: the bare prefix redirects with a 308, from Flask's own
strict_slashes(Express writes 302, Go and PHP 307 — all for the same relative-asset reason);and
ProxyFix(x_for=1)counts one trusted proxy from the right, so unlike the other examplesa caller cannot prepend an address of their own through a single nginx.
Checks
python -m compileallandpython -m unittest discover -s tests -t .— 13 tests, on the sameOAuth base-string and callback-checksum vectors the Go, Node and PHP suites pin. Added as a CI
job; no credentials needed, since the tests stub what
settings.pyvalidates at import.cd e2e-tests && npm test— 50 passed, ten per app. The emulator verifies the OAuthsignature against the generated public key and rejects a Sale whose amount is not the server's,
so the
cryptographysigning and the server-owned amount are checked on the wire. Thevirtualenv is built in
e2e-tests/.tmp/, next to the Go binary, so the suite still leaves everyapp directory as it found it.
./scripts/sync-shared.sh && git diff --exit-codeclean; the four existing apps still buildand test untouched.
config.jscarries a fresh ticket andno-store, the CSP namesthe SDK origin, a forged
controlgives403on both/resultand/result/callback, and{prefix}/app.py,{prefix}/.env,{prefix}/settings.pyand{prefix}/views/checkout.htmlall answer
404.No key, no
MERCHANT_CONTROLand no realENDPOINT_IDanywhere:.env.exampleand the deploytemplate carry placeholders only.