Package: whatever-rest-framework
Whatever REST FrameworkDISCLAIMER:This is WIP. Next steps I can think:Review the TODOs I have left in the projectDocument input/output of every component's methodCreate unit tests for base componentsWhat?Basically this is an agnostic and thin layer to create RESTful APIs.Why?Honestly because I every time I have to develop an API I tend to use Django just because of Django Rest Framework (and yes, this is my personal opinion).I would love to be able to create my RESTful APIs in whatever framework/technology I wanted to.How?pip install whatever-rest-frameworkThere are a bunch of full working projects as examples. Please see thetests folder.In details, you'll need to:1) Create anAPIOrchestratorby choosing a bunch of componentsThe types of base components you can choose for the API orchestrator are:TypeImplementationsMust be set?Defaultframework_component_classChaliceFrameworkComponent, DjangoFrameworkComponent, FalconFrameworkComponent, FlaskFrameworkComponent, PyramidFrameworkComponentYesNoneorm_component_classDjangoORMComponent, PeeweeORMComponent, SQLAlchemyORMComponentYesNoneschema_component_classMarshmallowSchemaComponent, MarshmallowSQLAlchemySchemaComponentYesNoneerror_component_classDefaultErrorComponentNoDefaultErrorComponentpagination_component_classNoPagePaginationComponent, PagePagePaginationComponentNoNoPagePaginationComponentpermission_component_classAllowAllPermissionComponent, AllowAuthenticatedPermissionComponent, ReadOnlyPermissionComponentNoAllowAllPermissionComponent2) Define theget_current_user(self)method inside this orchestratorThe logic to discover the current user of a request is heavily dependant of the framework (and the tools you use), and I decided not to include it in the scope of this project.
Ideally this can be simple asdef get_current_user(self): return g.useror evendef get_current_user(self): return self.request.user if self.request.user.is_authenticated else None.3) Create your APIs inheriting from theAPIOrchestratorThese APIs need to set the attributesmodel_classandschema_class. Also you have to set theget_queryset(self)method.
Here you have full, magic access to the basic API CRUD methods (list resources, retrieve resource, create resource, update resource, delete resource).Special note: the@api_view()decorator:You can add other specific methods to your needs by adding methods to the API class too! Just decorate your custom methods with the@api_view()decorator and you're good to go!
This decorator can receive as arguments the components override to be used for that particular method. So you can have, for instance, your APIOrchestrator with permission=AllowAllPermissionComponentbut this particular method with permission=AllowAuthenticatedPermissionComponentjust by like below:classAPIOrchestrator(BaseAPI):permission_component_class=AllowAllPermissionComponent# ...@api_view(permission_component_class=AllowAuthenticatedPermissionComponent)defretrieve_more_private_stuff(self):return{'super-private':'data'}Working example for a flask application:fromfunctoolsimportpartialfromwrf.api.baseimportBaseAPI,api_viewfromwrf.framework.flaskimportFlaskFrameworkComponentfromwrf.orm.sqlalchemyimportSQLAlchemyORMComponentfromwrf.schema.marshmallow_sqlalchemyimportMarshmallowSQLAlchemySchemaComponentfrom<your_stuff>importapp,db,User,UserSchemaclassAPIOrchestrator(BaseAPI):orm_component_class=partial(SQLAlchemyORMComponent,session=db.session)schema_component_class=MarshmallowSQLAlchemySchemaComponentframework_component_class=FlaskFrameworkComponentdefget_current_user(self):# from flask_login import current_user; return current_user # if you're using flask-login, for example# return self.request.user if self.request.user.is_authenticated else None  # if you're using django, for examplereturn{'name':'Filipe'}classUserAPI(APIOrchestrator):model_class=Userschema_class=UserSchemadefget_queryset(self):returnUser.query@api_view()defretrieve_something_else(self,pk):user=User.query.filter_by(id=pk).one()return{'something_else':user.something_else}@app.route('/',methods=['GET'])deflist_():returnUserAPI(request).list()@app.route('/',methods=['POST'])defcreate():returnUserAPI(request).create()@app.route('/<int:pk>/',methods=['GET'])defretrieve(pk):returnUserAPI(request).retrieve(pk)@app.route('/<int:pk>/',methods=['PATCH'])defupdate(pk):returnUserAPI(request).update(pk)@app.route('/<int:pk>/',methods=['DELETE'])defdelete(pk):returnUserAPI(request).delete(pk)@app.route('/<int:pk>/something_else/',methods=['GET'])defretrieve_something_else(pk):returnUserAPI(request).retrieve_something_else(pk)Supported technologiesFramework:ChaliceDjangoFalconFlaskPyramidORM:DjangoPeeweeSQLAlchemySchema:MarshmallowMarshmallow-SQLAlchemyBear in mind that this project is made to be easily extensible, so if you need to connect something else, it's simple to do it.Check how simple it is to add support to a new framework, for example. =DContributingPleaseopen issuesif you see one, orcreate a pull requestwhen possible.In case of a pull request, please consider the following:Respect the line length (132 characters)Keep the great test coverage of this projectRuntoxlocally so you can see if everything is green (including linter and other python versions)