From e87fa2a8dbb5d23038fbfe62119366497633e276 Mon Sep 17 00:00:00 2001 From: Neil Williams Date: Fri, 6 Dec 2013 15:17:11 -0800 Subject: [PATCH] /dev/api: Document how listings work. --- r2/r2/controllers/api_docs.py | 8 +++++++ r2/r2/controllers/listingcontroller.py | 3 ++- r2/r2/controllers/reddit_base.py | 10 +++++++- r2/r2/lib/validator/validator.py | 24 +++++++++++++++++++ r2/r2/templates/apihelp.html | 32 ++++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 2 deletions(-) diff --git a/r2/r2/controllers/api_docs.py b/r2/r2/controllers/api_docs.py index 72e71a2bc..af23ab044 100644 --- a/r2/r2/controllers/api_docs.py +++ b/r2/r2/controllers/api_docs.py @@ -141,6 +141,14 @@ class ApidocsController(RedditController): docs['parameters'] = {} docs.update(api_doc) + # append a message to the docstring if supplied + notes = docs.get("notes") + if notes: + if docs["doc"]: + docs["doc"] += "\n\n" + notes + else: + docs["doc"] = notes + uri = docs.get('uri') or '/'.join((url_prefix, action)) if 'extensions' in docs: # if only one extension was specified, add it to the URI. diff --git a/r2/r2/controllers/listingcontroller.py b/r2/r2/controllers/listingcontroller.py index 2054c2f63..6e0f95989 100755 --- a/r2/r2/controllers/listingcontroller.py +++ b/r2/r2/controllers/listingcontroller.py @@ -21,7 +21,7 @@ ############################################################################### from oauth2 import OAuth2ResourceController, require_oauth2_scope -from reddit_base import RedditController, base_listing +from reddit_base import RedditController, base_listing, paginated_listing from r2.models import * from r2.models.query_cache import CachedQuery, MergedCachedQuery @@ -202,6 +202,7 @@ listing_api_doc = partial( api_doc, section=api_section.listings, extends=ListingController.GET_listing, + notes=paginated_listing.doc_note, extensions=["json", "xml"], ) diff --git a/r2/r2/controllers/reddit_base.py b/r2/r2/controllers/reddit_base.py index 5b1c71998..30144e628 100644 --- a/r2/r2/controllers/reddit_base.py +++ b/r2/r2/controllers/reddit_base.py @@ -599,7 +599,9 @@ def paginated_listing(default_page_size=25, max_page_size=100, backend='sql'): before=VByName('before', backend=backend), count=VCount('count'), target=VTarget("target"), - show=VLength('show', 3, empty_error=None)) + show=VLength('show', 3, empty_error=None, + docs={"show": "(optional) the string `all`"}), + ) @wraps(fn) def new_fn(self, before, **env): if c.render_style == "htmllite": @@ -618,9 +620,15 @@ def paginated_listing(default_page_size=25, max_page_size=100, backend='sql'): kw['reverse'] = True return fn(self, **kw) + + if hasattr(fn, "_api_doc"): + fn._api_doc["notes"] = paginated_listing.doc_note + return new_fn return decorator +paginated_listing.doc_note = "*This endpoint is [a listing](#listings).*" + #TODO i want to get rid of this function. once the listings in front.py are #moved into listingcontroller, we shouldn't have a need for this #anymore diff --git a/r2/r2/lib/validator/validator.py b/r2/r2/lib/validator/validator.py index 233e9130b..2c34d1654 100644 --- a/r2/r2/lib/validator/validator.py +++ b/r2/r2/lib/validator/validator.py @@ -478,6 +478,11 @@ class VCount(Validator): except ValueError: return 0 + def param_docs(self): + return { + self.param: "a positive integer (default: 0)", + } + class VLimit(Validator): def __init__(self, param, default=25, max_limit=100, **kw): @@ -1451,6 +1456,21 @@ class VInt(VNumber): def cast(self, val): return int(val) + def param_docs(self): + if self.min is not None and self.max is not None: + description = "an integer between %d and %d" % (self.min, self.max) + elif self.min is not None: + description = "an integer greater than %d" % self.min + elif self.max is not None: + description = "an integer less than %d" % self.max + else: + description = "an integer" + + if self.num_default is not None: + description += " (default: %d)" % self.num_default + + return {self.param: description} + class VFloat(VNumber): def cast(self, val): return float(val) @@ -2046,6 +2066,10 @@ class VTarget(Validator): if name and self.target_re.match(name): return name + def param_docs(self): + # this is just for htmllite and of no interest to api consumers + return {} + class VFlairAccount(VRequired): def __init__(self, item, *a, **kw): VRequired.__init__(self, item, errors.BAD_FLAIR_TARGET, *a, **kw) diff --git a/r2/r2/templates/apihelp.html b/r2/r2/templates/apihelp.html index 2d2b8a530..9ebc629fe 100644 --- a/r2/r2/templates/apihelp.html +++ b/r2/r2/templates/apihelp.html @@ -133,6 +133,38 @@

overview

+

listings

+ + <%text filter="safemarkdown"> +Many endpoints on reddit use the same protocol for controlling pagination and +filtering. These endpoints are called Listings and share five common +parameters: `after` / `before`, `limit`, `count`, and `show`. + +Listings do not use page numbers because their content changes so frequently. +Instead, they allow you to view slices of the underlying data. Listing JSON +responses contain `after` and `before` fields which are equivalent to the +"next" and "prev" buttons on the site and in combination with `count` can be +used to page through the listing. + +The common parameters are as follows: + +* `after` / `before` - only one should be specified. these indicate the +[fullname](#fullnames) of an item in the listing to use as the anchor point of +the slice. +* `limit` - the maximum number of items to return in this slice of the listing. +* `count` - the number of items already seen in this listing. on the html site, +the builder uses this to determine when to give values for `before` and `after` +in the response. +* `show` - optional parameter; if `all` is passed, filters such as "hide links +that I have voted on" will be disabled. + +To page through a listing, start by fetching the first page without specifying +values for `after` and `count`. The response will contain an `after` value +which you can pass in the next request. It is a good idea, but not required, to +send an updated value for `count` which should be the number of items already +fetched. + +

modhashes

A modhash is a token that the reddit API requires to help prevent