Page 1 of 1

Not Found returning 405

PostPosted: Tue Nov 17, 2020 4:34 pm
by SBarnes
I have the code below to return an image for a route it works fine but when you give it a bad inventory ID it is returning a 405 instead of a 404, it is definitely producing the RecordNotFoundException but just the wrong status code any ideas how to resolve this?


Code: Select all
         [Authenticate]
         [AddHeader(ContentType = "image/png")]
         public byte[] Get( ImageRequest request)
         {

            JiwaApplication.Manager manager = this.SessionAs<JiwaAuthUserSession>().Manager;
            JiwaFinancials.Jiwa.JiwaInventory.Inventory inv =  manager.BusinessLogicFactory.CreateBusinessLogic<JiwaFinancials.Jiwa.JiwaInventory.Inventory>(null);
            try
            {
               inv.Read(request.InventoryID);
            }
            catch(Exception ex)
            {
               
               throw new JiwaApplication.Exceptions.RecordNotFoundException("Product not found for " + request.InventoryID);
            }
            

            return inv.Picture;
         }

Re: Not Found returning 405

PostPosted: Tue Nov 17, 2020 5:05 pm
by Mike.Sheen
Hi Stuart,

Does the response header contain an Allow field? a 405 response is supposed to have an Allow field which contains a list of allowed operations on that route. So, I think a 405 should be returned is you're trying to POST to a route which only knows how to GET on that, or something like that.

How we return a 404 when a RecordNotFoundException is encountered is via some exception mapping we add in the Configure method of the REST API plugin:

Code: Select all
AppHost.Config.MapExceptionToStatusCode.Add(typeof(JiwaApplication.Exceptions.RecordNotFoundException), 404);
AppHost.Config.MapExceptionToStatusCode.Add(typeof(JiwaApplication.Exceptions.LicencingException), 403);
AppHost.Config.MapExceptionToStatusCode.Add(typeof(JiwaApplication.Exceptions.PermissionDeniedException), 403);
AppHost.Config.MapExceptionToStatusCode.Add(typeof(JiwaApplication.Exceptions.ConcurrencyConflictException), 409);
AppHost.Config.MapExceptionToStatusCode.Add(typeof(JiwaApplication.Exceptions.RecordInUseException), 409);
AppHost.Config.MapExceptionToStatusCode.Add(typeof(JiwaFinancials.Jiwa.JiwaODBC.Exceptions.BadLoginException), 401);


If you've not explicitly gone and added your own mappings or modified ours, then it's likely as I said earlier - you've added a GET operation but the client is performing a POST or something other than a GET. Make sure the AppHost.Routes.Add you have for the route correctly passes the right verb - eg:

Code: Select all
AppHost.Routes.Add(typeof(DebtorAPIKeyDebtorGETRequest), "/Debtors", "GET", "Retrieves a debtor for a API Key authenticated customer.", "");

The "GET" above is the verb .

Re: Not Found returning 405

PostPosted: Tue Nov 17, 2020 5:11 pm
by Mike.Sheen
Oh, and you shouldn't do this :

Code: Select all
catch(Exception ex)


You really should only catch the RecordNotFoundException - if a different exception is encountered (like maybe the SQL Server is unreachable) you don't want to return a 404 so you want to:

Code: Select all
catch(JiwaApplication.Exceptions.RecordNotFoundException(ex)
{
    throw new JiwaApplication.Exceptions.RecordNotFoundException("Product not found for " + request.InventoryID);
}


And given that you're not adding much value to the exception with your own throw (the caller should already know the InventoryID as they provided it to you) you can probably dispense with the try catch block altogether :)

Re: Not Found returning 405

PostPosted: Tue Nov 17, 2020 5:22 pm
by SBarnes
Not I haven't added any mappings for exceptions is was because of the ones you have in the main plugin that I changed to the RecordNotFoundException instead of Exception, could it be because of the following line?

Code: Select all
 [AddHeader(ContentType = "image/png")]


But it is definitely getting the RecordNotFoundException as that's even showing up in Postman and it is definitely doing a GET.

Routes added as


Code: Select all
AppHost.Routes.Add(typeof(ImageRequest), "/Images/GetImage", "GET", "Get the image for the inventory.", "");
         
AppHost.Routes.Add(typeof(ImagePartNoRequest), "/Images/GetImageFromPartNo", "GET", "Get the image for the inventory based upon part no.", "");