user4489520
user4489520

Reputation:

401 Unauthorized DELETE request to RESTful API in laravel via Ajax

I've created a restful API using laravel controllers. I have a PhotosController which has a destroy($id) method for resource deletion. also I have a piece of javascript code that sends a DELETE request to my app. the result should be the deletion of the photo with $id id. but laravel doesn't route my request to destroy method. instead it sends an 401 Unauthorized error.

the thing is that I want to send DELETE request to my app via Ajax, but laravel doesn't let my request to be routed!

routes.php file :

Route::resource('photos', 'PhotosController');

destroy method :

public function destroy($id)
{
    try{
        unlink($_SERVER["DOCUMENT_ROOT"].'/uploads/doctors/' . $id);
        Session::forget('photo');
        $msg = Notification::where('flag', 's')->where('code', 'user-update-delete-photo-gallery')->first()->msg;
        return Response::json(array('success' => $msg));
    }catch (Exception $e){
        App::abort(500, $e->getMessage());
    }
}

my Ajax request :

$.ajax(
    {
        url: "/photos/" + name,
        method : "DELETE", // Or POST : result is the same
        data :{
            _token : $("input[name=_token]").val(),
            _method : 'DELETE'
        },
        success: function(data, textStatus, jqXHR ){
            parent.replaceWith("");
            toastr.success(data['success']);
            $("#overlay").hide();
        },
        beforeSend : function(jqXHR, settings ){
            $("#overlay").show();
        },
        error : function(jqXHR, textStatus, errorThrown ){
            toastr.error(jqXHR.responseText);
            $("#overlay").hide();
        }
    }
);

Thanks for your help.

Upvotes: 4

Views: 17197

Answers (2)

Brilliant-DucN
Brilliant-DucN

Reputation: 724

I think your system's requiring the authentication for controller action "destroy" method. So you need to login before calling that method.

If you're using the middleware "auth" (app\Http\Middleware\Authenticate.php), you can easy find the "handle" function that returning "Unauthorized" error.

Hope this will help.

Upvotes: 0

Jared Eitnier
Jared Eitnier

Reputation: 7152

I do this sort of thing all the time in my Laravel Apps with no issues. This code allows the user to delete a resource through AJAX while presenting a bootstrap confirmation dialog first. The code is laid out in the order the events would occur.

VIEW WITH RESOURCE TO DELETE

<a class="delete-plan" href="{{ route('admin.plans.destroy', $plan['id']) }}" data-redirect="{{ route('admin.plans.index') }}" data-plan-name="{{ $plan['name'] }}" data-lang="billing.plans">
    <i class="fa fa-trash fa-lg"></i>
</a>

JQUERY TO PROMPT CONFIRMATION MODAL

$('.delete-plan').on('click', function(e) {
    e.preventDefault();

    var data = {
        'route':        $(this).attr('href'),
        'redirect':     $(this).data('redirect'),
        'modal_title':  'Delete Plan',
        'content_view': 'Are you sure you want to delete plan: <strong>' + $(this).data('plan-name') + '</strong>?',
        'lang':         $(this).data('lang')
    };

    loadDestroyModal(data);
});

function loadDestroyModal(data) {
    $.get('/ajax/destroy-modal', { data: data }, function(modal) {
        $('body').append(modal);
        $('#destroy-modal').modal('show');
    });
}

AJAX CONTROLLER

// routed by /ajax/destroy-modal
public function destroyModal() {
    $data = Input::get('data');

    $params = [
        'route'    => $data['route'],
        'redirect' => $data['redirect'],
        'title'    => $data['modal_title'],
        'content'  => $data['content_view'],
        'lang'     => $data['lang']
    ];

    return View::make('_helpers.modal-destroy', $params);
}

DESTROY CONFIRMATION MODAL (_helpers.modal-destroy)

<div id="destroy-modal" class="modal fade">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">
                    <span aria-hidden="true"><i class="fa fa-times"></i></span>
                    <span class="sr-only">Close</span>
                </button>
                <h4 class="modal-title">{{ $title }}</h4>
            </div>
            <div class="modal-body">
                {{ $content }}
            </div>
            <div class="modal-footer">
                <button id="modal-confirm" type="button" class="btn btn-primary" data-route="{{ $route }}"
                data-redirect="{{ $redirect }}" data-lang="{{ $lang }}">Confirm</button>
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            </div>
        </div>
    </div>
</div>

JQUERY TO PROCESS DESTROY METHOD AND REDIRECT FLASH MESSAGE

$('body').on('click', '#destroy-modal #modal-confirm', function(e) {
    var redirect = $(this).data('redirect');
    var lang     = $(this).data('lang');

    $(this).html('<i class="fa fa-spinner fa-spin"></i> Please Wait');

    $.ajax({
        'url':     $(this).data('route'),
        'type':    'DELETE',
        'success': function(response) {
            if (response) {
                redirectWithFlashMessage(redirect, 'destroy', 'success', lang);
            } else {
                redirectWithFlashMessage(redirect, 'destroy', 'errors', lang);
            }
        }
    });
});

PLANS CONTROLLER

public function destroy($id)
{
    try
    {
        Stripe::plans()->destroy(['id' => $id]);

        return Response::json(TRUE);
    }
    catch (Exception $e)
    {
        return Response::json(FALSE);
    }
}

JQUERY FOR REDIRECTION

function redirectWithFlashMessage(redirect, type, status, lang) {
    var params = {
        type:   type,
        status: status,
        lang:   lang
    };

    $.get('/ajax/flash', params, function(response) {
        window.location.href = redirect;
    });
}

AJAX CONTROLLER (Redirect with Flash)

public function flashData() {
    $message_type = 'success' == Input::get('status') ? 'success' : 'failure';

    $message = Lang::get(Input::get('lang'))[Input::get('type') . '_' . $message_type];

    Session::flash($message_type, $message);

    return ['status' => $message_type, 'message' => $message];
}

It's a lot of code but once setup it's extremely easy to replicate.

Upvotes: 8

Related Questions