Chapter 15
The RESTful web server will then need a small database with the valid keys and
perhaps some client contact information. If an API request includes a key that's in the
database, the associated user is responsible for the request. If the API request doesn't
include a known key, the request can be rejected with a simple 401 UNAUTHORIZED
response. Since the key itself is a 24-character string, the database will be rather small
and can easily be cached in memory.
Ordinary log-scraping might be sufficient to show the usage for a given key. A more
sophisticated application might record API requests in a separate logfile or database
to simplify analysis.
Summary
In this chapter, we looked at ways in which we can apply functional design to the
problem of serving content with REST-based web services. We looked at the ways
that the WSGI standard leads to somewhat functional overall applications. We
also looked at how we can embed a more functional design into a WSGI context by
extracting elements from the request for use by our application functions.
For simple services, the problem often decomposes down into three distinct
operations: getting the data, searching or filtering, and then serializing the results.
We tackled this with three functions: raw_data(), anscombe_filter(), and
serialize(). We wrapped these functions in a simple WSGI-compatible application
to divorce the web services from the "real" processing around extracting and filtering
the data.
We also looked at the way that web services functions can focus on the "happy path"
and assume that all of the inputs are valid. If inputs are invalid, the ordinary Python
exception handling will raise exceptions. The WSGI wrapper function will catch the
errors and return appropriate status codes and error content.
We avoided looking at more complex problems associated with uploading data
or accepting data from forms to update a persistent data store. These are not
significantly more complex than getting data and serializing the results. They are
already solved in a better manner.
For simple queries and data sharing, a small web service application can be helpful.
We can apply functional design patterns and assure that the website code is succinct
and expressive. For more complex web applications, we should consider using a
framework that handles the details properly.
In the next chapter, we'll look at a few optimization techniques that are available to
us. We'll expand on the @lru_cache decorator from Chapter 10, The Functools Module.
We'll also look at some other optimization techniques that were presented in Chapter 6,
Recursions and Reductions.