Search code examples
c#asp.net-coreasp.net-core-mvcasp.net-core-2.0asp.net-core-2.2

How to make a PATCH request to am API with ASP.NET Core 2.2?


I have an application that is written using C# on the top of ASP.NET Core 2.2. I created a controller that responds to a PATCH request called Update. Here is my controller

[Route("api/[controller]"), ApiController, Produces("application/json")]
public class CategoriesController : ControllerBase
{
    [HttpPatch("{propertyId}/{listId}/{isOn}"), Authorize]
    public ActionResult<bool> Update(int propertyId, int listId, bool isOn)
    {
        // Do something
        return true;
    }
}

also, to return a 401 error when the user isn't authorized instead of a redirect, I added the following code to my Startup class

services.ConfigureApplicationCookie(config =>
{
    config.Events = new CookieAuthenticationEvents
    {
        OnRedirectToLogin = ctx =>
        {
            if (ctx.Request.Path.StartsWithSegments("/api", StringComparison.CurrentCultureIgnoreCase))
            {
                ctx.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            }
            else
            {
                ctx.Response.Redirect(ctx.RedirectUri);
            }

            return Task.FromResult(0);
        }
    };
});

Now to call this API using jQuery I did the following

$('.update-property').click(function (e) {
    e.preventDefault();
    var obj = $(this);
    $.ajax({
        url: '/api/Categories/Update',
        type: 'PATCH',
        data: {
            'propertyId': obj.data('property-id'),
            'listId': obj.data('list-id'),
            'isOn': obj.data('is-on') === 'True' ? 'false' : 'true'
        },

        success: function (response) {

            console.log(response);

            // if response unauthorized, redirect to the login page with the ReturnUrl
            // else if response.data is true then change the icon
        }
    });
});

But this request keeps returning a 404 http error code. I inspected this question in the developer tools and I see that the parameter are being set correctly and the URL is valid.

How can I correctly handle this PATCH request?


Solution

  • [Route("api/[controller]"), ApiController, Produces("application/json")]
    public class CategoriesController : ControllerBase
    {
        [HttpPatch("{propertyId}/{listId}/{isOn}"), Authorize]
        public ActionResult<bool> Update(int propertyId, int listId, bool isOn)
    

    The route templates here determine the URL for your Update endpoint. In this case, the resulting URL template would be this:

    api/Categories/{propertyId}/{listId}/{isOn}
    

    So for example, a valid URL for this endpoint would be /api/Categories/12/34/true.

    If you don’t want to pass the values as parameters (since you already pass them in the body), you have to change the route template. For example, you could just remove the route template on the action method:

    [HttpPatch, Authorize]
    public ActionResult<bool> Update(int propertyId, int listId, bool isOn)
    // …
    

    Then, the URL would be just api/Categories.

    Of course, you could also make api/Categories/Update the URL for the endpoint, but with REST, it’s usually not recommended to have method names in the URL. A PATCH request usually means “update this resource” and then you would be pointing to the URL of the resource.