Giter Site home page Giter Site logo

rafaelcaricio / sticker Goto Github PK

View Code? Open in Web Editor NEW
26.0 4.0 1.0 251 KB

Sticker is a powerful yet boilerplate-free alternative to writing your web API.

License: Apache License 2.0

Python 100.00%
tornado flask bottle sanic python api-rest openapi openapi3

sticker's Introduction

Sticker

Write boilerplate-free Python functions and use them as your API handlers. Sticker allows you to choose Flask, bottle.py, Sanic, or Tornado as your application runtime.

Highlights:

It's Easy to Write

You need a little bit of Python.

def say_hello(params):
    return {"contents": "Hello World!"}

Plus bits of your API description.

openapi: "3.0.0"
paths:
  /:
    get:
      operationId: hello.say_hello

Now the fun part, you choose which web framework you want to use.

Run with Flask:

from sticker import FlaskAPI
api = FlaskAPI('hello.yml')
api.get_app(__name__).run()

Run with Bottle.py:

from sticker import BottleAPI
api = BottleAPI('hello.yml')
api.run()

Run with Sanic:

from sticker import SanicAPI
api = SanicAPI('hello.yml')
api.get_app(__name__).run()

Run with Tornado:

from sticker import TornadoAPI
import tornado.ioloop
api = TornadoAPI('hello.yml')
api.get_app().listen(8888)
tornado.ioloop.IOLoop.current().start()

The framework setup, validation, types conversion, and mocking is handled at runtime by Sticker.

โœจ

Installation

Sticker is published at PyPI, so you can use pip to install:

$ pip install sticker

Requirements

Sticker was developed for Python >=3.6 and OpenAPI 3.0. Support for Python 2.7 is not present nor planned for this project.

Documentation

Sticker is a flexible metaframework for Web API development and execution. The OpenAPI 3.0 standard is used as description format for Sticker powered APIs. You provide the API specification and choose one of the Sticker's runtimes to have a webserver up and running.

In this document we will describe a few different ways to write code that works well with Sticker.

Pure Python Handlers

Sticker supports the use of pure Python functions as handlers. Your code will be free of any framework specific boilerplate code, including Sticker's itself. This allows you to swap between different frameworks as you wish. Sticker will take care of putting together your code, your API, and the framework you choose.

def myhandler(params):
    return {
        "content": f"Hello {params.get("name", "World")}!",
        "status": 200
    }

Writing tests for pure Python handles is easy and also free of boilerplate code.

def test_myhandler():
    params = {
        "name": "John Doe"
    }
    response = myhandler(params)
    assert response["content"] == "Hello John Doe!"

As you could see in the example above, no imports from Sticker were necessary to define the API handler function. This is only possible because Sticker expects your handlers to follow a code convention.

Anatomy Of An API Handler Function

Write this part.

Responses

API handlers are expected to return a Python dictionary (dict) object. The returned dictionary defines how a response will look like. All keys in the dictionary are optional. The expected keys are described in the table bellow.

Key Type Description
content str Body of HTTP request. No treatment/parsing of this value is done. The value is passed directly to the chosen framework.
json Union[dict, List[dict]] JSON value to be used in the body of the request. This is a shortcut to having the header "Content-Type: application/json" and serializing this value using the most common way done by the chosen framework.
file Union[IO[AnyStr], str] Data to be returned as byte stream. This is a shortcut for having the header "Content-Type: application/octet-stream". Uses the most common way to stream files with the chosen framework.
redirect str The path or full URL to be redirected. This is a shortcut for having the header "Location:" with HTTP status 301.
status int The HTTP status code to be used in the response. This value overrides any shortcut default status code.
headers Dict[str, str] The HTTP headers to be used in the response. This value is merged with the shortcut values with priority.

We have exposed here some examples of using different configurations of the dict we've defined above to describe the HTTP response of API handlers. The actual HTTP response value generated will vary depending on the framework chosen as runtime. The examples are a minimal illustration of what to expect to be the HTTP response.

The "content" key can be used when it's desired to return a "Hello world!" string with status 200.

def say_hello(params):
    return {"content": "Hello world!"}

Results in the HTTP response similar to:

HTTP/1.1 200 OK
Content-Type: text/plain

Hello world!

The "json" key can be used when desired to return an JSON response with status 201.

def create(params):
    data = {
        "id": "uhHuehuE",
        "value": "something"
    }
    return {"json": data, "status": 201}

The HTTP response generated will be similar to:

HTTP/1.1 201 Created
Content-Type: application/json

{"id":"uhHuehuE","value":"something"}

The "file" key is used to return file contents.

def homepage(params):
    return {
        "file": open('templates/home.html', 'r'),
        "headers": {
            "Content-Type": "text/html"
        }
    }

The HTTP response will be similar to:

HTTP/1.1 200 OK
Content-Type: text/html

<html><title>My homepage</title><body><h1>Welcome!</h1></body></html>

When necessary to redirect request, the "redirect" key can be used.

def old_endpoint(params):
    return {'redirect': '/new-path'}

The HTTP response will be similar to:

HTTP/1.1 301 Moved Permanently
Location: https://example.com/new-path

The usage of keys "status" and "headers" were shown in the previous examples. The "status" and "headers" keys, when set, override the values set by default when using the shortcut keys ("json", "file", and "redirect").

Error Handling

Sticker expects you to define the error format to be returned by your API. A error handler is configurable, and called every time validation for the endpoint fails.

def error_handler(error):
    return {
        "content": {
            "error": error["message"]
        },
        "headers": {
            "Content-Type": "application/json"
        },
        "status_code": 400
    }

Developing

We follow Semantic Versioning.

Contributing

Sticker is developed under the Apache 2.0 license and is publicly available to everyone. We are happy to accept contributions.

How to Contribute

  1. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug. There is a Good First Issue tag for issues that should be ideal for people who are not very familiar with the codebase yet.
  2. Fork the repository on GitHub to start making your changes to the master branch (or branch off of it).
  3. Write a test which shows that the bug was fixed or that the feature works as expected.
  4. Send a pull request and bug the maintainer until it gets merged and published. :) Make sure to add yourself to AUTHORS.

sticker's People

Contributors

dependabot[bot] avatar rafaelcaricio avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

hassan11196

sticker's Issues

Validate "openapi" key and version

We should validate if the specification document contains the "openapi" key and that it's value matches the expression ^3\.\d+\.\d+$.

Validate output optionally

We should be able to validate the output given by the user's handlers based on the API spec. This must be an optional behaviour.

Define schema for handler output

Currently, the format of output supported is:

{
    "content": str
}

Which defines the "content" key to be used as body of the HTTP response. We should expand this schema to support HTTP headers, status code and other types of response.

Pass along request parameters

We need to pass along the parameters of incoming requests based on the specification. This will differ from every framework we support. We should extract some common code to be used between different framework implementations.

Support for custom errors

We should be able to show errors in the format user's defined. An error function is defined and added to the configuration. We should call the error function for every error we find. Every time a request causes an error, we call the error function to get the response format for the error.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.