WSGI created using the REST interface

 

problem

You want to use a simple REST interface over the network or remote control access to your application, but you do not want to own to install a complete web framework.

solution

Interface easiest way to build a REST style is to create a standards-based WSGI (PEP 3333) is a small library, the following is an example:

# resty.py

import cgi

def notfound_404(environ, start_response): start_response('404 Not Found', [ ('Content-type', 'text/plain') ]) return [b'Not Found'] class PathDispatcher: def __init__(self): self.pathmap = { } def __call__(self, environ, start_response): path = environ['PATH_INFO'] params = cgi.FieldStorage(environ['wsgi.input'], environ=environ) method = environ['REQUEST_METHOD'].lower() environ['params'] = { key: params.getvalue(key) for key in params } handler = self.pathmap.get((method,path), notfound_404) return handler(environ, start_response) def register(self, method, path, function): self.pathmap[method.lower(), path] = function return function 

In order to use this scheduler, you only need to write different processors, such as the following:

import time

_hello_resp = '''\ <html>  <head>  <title>Hello {name}</title>  </head>  <body>  <h1>Hello {name}!</h1>  </body> </html>''' def hello_world(environ, start_response): start_response('200 OK', [ ('Content-type','text/html')]) params = environ['params'] resp = _hello_resp.format(name=params.get('name')) yield resp.encode('utf-8') _localtime_resp = '''\ <?xml version="1.0"?> <time>  <year>{t.tm_year}</year>  <month>{t.tm_mon}</month>  <day>{t.tm_mday}</day>  <hour>{t.tm_hour}</hour>  <minute>{t.tm_min}</minute>  <second>{t.tm_sec}</second> </time>''' def localtime(environ, start_response): start_response('200 OK', [ ('Content-type', 'application/xml') ]) resp = _localtime_resp.format(t=time.localtime()) yield resp.encode('utf-8') if __name__ == '__main__': from resty import PathDispatcher from wsgiref.simple_server import make_server # Create the dispatcher and register functions dispatcher = PathDispatcher() dispatcher.register('GET', '/hello', hello_world) dispatcher.register('GET', '/localtime', localtime) # Launch a basic server httpd = make_server('', 8080, dispatcher) print('Serving on port 8080...') httpd.serve_forever() 

To test this server, you can use a browser or  urllib interact with it. E.g:

>>> u = urlopen('http://localhost:8080/hello?name=Guido') >>> print(u.read().decode('utf-8')) <html>  <head>  <title>Hello Guido</title>  </head>  <body>  <h1>Hello Guido!</h1>  </body> </html> >>> u = urlopen('http://localhost:8080/localtime') >>> print(u.read().decode('utf-8')) <?xml version="1.0"?> <time>  <year>2012</year>  <month>11</month>  <day>24</day>  <hour>14</hour>  <minute>49</minute>  <second>17</second> </time> >>> 

discuss

When writing REST interface, usually serving the normal HTTP request. However, compared with the full functionality of those sites, you usually only need to process data. The data encoded in a variety of standard formats, such as XML, JSON or CSV. Although the program looks very simple, but the API provided in this way for many applications in terms of is very useful.

For example, the long-running program may be implemented using a REST API monitoring or diagnosis. Big Data applications can query or to build a data extraction system using REST. REST can also be used to control hardware devices such as a robot, a sensor, or bulb plant. More importantly, REST API has been supported by a large number of client programming environment, such as Javascript, Android, iOS and so on. Therefore, with this kind of interface that allows you to develop more complex applications.

In order to achieve a simple REST interface, you need to make your program code Python's WSGI standard to meet. WSGI is supported by the standard library, but also by the framework supports most third party web. So, if you follow this standard code will use later in the process more flexible!

In WSGI, you may like this way agreed to form a callable object to implement your program.

import cgi

def wsgi_app(environ, start_response): pass 

environ Attribute is a dictionary containing the value obtained from a web server such as the Apache CGI interface [with reference to Internet RFC 3875] provided. To extract these different values, you can write this like so:

def wsgi_app(environ, start_response): method = environ['REQUEST_METHOD'] path = environ['PATH_INFO'] # Parse the query parameters params = cgi.FieldStorage(environ['wsgi.input'], environ=environ) 

We show some common values. environ['REQUEST_METHOD'] Representative of the request type such as GET, POST, HEAD like. environ['PATH_INFO'] It represents the path of the requested resource. Call  cgi.FieldStorage() may be extracted from the request query parameters and place them in a dictionary object for later use.

start_response A parameter is a function to initialize a request object must be called. The first parameter is the value returned HTTP status, the second parameter is a (name, value) of a list of tuples, used to build the returned HTTP header. E.g:

def wsgi_app(environ, start_response): pass start_response('200 OK', [('Content-type', 'text/plain')]) 

In order to return data, a WSGI must return a string of bytes sequence. Like this can be accomplished using a list of the following:

def wsgi_app(environ, start_response): pass start_response('200 OK', [('Content-type', 'text/plain')]) resp = [] resp.append(b'Hello World\n') resp.append(b'Goodbye!\n') return resp 

Or, you can use  yield :

def wsgi_app(environ, start_response): pass start_response('200 OK', [('Content-type', 'text/plain')]) yield b'Hello World\n' yield b'Goodbye!\n' 

It should be emphasized that the final return must be a byte string. If the return result includes a text string, it must be encoded into the first byte. Of course, there is no requirement that you must return the text, you can easily write a program-generated image.

Although WSGI program is generally defined as a function, but you can also use the class instance to implement, as long as it implements the appropriate  __call__() method. E.g:

class WSGIApplication:
    def __init__(self): ... def __call__(self, environ, start_response) ... 

We have used this technique to create in the above  PathDispatcher categories. This distribution is just a dictionary management, the (method path) mapped to the top of the processor functions. When a request comes in, its methods and paths are extracted, and then to be distributed to the processor corresponding to the above. In addition, any inquiry into the variable will be resolved after a dictionary to  environ['params'] form storage. This latter step too common, it is recommended that you complete the dispenser inside, so you can save a lot of duplicate code. Using the dispenser, you simply create an instance and then register it by various forms of WSGI function. These functions should write super simple, as long as you follow the  start_response() written rules of function, and finally returned to the byte string.

When writing this function needs to note is that the use of a template for the string. Nobody wants to write the kind of mix of full  print() function, XML, and a lot of code formatting operation. We used the above pre-defined template string triple quotes included. This approach allows us to easily modify it later output format (only need to modify the template itself, without touching any place to use it).

Finally, WSGI there is a very important part is there is no place for a specific web server. Because the standard for servers and frameworks are neutral, you can put your program into any type of server. We use the following code to test test the code in this section:

if __name__ == '__main__':
    from wsgiref.simple_server import make_server # Create the dispatcher and register functions dispatcher = PathDispatcher() pass # Launch a basic server httpd = make_server('', 8080, dispatcher) print('Serving on port 8080...') httpd.serve_forever() 

The above code creates a simple server, then you can come to test whether your implementation under work properly. Finally, when you are ready to further expand your program, you can modify this code, you can work for a particular server.

WSGI itself is a very small standard. So it does not offer advanced features such as authentication, cookies, redirects and so on. These you realize it is also not difficult. But if you want more support, consider third-party libraries, such as  WebOb or Paste

 

Reference: https://python3-cookbook.readthedocs.io/zh_CN/latest/c11/p05_creating_simple_rest_based_interface.html

Guess you like

Origin www.cnblogs.com/-wenli/p/11345225.html