Skip to main content

Cocktail ApiKit

A collection of tools which will be used in all new API project, which including: Bottle, marshmallow, mongo and aws

apikit structure

Dependencies

  • Python 3.9-bullseye
  • pymongo: 3.11.4
  • marshmallow: 2.16.3
  • bottle: 0.12.19
  • apispec: 3.7.1
  • boto3: 1.20.48
  • botocore: 1.23.49

Usage Example

1. Install cocktail apikit

pip install cocktail-apikit

2. Create a demo project

2.1 Recommend api project structure

example/
    __init__.py

    settings.py
    application.py

    config/
        database.ini
    api/
        __init__.py
        demo.py

    schema/
        __init__.py
        demo.py

2.2 plain text configuration file database.ini

Use $VAR_NAME can support Environment variable, if API_ENV specified, then the corresponding API_ENV configuration will overload the default configurations Be careful all the key defined in the ini file should be declared in the project level Settings class

[default]
; Support Environment variable 
API_ENV=$API_ENV 
COLLECTION_NAME = example
API_DEFAULT_LIMIT = 40
BUCKET_NAME=dev.io
MONGODB_URI=localhost:27017

[development]
;DB_NAME = develop_db
DEMO_COLLECTION = demo_collection

[test]
;DB_NAME = test_db
DEMO_COLLECTION = demo_collection

2.3 content of project level setting file settings.py

import os
from cocktail_apikit import DefaultSettings
class Settings(DefaultSettings):

    # specify configuration file names to load configuration from file
    # Be aware, any configuration fields in configuration file should be 
    # declare in the settings class  or any its super class, just 
    # to make us have better IDE auto-complete help
    _config_files = ['config/database.ini']

    # **REQUIRED: for Settings class can find the files in the _config_files attribute in any situation**
    BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 

2.4 content of a demo Schema in schema/demo.py

from marshmallow import fields 
from cocktail_apikit import BaseSchema 

class DemoSchema(BaseSchema):
    """
    BaseSchema included some common fields: id, created_at, updated_at, deleted_at;
    Also contains some util method from SchemaMongoMixin for communicate with mongo db
    """
    name = fields.Str()

2.5 content of a endpoint Resource in api/demo.py

from settings import Settings
from bottle import request 
from schema.demo import DemoSchema

from cocktail_apikit import (
    ResourcePlugin,  route_mark,  ValidationError,  MongoDBManager,  enable_cors,
    BottleMongoQueryBuilder, Pagination, HTTP_DELETE_OK, HTTP_UPDATE_OK, HTTP_OK
)


demo_db = MongoDBManager(Settings.mongo_config_for_collection('demo')) # specify a Config option name or be the given name
demo_schema = DemoSchema()

class DemoResource(ResourcePlugin):

    # a simple demo endpoint
    @route_mark('/index')
    def index(self):
        return 'hello cocktail apikit'

    @route_mark('/demos')
    @enable_cors # allow cors for endpoint
    def list_demo(self):

        mongo_query_builder = BottleMongoQueryBuilder(request, demo_schema)
        mongo_query = mongo_query_builder.to_mongo_query()
        results, count = demo_db.filter(mongo_query)
        pagination = Pagination(mongo_query, results, count)
        return pagination.serialize(demo_schema)


    @route_mark('/demos', 'POST')
    def create_demo(self):
        payload = request.json
        cleaned_obj, errors = demo_schema.load(payload)
        if errors:
            raise ValidationError(errors)

        created_ids, errors = demo_db.create(cleaned_obj)

        if errors:
            raise ValidationError(errors)

        return {
            "ids": created_ids 
        }

    @route_mark('/demos/<demo_id>', 'DELETE')
    def soft_delete_demo(self, demo_id):
        delete_condition = {'_id':demo_id}

        result, errors = demo_db.delete(delete_condition)

        if errors:
            raise ValidationError(errors)

        if not result.raw_result['updatedExiting']:
            raise ValidationError({
                'msg': 'Object does not exist or already deleted!'
            })
        return {
            'msg':HTTP_DELETE_OK
        }


    @route_mark('/demos/<demo_id>', ['PUT','PATCH'])
    def update_demo(self, demo_id):
        payload = request.json
        condition = {'_id':demo_id}

        result, errors = demo_db.update(condition, payload)
        if errors:
            raise ValidationError(errors)
        if not result.raw_result['updatedExisting']:
            raise ValidationError({
                'msg': 'Does not found any thing to udpate'
            })
        return {'msg':HTTP_UPDATE_OK}
        
        
    @route_mark('/auth', auth=True) # Specify endpoint is authentication needed
    def auth_demo(self):
        return {'msg':HTTP_OK}

2.6 content of main application.py

from bottle import Bottle
from cocktail_apikit import FlexibleJsonPlugin, CorsPlugin, APP_ERROR_HANDLER
from api.demo import DemoResource

app  = Bottle()

# install FlexibleJsonPlugin to enable handle more data type
app.install(FlexibleJsonPlugin())

# install endpoint resource class`s instance
app.install(DemoResource())

app.install(CorsPlugin())

#config application object's error handlers
app.error_handler = APP_ERROR_HANDLER

if __name__ == "__main__":
    app.run(port=8000, debug=True, reloader=True)

2.7 Then we can run 'python application.py', and access

### Create a demo
POST http://localhost:8000/demos

{
  "name": "test1"
}


### list all demos
GET  http://localhost:8000/demos

### update a demo
PUT http://localhost:8000/demos/<demo_id>

### delete a demo
DELETE http://localhost:8000/demos/<demo_id>

3. Endpoint Authentication

If you want to create an endpoint with authentication need, you can follow the following example:

from bottle import request
from cocktail_apikit import Authentication, ResourcePlugin, route_mark, HTTP_OK

class MyAuthentication(Authentication):
    def is_authenticated(self, *args, **kwargs):
        authentcation_data = request.headers.get('authorization')
        return authentcation_data == 'authorization'
    

class AuthDemoResource(ResourcePlugin):
    
    authentication = MyAuthentication()

    @route_mark('/auth', auth=True) #Default auth=False which means does not need authentication
    def auth_endpoint(self):
        return {'msg':HTTP_OK}
        

When you do request http://localhost:80000/auth without authorization data will raise Unauthorized error When do request above with Authorization=authorization will return { "msg": "OK" }

Release files for cocktail-apikit 0.1.22

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cocktail-apikit 0.1.22
File Size Uploaded
cocktail-apikit-0.1.22.tar.gz 29.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cocktail-apikit 0.1.22
File Interpreter ABI Platform
cocktail_apikit-0.1.22-py3-none-any.whl Python 3 none any Details

Total release size: 55.3 kB

Release files / cocktail-apikit-0.1.22.tar.gz

Download URL cocktail-apikit-0.1.22.tar.gz
Size 29.4 kB
Tags Source
SHA-256 checksum
How to use checksums
8b0867d09da15f8e63f82881f76d820f4d12b9d296e90d6ab6a6876e3a89e69f
BLAKE2b-256 checksum
How to use checksums
d9ac5bc9897e3382bb0252248443853e69fa03817d7870699d39e7aa24665ae2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.62.3 importlib-metadata/4.11.1 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.10

Release files / cocktail_apikit-0.1.22-py3-none-any.whl

Download URL cocktail_apikit-0.1.22-py3-none-any.whl
Size 25.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6b9d23c164a9f975a2b27f52762d60fec72f3fb307c10a282104afc7b1b38a75
BLAKE2b-256 checksum
How to use checksums
53d194456be99cb2cbf2d051a4fd46bda8c59a27bbc444dff2a8212a4ba1fa45
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.8.0 pkginfo/1.8.2 readme-renderer/32.0 requests/2.27.1 requests-toolbelt/0.9.1 urllib3/1.26.8 tqdm/4.62.3 importlib-metadata/4.11.1 keyring/23.5.0 rfc3986/2.0.0 colorama/0.4.4 CPython/3.9.10

Release history Release notifications | RSS feed

This release

0.1.22 This release

2 release files

0.1.21

2 release files

0.1.20

2 release files

0.1.18

2 release files

0.1.17

2 release files

0.1.16

2 release files

0.1.15

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.0.32

2 release files

0.0.31

2 release files

0.0.30

2 release files

0.0.29

2 release files

0.0.28

2 release files

0.0.27

2 release files

0.0.26

2 release files

0.0.25

2 release files

0.0.24

2 release files

0.0.23

2 release files

0.0.20

2 release files

0.0.19

2 release files

0.0.18

2 release files

0.0.17

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page