Giter Club home page Giter Club logo

madness's Introduction

madness

Madness orchestrates the HTTP request-response cycle using context functions to build abstractions and route functions to transform abstractions into a HTTP responses.

It is built upon the fabulous werkzeug routing system.

Principles

Don't repeat yourself

Dependency inversion principle

Do One Thing and Do It Well.

Installing

$ pip install -U madness

A Simple Example

from madness import Madness, response

app = Madness()

@app.index
def hello():
    return response(['Hello, world!'])

if __name__ == '__main__':
    app.run()

Routing

@app.route(*paths, methods=[], context=[], origin=None, headers=[])

option description
*paths relative paths, defaults to the decorated function name
methods list of allowed http methods
context list of extra context functions see #Context
origin allowed origin: * or list of urls
headers allowed request headers: list of header names
wsgi set to True if the route implements a WSGI interface

convenience methods for @app.route

you can still use options with these!

@app.get, @app.post, @app.put, @app.delete, @app.patch, @app.options

RESTful routes

inspired by Ruby on Rails' resources

https://gist.github.com/alexpchin/09939db6f81d654af06b

https://medium.com/@shubhangirajagrawal/the-7-restful-routes-a8e84201f206

decorator path method
@app.index {path} GET
@app.new new{path} GET
@app.create {path} POST
@app.show /:id{path} GET
@app.edit /:id/edit{path} GET
@app.update /:id{path} PATCH/PUT
@app.destroy /:id{path} DELETE

AWS Lambda

see also: RequestResponse

from madness import json

@json.schema
class EventSchema():
    x: int = 1

@app.lambda_handler
def process(event: EventSchema):
    return {'y': event['x'] + 2}

if you annotate the event with a marshmallow schema, it is automatically validated :)

handling routing errors

@app.error(404)
def my404handler():
    return response(['not found'], status = 404)

Modules

from madness import Madness, response

app = Madness()

module = Madness()

@module.route
def thing():
    return response(['hello!'])

app.extend(module) # now app has /thing

app.extend(module, 'prefix') # now app has /prefix/thing

app.extend(module, context=False) # add the routes but not the context

if __name__ == '__main__':
  app.run()

Context

madness.context contains the abstractions created by the previous contexts

use @context to build abstractions for your low-level modules @context and @route

e.g.

  @context authenticate the HTTP request `context.username = 'xyz'`

  @context get database connection `context.database = Database()`

  @context(database) use database connection `context.data = database.myobjects.find(context.id)`

  @show(data) convert data to HTTP response `return json.response(data)`

rule args are added to context

e.g. @app.route('path/<myvar>') creates context.myvar

Basic Context Functions

from madness import context, json

@app.context
def before_request():
    "could do anything here, so let's add a variable to the context!"
    context.x = 2

@app.context
def continue_processing(x):
    "define context.y based on context.x!"
    context.y = x * 3 # 6

@app.route
def double(y):
    "doubles context.y and sends it as a JSON response"
    return json.response(y * 2) # 12

Advanced Context Generators

a context has full access to the request/response/exceptions

the response/exception is bubbled through the context handlers

@app.context
def advanced_context():
    # before_request
    if request.headers.get('x-api-key') != 'valid-api-key':
        # abort
        yield json.response({'message': 'invalid api key'}, status = 403)
    else:
        # run remaining context functions and the route endpoint (if not aborted)
        try:
            response = yield

        except MyException as exception:
            yield json.response({'message': exception.message}, status = 500)

        else:
            # modify the response headers
            response.headers['x-added-by-context'] = 'value'

            # abort
            yield json.response('we decided to not send the original response, isn\'t that weird?')

        finally:
            # after_request
            pass

madness's People

Contributors

waffles32 avatar

Watchers

 avatar  avatar

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.