Web application - well, almost no back-end: Flask, Redis, API via JSONP, JSFiddle.net

    This article is the so-called "proof-of-concept" of creating a front-end application that works with the API through JSONP, that is, as they say, "cross-origin". Data organization in Redis is also described.

    For example, you can easily place a certain application on jsfiddle.net , the back-end of which will be located on another domain.

    Agree that a full-fledged working final product (requiring a certain server to centralize the exchange of data) located inside JSFiddle looks funny!

    The purpose of the article is to share its current experience from two sides:
    • Implementation of JSONP + Long Polling
    • Work with wonderful Redis

    The guys from BackendLess are doing something similar .

    What do we have

    So we have:
    • Some own server with Python 2.x on board
    • Browser and access to JSFiddle.net
    • Desire to build API-over-JSONP

    What i used


    I think the reader does not need an explanation of what it is. As for the implementation, everything is done by one decorator:
    defjsonp(fn):defwrapper(*args, **kwargs):
            callback = request.args.get('callback', None)
            ifnot callback:
                raise BadRequest('Missing callback argument.')
                data=dumps(fn(*args, **kwargs))
        wrapper.__name__ = fn.__name__
        return wrapper


    There is such a wonderful thing - Redis. As developers say about it,
    Redis is an open source, BSD licensed, advanced key-value cache and store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets, sorted sets, bitmaps and hyperloglogs.

    Or in a nutshell:
    Redis is a powerful key-value storage and caching system.

    A bit about Redis

    If you are not familiar with Redis, I advise you to read about it at the office. site, since not all the subtleties of working with it will be described below.
    Actually, Redis itself works as a separate daemon, and from the Python script we access it through a fairly simple connector module of the same name.
    We can create some key and assign it:
    • Scalar value (actually a string )
    • List
    • Array
    • Lots of
    • Sorted Set

    But! We cannot make an array of arrays, for example. Therefore, in this case, you have to make a key with a list of indices and a key for each index. Also, due to the lack of selection by values ​​(a la WHERE in SQL), sometimes you have to do lists with reverse “mapping”, for example, to search for a user ID by nickname and to search for a user nickname by its ID.
    Roughly speaking: what is a table in SQL will be a list of indexes and a set of arrays in Redis . It is also customary to separate parts of the key with a colon.

    Example in SQL: 1 table - with fields user_id, user_name, user_email and 5 records.
    Redis analogy: 1 list and 5 arrays - users listwith data [1, 2, 3, 4, 5] and 5 arrays with names (keys) of the form user: X with data {id: X, name: Y, email: Z}, as well as several arrays with feedback, for example , nicknames with values ​​{andrew: 1, john: 2, mike: 3, ...}

    Why redis

    • Redis does not need to define data structures: just put them there.
    • We can do CRUD ( Create-Read-Update-Delete ) with the data in the Redis database, and also use the built-in locking mechanism - it, by the way, greatly simplifies the implementation of the long polling mechanism .
    • Redis does not know how to JOIN or WHERE, nor should it - it just stores primitives, maximum lists or associative arrays from primitives. But this is not a minus, but an additional freedom of action and an incentive to expand thinking, which is different from the SQL- and NoSQL-DBMS patterns.

    The structure of the database of the key-value storage system

    This is how the data in our Redis looks at the moment when Andrew wrote a message and John wrote a message, but the first read everything except the shirt, and the second - only John himself. But in a few moments all user: X: messages will be cleared, because there will be a polishing timeout and the data will go to the clients. Those. user: X: messages - this is such a container for messages not yet received by a certain user.

    Long polling

    Redis can easily implement long polling . An example algorithm is as follows:
    • We ask in Redis (with the LLEN command ) whether there are messages in the message list for the client right now, if so, we return the messages and clear the list via DEL
    • If there are no messages, we request them again, but this time with the BLPOP command , which will block the active stream until the data appears or the timeout expires. By unlocking, we return to the client the result from Redis, in which there will be either a message just arrived or nothing.

    “Battle Team, Go!”

    Front end for testing: jsfiddle.net/andunai/kcdtzdww Back
    -end source code: bitbucket.org/AndrewDunai/nobackend-chat-dirty
    Full-screen version: jsfiddle.net/andunai/kcdtzdww/embedded/result

    Post scriptum

    I am very pleased that you read up to this place. I, as always, welcome any comments and suggestions.
    Hopefully the habraeffect doesn’t hurt my little VPS very much.
    Thanks for attention!

    UPDATE: the repository is now public, accidentally made it private during creation.

    Also popular now: