cutshort 0.0.4
Yet another, experimental utility to write wsgi REST API apps using python functions, Mostly.
License: MIT
Keywords: python,wsgi,RESTAPI,function-to-rest-endpoint

# **Cutshort**
Yet another, experimental `nano framework` to write WSGI REST API apps using python functions, mostly. 

## How to Install
`pip install cutshort`

## A Pic Generated by `Dall-E`
I was looking for a dark, pale yet dope background image for `cutshort`. So, `Dall-E` game me this.
Prompt was, 
```commandline
night sky with a terror looking blackhole, digital art, high resolution
```
![background](/img/background.png)

## The Very First Hello World
`Cutshort` is developed keeping in mind that you write a python function, and you would directly publish it to let it be consumed.
 First import `API` and `simple_server` from `cutshort`
```python
from cutshort import API, simple_server
```
Instantiate the `API` object and follow on.
```python
api = API()
```
By default, it is going to console print some logs. ( will remove it pretty soon, promise).
To avoid logging, 
```python
api = API(debug= False)
```
Define any python function,
```python
def get_summation(a: int, b: int):
    return a + b
```
Register this function to `API` object. 
```python
api.add_func(get_summation, path='/', http_method='GET')
```
`add_func` receives a `handler_function`, a `path` variable and `http_method`. 

## Automatic method registering with routing path
`cutshort` can check the `handler_func` name and can assign both `routing_path` and `http_method`. 

Function name should start with a action name like `create`,`update`, `get`, `fetch` etc followed by a `_` underscore and
a `resource` name with some extension. example
```python
user_db = [
    {'ID': 1, 'name': 'John Doe', 'age': 21},
    {'ID': 2, 'name': 'Jane Doe', 'age': 23}]

def get_users():
    resp = {
        'users': user_db
    }
    return resp

api.add_func(get_users)
```
So, `api.add_func(get_users)` would set the routing path to `get_users` and `http_method` to 'GET'

## Handling Function Parameters
`cutshort` currenly only supports inputs from `Request-Body` and `JSON-ENCODED`. Internally, when a handler is set against
a particular routing path, request processor first looks for the params in the request-body in JSON, and then delivers it
to the function. After the processing, it collects the response and sends the response after json encoding.
Example:
```python
def get_user_by_id(user_id: int):
    for user in user_db:
        if user.get('ID') == user_id:
            resp = {
                'user': user
            }
            return resp
    return None
```
Here, the request body should be, 
```json
{
	"user_id": 1
}
```
while sending request from `Insomnia` or `POSTMAN` HTTP Clients.

## Running the Application
As `API` is a WSGI callable so it can easily be run with `Gunicorn`, `Waitress` or any similar `WSGIServer`. 
For development purpose, a simple server `simple_server` is provided with `cutshort`, which is a very light wrap-around `simple_server` from
`werkzeug`. So,  running is simply, 
```python
if __name__ == '__main__':
    simple_server(host='localhost', port=8456, application=api)
```

## Complete Example [Almost]
```python
from cutshort import API, simple_server

api = API()

user_db = [
    {'ID': 1, 'name': 'John Doe', 'age': 21},
    {'ID': 2, 'name': 'Jane Doe', 'age': 23}]


def get_summation(a: int, b: int):
    return a + b


def get_users():
    resp = {
        'users': user_db
    }
    return resp


def get_user_by_id(user_id: int):
    for user in user_db:
        if user.get('ID') == user_id:
            resp = {
                'user': user
            }
            return resp
    return None


def create_user(id: int, name: str, age: int):
    user = {
        'ID': id,
        'name': name,
        'age': age
    }
    user_db.append(user)
    return user_db


def delete_user(id: int):
    for index, user in enumerate(user_db):
        if user.get('ID') == id:
            user_db.remove(user)
            return user_db
    return None


def update_user(id: int, name: str):
    for user in user_db:
        if user.get('ID') == id:
            user['name'] = name
            return user
    return None


def send_message(message: str):
    return 'Your Message is + {}'.format(message)


api.add_func(get_summation, path='/', http_method='GET')
api.add_func(send_message,http_method='POST')
api.add_func(get_users)
api.add_func(get_user_by_id)
api.add_func(create_user)
api.add_func(delete_user)
api.add_func(update_user)

if __name__ == '__main__':
    simple_server(host='localhost', port=8456, application=api)
```

## Future Planning
1. Adding Middleware support for interacting with `Request` and `Response` objects.
2. Reading function params from `url-params`.
3. Adding proper logging and debugging messages. 


## Inspirations
This is a pet project and it should not be considered to be using in a critical production environment. This project 
heavily relies on python packages like `parse`, `WebOb` and `Werkzeug`. 

Also, `cutshort` is inspired by [Lumi](https://github.com/Tanmoy741127/lumi)