tethysplatform / tethys

The Tethys Platform main Django website project repository.
http://tethysplatform.org/
BSD 2-Clause "Simplified" License
92 stars 49 forks source link

[FEATURE] Add API-related decorators to Tethys Controller decorator #932

Open msouff opened 1 year ago

msouff commented 1 year ago

Is your feature request related to a problem? Please describe. Django REST Framework uses various decorators including @api_view, @permission_classes, @authentication_classes, and @csrf_exempt. This last one actually comes from Django but allows the developer to disable csrf for a specific call, which is needed if you plan on having an open API.

At the moment, we cannot have csrf_exempt controllers unless the login_required parameter is set to False, and thecontroller decorator needs to be sandwiched between @csrf_exempt and @api_view.

# This works
@api_view(['POST'])
@permission_classes([AllowAny])
@controller(name='my_app', url='my-app/api/call', app_workspace=True, login_required=False)
@csrf_exempt
def api_call(request, app_workspace):
    pass

# This does not
@api_view(['POST'])
@permission_classes([AllowAny])
@csrf_exempt
@controller(name='my_app', url='my-app/api/call', app_workspace=True)
def api_call(request, app_workspace):
    pass

Describe the solution you'd like

# Suggested change
@controller(
    name='my_app',
    url='my-app/api/call',
    app_workspace=True,
    csrf_exempt=True,
    api_view=['POST'],
    permission_classes=[AllowAny]
)
def api_call(request, app_workspace):
    pass

Describe alternatives you've considered It would be nice if the Tethys controller could be extended to accept any additional decorator as part of a new parameter in the order they are provided. That would take care of any future decorator issues in an elegant way.

# Alternative
@controller(
    name='my_app',
    url='my-app/api/call',
    app_workspace=True,
    other_decorators=[
        [csrf_exempt],
        [api_view, ['GET']], 
        [authentication_classes, [TokenAuthentication]]
    ]
)
def api_call(request, app_workspace):
    pass