Recently, I am going to be a simple web server and implement a custom API by configuring properties such as url method header. The framework considers Tornado and PyRestful. Then there is a problem, the number of APIs is dynamically generated, and the request method of each API is different. If pure PyRestful is not enough.
import pyrestful.rest import tornado.ioloop from pyrestful import mediatypes from pyrestful.rest import get, post class Book(object): isbn = int title = str class BookResource(pyrestful.rest.RestHandler): @get(_path="/books/json/{isbn}", _types=[int], _produces=mediatypes.APPLICATION_JSON) def getBookJSON(self, isbn): book = Book() book.isbn = isbn book.title = "My book for isbn " + str(isbn) return book
Therefore, it is necessary to dynamically generate the method of class and claas. Fortunately, Python has a corresponding syntax: Metaclass
Override the __new__(cls, name, bases, attrs) method by inheriting type
class RestHandleMetaclass(type): def __new__(cls, name, bases, attrs): # do something ,such as redefinition attrs # ps: attr is a tuple return type.__new__(cls, name, (RestHandler,), attrs)
Then I encountered the second problem, how to add @get(_path="/books/json/{isbn}", _types=[int], _produces=mediatypes.APPLICATION_JSON) to the method. At first, I thought the @ symbol was an annotation, and I took a lot of detours. Later, I learned that @ is used to deal with Decorators in Python. (Reference: A B ). Since the element in attrs is a method, how to generate a method, which has been processed by the decorator, can modify the parameters in @get(), and finally return a method becomes the third problem. Fortunately pyrestful.rest.get inspired me
def get(*params, **kwparams): """ Decorator for config a python function like a Rest GET verb """ def method(f): return config(f,'GET',**kwparams) return method
Method in Python can define Method and return Method. At the same time, after trying, it is found that the internally defined Method can be added with @get, and finally returns to the method after the decorator is processed.
class RestHandleMetaclass(type): @staticmethod def dynamicDecorator(data): _path = "/books/json/" + str(data) + "/{isbn}" _types = [int] _produces = mediatypes.APPLICATION_JSON @get(_path=_path, _types=_types, _produces=_produces) def getBookJSON(self, isbn): book = Book() book.isbn = isbn book.title = "My book for isbn " + str(isbn) return book return getBookJSON def __new__(cls, name, bases, attrs): for x in range(5): attrs["getBookIsbn_" + str(x)] = RestHandleMetaclass.dynamicDecorator(x) return type.__new__(cls, name, (RestHandler,), attrs)
Finally add the relevant code.
class TestA(object, metaclass=RestHandleMetaclass): pass
if __name__ == '__main__': try: print("Start the service") app = pyrestful.rest.RestService([TestA]) app.listen(8080) tornado.ioloop.IOLoop.instance().start() except KeyboardInterrupt: print("\nStop the service")