About Me

  • Mike Brown

  • Your Favorite Organizer

  • Python Backend + DevOps

  • Python Lead @ Excella Consulting

The Premise

 I made a simple API last year

 

Let's rewrite it using some currently trending frameworks

The Input


 {
    "text": "mike made the coolest API", 
    "search": "sarcastic wonka"
 }

The Output

The Original Code


 @app.route('/', methods = ['GET', 'POST'])
 def giffer():
    if request.method == 'POST':
       data = request.data
       gif_file = gif_factory.create(**data)
       return send_file(gif_file)
    else:
       return get_guide_text()

gif_factory.create

  • Pull a gif image from the giphy API

  • Use moviepy to generate new gif with meme text

  • Save the file to the filesystem (sadface)

  • Return string path to the new gif file

The Contestants

  • Sanic - Asynchronous/Fast

  • Hug - Simplified/Self Documenting

Sanic

  • Flask-style API

  • Python 3 required

  • Async/Await syntax

  • "Faster than Node"


 @app.route('/', methods = ['POST'])
 async def giffer(request):

    data = request.json
    gif_file = await gif_factory.create(**data)
    return file(gif_file, mime_type='image/gif')

 class GifferView(HTTPMethodView):

   def post(self, request):
      data = request.json
      gif_file = await gif_factory.create(**data)
      return file(gif_file, mime_type='image/gif')

   def get(self, request):
      return create_guide_text()

 app.add_route(GifferView.as_view(), '/')

Hug

  • Flask-style API

  • Python 3 required

  • Type Annotations

  • Autogenerated documentation

  • "make developing an API as simple as possible"


 @hug.get('/', output=hug.output_format.pretty_json)
 def giffer_get():
    return print_guide()

 @hug.post('/', output=hug.output_format.gif_image)
 def giffer_post(data):
    return gif_factory.create(**data)
{
    "documentation": {
        "handlers": {
            "/": {
                "GET": {
                    "examples": [
                        "http://localhost:8000/"
                    ],
                    "outputs": {
                        "format": "JSON pretty printed and indented",
                        "content_type": "application/json"
                    }
                },
                "POST": {
                    "outputs": {
                        "format": "gif formatted image",
                        "content_type": "image/gif"
                    },
                    "inputs": {
                        "data": {
                            "type": "Basic text / string value"
                        }
                    }
                }
}}}}

http://localhost:8000/documentation


 @hug.get('/', output=hug.output_format.pretty_json)
 def giffer_get():
    return print_guide()

 @hug.post('/', output=hug.output_format.gif_image)
 # def giffer_post(data):
 #   return gif_factory.create(**data)
 def giffer_post(search, text):
    return gif_factory.create(search=search, text=text)
{
    "documentation": {
        "handlers": {
            "/": {
                "GET": {
                    "examples": [
                        "http://localhost:8000/"
                    ],
                    "outputs": {
                        "format": "JSON pretty printed and indented",
                        "content_type": "application/json"
                    }
                },
                "POST": {
                    "outputs": {
                        "format": "gif formatted image",
                        "content_type": "image/gif"
                    },
                    "inputs": {
                        "search": {
                            "type": "Basic text / string value"
                        },
                        "text": {
                            "type": "Basic text / string value"
                        }
                    }
}}}}}

http://localhost:8000/documentation


 @hug.type(extend=hug.types.text)
 def input_search(value):
    """The search string for giphy"""
    pass

 @hug.type(extend=hug.types.text)
 def input_text(value):
    """The text to display in the gif"""
    pass

 @hug.post('/', output=hug.output_format.gif_image)
 # def giffer_post(search, text):
 def giffer_post(search: input_search, text: input_text,
                 text_width: int=60):
    return gif_factory.create(search=search, text=text,
                              text_width=text_width)

Type Annotations!

{
    "documentation": {
        "handlers": {
            "/": {
                "POST": {
                    "outputs": {
                        "format": "gif formatted image",
                        "content_type": "image/gif"
                    },
                    "inputs": {
                        "search": {
                            "type": "The search string for giphy"
                        },
                        "text": {
                            "type": "The text to display in the gif"
                        },
                        "text_width": {
                            "type": "int(x=0) -> integer\nint(x, base=10)",
                            "default": 60
                        }
                    },
                }
}}}}

http://localhost:8000/documentation

Final Thoughts

Questions?

How To Make An API In 2017

By m3brown

How To Make An API In 2017

  • 1,096