Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Documentation for the "request" object #706

Closed
simonw opened this issue Mar 22, 2020 · 6 comments
Closed

Documentation for the "request" object #706

simonw opened this issue Mar 22, 2020 · 6 comments

Comments

@simonw
Copy link
Owner

simonw commented Mar 22, 2020

Since that object is passed to the extra_template_vars hooks AND the classes registered by register_facet_classes it should be part of the documented interface on https://datasette.readthedocs.io/en/stable/internals.html

I could also start passing it to the register_output_renderer callback.

@simonw
Copy link
Owner Author

simonw commented May 27, 2020

This is the full current implementation of the request object:

class Request:
def __init__(self, scope, receive):
self.scope = scope
self.receive = receive
@property
def method(self):
return self.scope["method"]
@property
def url(self):
return urlunparse(
(self.scheme, self.host, self.path, None, self.query_string, None)
)
@property
def scheme(self):
return self.scope.get("scheme") or "http"
@property
def headers(self):
return dict(
[
(k.decode("latin-1").lower(), v.decode("latin-1"))
for k, v in self.scope.get("headers") or []
]
)
@property
def host(self):
return self.headers.get("host") or "localhost"
@property
def path(self):
if self.scope.get("raw_path") is not None:
return self.scope["raw_path"].decode("latin-1")
else:
path = self.scope["path"]
if isinstance(path, str):
return path
else:
return path.decode("utf-8")
@property
def query_string(self):
return (self.scope.get("query_string") or b"").decode("latin-1")
@property
def args(self):
return RequestParameters(parse_qs(qs=self.query_string))
@property
def raw_args(self):
return {key: value[0] for key, value in self.args.items()}
async def post_vars(self):
body = []
body = b""
more_body = True
while more_body:
message = await self.receive()
assert message["type"] == "http.request", message
body += message.get("body", b"")
more_body = message.get("more_body", False)
return dict(parse_qsl(body.decode("utf-8")))
@classmethod
def fake(cls, path_with_query_string, method="GET", scheme="http"):
"Useful for constructing Request objects for tests"
path, _, query_string = path_with_query_string.partition("?")
scope = {
"http_version": "1.1",
"method": method,
"path": path,
"raw_path": path.encode("latin-1"),
"query_string": query_string.encode("latin-1"),
"scheme": scheme,
"type": "http",
}
return cls(scope, None)

@simonw
Copy link
Owner Author

simonw commented May 27, 2020

New documentation can be seen here: https://github.com/simonw/datasette/blob/6d7cb02f00010d3cb4b4bac0460d41277652b80e/docs/internals.rst#request-object

It's inspired me to reconsider the name of the .raw_args property, which isn't particularly clear.

@simonw
Copy link
Owner Author

simonw commented May 27, 2020

It looks like I inherited .raw_args from Sanic - I use it in a few places: https://github.com/search?q=user%3Asimonw+raw_args&type=Code

@simonw
Copy link
Owner Author

simonw commented May 27, 2020

What would a better name be?

  • .simple_args
  • .kv_args
  • .pair_args
  • .dict_args
  • .args_dict

I dislike the last two the least.

@simonw
Copy link
Owner Author

simonw commented May 27, 2020

I'm going to leave .raw_args in for the moment but deliberately not document it. I'll hope to phase it out entirely at a later date.

@simonw
Copy link
Owner Author

simonw commented May 28, 2020

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests

1 participant