Package: cocktail-apikit
Cocktail ApiKitA collection of tools which will be used in all new API project, which including: Bottle, marshmallow, mongo and awsDependenciesPython 3.9-bullseyepymongo: 3.11.4marshmallow: 2.16.3bottle: 0.12.19apispec: 3.7.1boto3: 1.20.48botocore: 1.23.49Usage Example1. Install cocktail apikitpipinstallcocktail-apikit2. Create a demo project2.1 Recommend api project structureexample/
    __init__.py

    settings.py
    application.py

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

    schema/
        __init__.py
        demo.py2.2 plain text configuration filedatabase.iniUse$VAR_NAMEcan support Environment variable, if API_ENV specified, then the corresponding API_ENV configuration
will overload the default configurationsBe careful all the key defined in the ini file should be declared in the project level Settings class[default]; Support Environment variableAPI_ENV=$API_ENVCOLLECTION_NAME=exampleAPI_DEFAULT_LIMIT=40BUCKET_NAME=dev.ioMONGODB_URI=localhost:27017[development];DB_NAME = develop_dbDEMO_COLLECTION=demo_collection[test];DB_NAME = test_dbDEMO_COLLECTION=demo_collection2.3  content of project level setting filesettings.pyimportosfromcocktail_apikitimportDefaultSettingsclassSettings(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.pyfrommarshmallowimportfieldsfromcocktail_apikitimportBaseSchemaclassDemoSchema(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.pyfromsettingsimportSettingsfrombottleimportrequestfromschema.demoimportDemoSchemafromcocktail_apikitimport(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 namedemo_schema=DemoSchema()classDemoResource(ResourcePlugin):# a simple demo endpoint@route_mark('/index')defindex(self):return'hello cocktail apikit'@route_mark('/demos')@enable_cors# allow cors for endpointdeflist_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)returnpagination.serialize(demo_schema)@route_mark('/demos','POST')defcreate_demo(self):payload=request.jsoncleaned_obj,errors=demo_schema.load(payload)iferrors:raiseValidationError(errors)created_ids,errors=demo_db.create(cleaned_obj)iferrors:raiseValidationError(errors)return{"ids":created_ids}@route_mark('/demos/<demo_id>','DELETE')defsoft_delete_demo(self,demo_id):delete_condition={'_id':demo_id}result,errors=demo_db.delete(delete_condition)iferrors:raiseValidationError(errors)ifnotresult.raw_result['updatedExiting']:raiseValidationError({'msg':'Object does not exist or already deleted!'})return{'msg':HTTP_DELETE_OK}@route_mark('/demos/<demo_id>',['PUT','PATCH'])defupdate_demo(self,demo_id):payload=request.jsoncondition={'_id':demo_id}result,errors=demo_db.update(condition,payload)iferrors:raiseValidationError(errors)ifnotresult.raw_result['updatedExisting']:raiseValidationError({'msg':'Does not found any thing to udpate'})return{'msg':HTTP_UPDATE_OK}@route_mark('/auth',auth=True)# Specify endpoint is authentication neededdefauth_demo(self):return{'msg':HTTP_OK}2.6 content of main application.pyfrombottleimportBottlefromcocktail_apikitimportFlexibleJsonPlugin,CorsPlugin,APP_ERROR_HANDLERfromapi.demoimportDemoResourceapp=Bottle()# install FlexibleJsonPlugin to enable handle more data typeapp.install(FlexibleJsonPlugin())# install endpoint resource class`s instanceapp.install(DemoResource())app.install(CorsPlugin())#config application object's error handlersapp.error_handler=APP_ERROR_HANDLERif__name__=="__main__":app.run(port=8000,debug=True,reloader=True)2.7  Then we can run 'python application.py', and access### Create a demoPOST http://localhost:8000/demos{"name": "test1"}### list all demosGET  http://localhost:8000/demos### update a demoPUT http://localhost:8000/demos/<demo_id>### delete a demoDELETE http://localhost:8000/demos/<demo_id>3. Endpoint AuthenticationIf you want to create an endpoint with authentication need, you can follow the following example:frombottleimportrequestfromcocktail_apikitimportAuthentication,ResourcePlugin,route_mark,HTTP_OKclassMyAuthentication(Authentication):defis_authenticated(self,*args,**kwargs):authentcation_data=request.headers.get('authorization')returnauthentcation_data=='authorization'classAuthDemoResource(ResourcePlugin):authentication=MyAuthentication()@route_mark('/auth',auth=True)#Default auth=False which means does not need authenticationdefauth_endpoint(self):return{'msg':HTTP_OK}When you do requesthttp://localhost:80000/authwithout authorization data will raise Unauthorized error
When do request above withAuthorization=authorizationwill return{ "msg": "OK" }