Giter VIP home page Giter VIP logo

symmetric's Introduction

Symmetric

PyPI - Version PyPI - Downloads

A powerful tool to enable super fast module-to-API transformations. Learn in minutes, implement in seconds. Batteries included.

Tests Workflow Linters Workflow

Disclaimer

symmetric is no longer being maintained. But don't worry! Its spiritual successor, asymmetric, has an essentially identical API, and is faster, better designed, and has a bunch of new features. The symmetric token is the only feature present in symmetric that won't be part of asymmetric. Other than that, you can port your code performing a search and replace, replacing all the appearances of symmetric for asymmetric. Thank you for being a part of this project! Hope to see you around asymmetric!

Why Symmetric?

Raw developing speed and ease of use, that's why. symmetric is based on Flask! While Flask is a powerful tool to have, getting it to work from scratch can be a bit of a pain, especially if you have never used it before. The idea behind symmetric is to be able to take any module already written and transform it into a working API in a matter of minutes, instead of having to design the module ground-up to work with Flask (it can also be used to build an API from scratch really fast). With symmetric, you will also get some neat features, namely:

  • Auto logging.
  • Server-side error detection and exception handling.
  • Auto-generated /docs endpoint for your API with interactive documentation.
  • Native support for an authentication token on a per-endpoint basis.
  • Auto-generated OpenAPI Specification and Markdown documentation files for your API.

The complete documentation is available on the official website.

Installing

Install using pip!

pip install symmetric

Usage

Running the development server

To start the development server, just run:

symmetric run <module>

Where <module> is your module name (in the examples, we will be writing in a file named module.py, so the module name will be just module). A Flask instance will be spawned immediately and can be reached at http://127.0.0.1:5000 by default. We don't have any endpoints yet, so we'll add some later. Do not use this in production. The Flask server is meant for development only. Instead, you can use any WSGI server to run the API. For example, to run the API using gunicorn, you just need to run gunicorn module:symmetric and a production ready server will be spawned.

Defining the API endpoints

The module consists of a main object called symmetric, which includes an important element: the router decorator. Let's analyze it:

from symmetric import symmetric

@symmetric.router("/some-route", methods=["post"], response_code=200, auth_token=False)

The decorator recieves 4 arguments: the route argument (the endpoint of the API to which the decorated function will map), the methods argument (a list of the methods accepted to connect to that endpoint, defaults in only POST requests), the response_code argument (the response code of the endpoint if everything goes according to the plan. Defaults to 200) and the auth_token argument (a boolean stating if the endpoint requires authentication using a symmetric token. Defaults to False).

Now let's imagine that we have the following method:

def some_function():
    """Greets the world."""
    return "Hello World!"

To transform that method into an API endpoint, all you need to do is add one line:

@symmetric.router("/sample", methods=["get"])
def some_function():
    """Greets the world."""
    return "Hello World!"

Run symmetric run module and send a GET request to http://127.0.0.1:5000/sample. You should get a Hello World! in response! (To try it with a browser, make sure to run the above command and click this link).

But what about methods with arguments? Of course they can be API'd too! Let's now say that you have the following function:

def another_function(a, b=372):
    """
    Adds :a and :b and returns the result of
    that operation.
    """
    return a + b

To transform that method into an API endpoint, all you need to do, again, is add one line:

@symmetric.router("/add")
def another_function(a, b=372):
    """
    Adds :a and :b and returns the result of
    that operation.
    """
    return a + b

Querying API endpoints

To give parameters to a function, all we need to do is send a json body with the names of the parameters as keys. Let's see how! Run symmetric run module and send a POST request (the default HTTP method) to http://127.0.0.1:5000/add, now using the requests module.

import requests

payload = {
    "a": 48,
    "b": 21
}
response = requests.post("http://127.0.0.1:5000/add", json=payload)
print(response.json())

We got a 69 response! (48 + 21 = 69). Of course, you can return dictionaries from your methods and those will get returned as a json body in the response object automagically!

With this in mind, you can transform any existing project into a usable API very quickly!

ReDoc Documentation

By default, you can GET the /docs endpoint (using a browser) to access to interactive auto-generated documentation about your API. It will include request bodies for each endpoint, response codes, authentication required, default values, and much more!

Tip: Given that the ReDoc Documentation is based on the OpenAPI standard, using type annotations in your code will result in a more detailed interactive documentation. Instead of the parameters being allowed to be any type, they will be forced into the type declared in your code. Cool, right?

Developing

Clone the repository:

git clone https://github.com/daleal/symmetric.git

cd symmetric

Recreate environment:

./environment.sh

. .venv/bin/activate

Test install:

poetry install  # will also install the symmetric CLI

Run the tests:

python -m unittest

Resources

symmetric's People

Contributors

daleal 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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

vibster

symmetric's Issues

Restrict endpoint names

Right now two endpoints can have the same URL (probably Flask would not like that), so maybe symmetric should raise an exception if this happens before Flask.

Add tests

It seems obvious, but some tests need to be added in order to keep the sanity of the repo while the code grows.

Application context auto handling for running tests

When trying to test a function in a module wrapped by symmetric by running python -m unittest, for example, the following error pops up:

RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that needed
to interface with the current application object in some way. To solve
this, set up an application context with app.app_context().  See the
documentation for more information

Apparently, this really has to do with flask's application context and it's the expected behavior when testing flask wrapped modules.

Even if this is not technically a bug, I think that it's a must to provide a way to auto-handle the app_context during test runs to ensure that a module can be wrapped with symmetric without the need to touch any code at all.

Add support for REST APIs

Due to symmetric restricting the path names only by mere existence and not accounting for the HTTP method defined, it is impossible to write REST APIs (a path can only run one function, no matter what HTTP methods are used). The objective of symmetric is not no be a full blown REST wrapper over Flask, but to be a simple library to help deploy already written modules with little to no hassle. I would consider this issue to be low priority, but maybe it is worth to give it a shot (it would require some major re-structuring labors of the codebase, but I think that it can be done)

Add API auto-documentation

It would be nice if the endpoints could document theirselves (maybe with a CLI tool) and include endpoint names, request types and expected json data.

Import the decorator and the app object in a custom object

To prevent developers to forget to import the app object and then not being able to start the server, it may be a good idea to encapsulate the router decorator and the app object into a special symmetric object that can be imported and used to decorate like @symmetric.router("/endpoint"), and start the server running symmetric.run() applying a chain of responsibility.

It is important to keep in mind that this change would break every script currently using symmetric, so a major version change would have to be made (also, a very large chunk of the README should have to be updated).

Add native token requirement

It would be a good idea to implement a sort of native token requirement if an endpoint was given an extra parameter. What I mean by this is that the wrapper, if asked for, could check if, for example, the request body parameter symmetric_api_key is equal to an environmental SYMMETRIC_API_KEY and deny access to any request that does not include the correct key,

Add docs endpoint

It should be possible to access to /docs and get the same documentation generated by the symmetric docs <module>. One possibility is to use something like Swagger UI. Another possibility is to render the markdown documentation directly into an HTML. The latter would be the simplest choice, given that the markdown documentation is already generated. The problem with this is that it requires a third party library for converting markdown to HTML.

Add pull request template

It might be necessary to standardize pull requests for the future, so a template seems like a good idea.

Add option to change the log file name via CLI

Right now, the default log file name is symmetric.log an it's defined by the constant LOG_FILE_NAME inside the module symmetric.constants. It might be a good idea to add the option to change that file name via the command startup utility (the file name can already be changed by adding an environmental variable LOG_FILE with the desired file name).

Add CLI to start the server

Starting the server with a command like symmetric module:app could mean that data scientists would not need to remove code under the line if __name__ == "__main__": every time just to run the server, so they could test their module methods in a more natural fashion and then just start the server from a console, if they so want.

Add option to change authentication token names

Right now, the key of the token in the request body must be "symmetric_api_key" an it's defined by the constant API_CLIENT_TOKEN_NAME inside the module symmetric.constants. Similar to this, the key of the environmental variable holding the token on the server side must be "SYMMETRIC_API_KEY" and it's defined by the constant API_SERVER_TOKEN_NAME inside the module symmetric.constants.

It might be a good idea to consider adding a method to change these default values, something like symmetric.set_client_token_name(token_name) and symmetric.set_server_token_name(token_name). The symmetric object would have to hold the token name values, so a bit of a change must be made, but it doesn't seem too complex.

Adding this would make the module more complex to use (more configuration), which is exactly the opposite of the philosophy of symmetric, so that's also something to consider.

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.