From a3722d89ff19780f9995da48e736d575bef6fb70 Mon Sep 17 00:00:00 2001 From: Georgy Litvinov Date: Fri, 11 Aug 2023 09:16:05 +0200 Subject: [PATCH] Custom REST actions fixes to support specified http methods and provide correct documentation (#413) * Custom REST actions fixes to support specified http methods and provide correct documentation * fix: hide RESTEndpoint expections while running tests * fix: test message in RESTEndpointTest * improve log error message * fix for prev commit --------- Co-authored-by: Georgy Litvinov --- .../dynapi/DynamicAPIDocumentation.java | 19 ++++++++++++++++++- .../vitro/webapp/dynapi/RESTEndpoint.java | 9 ++------- .../dynapi/components/CustomRESTAction.java | 10 ++++++++++ .../webapp/dynapi/components/ResourceAPI.java | 8 ++++---- .../vitro/webapp/dynapi/LoggingControl.java | 2 ++ .../vitro/webapp/dynapi/RESTEndpointTest.java | 8 ++++---- 6 files changed, 40 insertions(+), 16 deletions(-) diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/DynamicAPIDocumentation.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/DynamicAPIDocumentation.java index 1aedaf01c4..f316649cdf 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/DynamicAPIDocumentation.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/DynamicAPIDocumentation.java @@ -376,7 +376,24 @@ private PathItem customRESTActionPathItem(CustomRESTAction customRESTAction, Tag if (targetRPC != null) { try (Procedure action = actionPool.get(targetRPC)) { - pathItem.setPut(customRESTActionPutOperation(action, tag)); + String httpMethodName = customRESTAction.getHttpMethodName(); + switch (httpMethodName) { + case "POST": + pathItem.setPost(customRESTActionPostOperation(action, tag)); + break; + case "GET": + pathItem.setGet(customRESTActionGetOperation(action, tag)); + break; + case "DELETE": + pathItem.setDelete(customRESTActionDeleteOperation(action, tag)); + break; + case "PUT": + pathItem.setPut(customRESTActionPutOperation(action, tag)); + break; + case "PATCH": + pathItem.setPatch(customRESTActionPatchOperation(action, tag)); + break; + } } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/RESTEndpoint.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/RESTEndpoint.java index 10c8f01dbe..89ab3e0647 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/RESTEndpoint.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/RESTEndpoint.java @@ -96,16 +96,11 @@ private void process(HttpServletRequest request, HttpServletResponse response) { String procedureUri = null; if (requestPath.isCustomRestAction()) { - - if (!"PUT".equals(method)) { - resourceAPI.removeClient(); - OperationResult.methodNotAllowed().prepareResponse(response); return; - } String actionName = requestPath.getCustomRestActionName(); try { - procedureUri = resourceAPI.getProcedureUriByActionName(actionName); + procedureUri = resourceAPI.getProcedureUriByActionName(method, actionName); } catch (UnsupportedOperationException e) { - log.error(format("Custom REST action %s not implemented for resource %s", actionName, key), e); + log.error(format("Custom REST action %s not implemented for resource %s and method %s", actionName, key, method), e); OperationResult.methodNotAllowed().prepareResponse(response); return; } finally { diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/components/CustomRESTAction.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/components/CustomRESTAction.java index 755b093f63..88aa0c2edd 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/components/CustomRESTAction.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/components/CustomRESTAction.java @@ -6,6 +6,7 @@ public class CustomRESTAction implements Removable { private String name; private String targetProcedureUri; + private String httpMethodName = "PUT"; @Override public void dereference() { @@ -20,6 +21,11 @@ public String getName() { public void setName(String name) { this.name = name; } + + @Property(uri = "https://vivoweb.org/ontology/vitro-dynamic-api#hasDefaultMethod") + public void setHttpMethod(HTTPMethod httpMethod) { + this.httpMethodName = httpMethod.getName(); + } public String getTargetProcedureUri() { return targetProcedureUri; @@ -29,5 +35,9 @@ public String getTargetProcedureUri() { public void setTargetProcedureUri(String procedureUri) { this.targetProcedureUri = procedureUri; } + + public String getHttpMethodName() { + return httpMethodName; + } } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/components/ResourceAPI.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/components/ResourceAPI.java index f0c83983ac..2d08e86c61 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/components/ResourceAPI.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/dynapi/components/ResourceAPI.java @@ -150,18 +150,18 @@ private String getProcedureUriByMethod(String method, boolean isResourceRequest) } } - public String getProcedureUriByActionName(String name) { - String uri = getProcedureUriByCustomActionName(name); + public String getProcedureUriByActionName(String method, String actionName) { + String uri = getProcedureUriByCustomActionName(method, actionName); if (uri != null) { return uri; } throw new UnsupportedOperationException("Unsupported custom action"); } - private String getProcedureUriByCustomActionName(String name) { + private String getProcedureUriByCustomActionName(String method, String name) { String uri = null; for (CustomRESTAction customRestAction : customRESTActions) { - if (customRestAction.getName().equals(name)) { + if (customRestAction.getName().equals(name) && method.equals(customRestAction.getHttpMethodName())) { uri = customRestAction.getTargetProcedureUri(); break; } diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dynapi/LoggingControl.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dynapi/LoggingControl.java index 31b0803e5b..3a8102e82c 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dynapi/LoggingControl.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dynapi/LoggingControl.java @@ -50,6 +50,7 @@ private void restoreLogging(Class clazz) { } public static void offLogs() { + offLog(RESTEndpoint.class); offLog(ResourceAPIPool.class); offLog(RPCPool.class); offLog(ProcedurePool.class); @@ -57,6 +58,7 @@ public static void offLogs() { } public static void restoreLogs() { + restoreLog(RESTEndpoint.class); restoreLog(ResourceAPIPool.class); restoreLog(RPCPool.class); restoreLog(ProcedurePool.class); diff --git a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dynapi/RESTEndpointTest.java b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dynapi/RESTEndpointTest.java index 9098f91be1..fbd9ff3f6f 100644 --- a/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dynapi/RESTEndpointTest.java +++ b/api/src/test/java/edu/cornell/mannlib/vitro/webapp/dynapi/RESTEndpointTest.java @@ -167,13 +167,13 @@ public void doTest() throws IOException { String procedureUri = "resource_uri"; when(resourceAPI.getProcedureUri(testMethod, false)).thenReturn(procedureUri); - when(resourceAPI.getProcedureUriByActionName(testActionName)).thenReturn(procedureUri); + when(resourceAPI.getProcedureUriByActionName(testMethod, testActionName)).thenReturn(procedureUri); doNothing().when(resourceAPI).removeClient(); run(testMethod); verify(resourceAPI, times(testExpectedCounts[0])).getProcedureUri(any(), anyBoolean()); - verify(resourceAPI, times(testExpectedCounts[1])).getProcedureUriByActionName(any()); + verify(resourceAPI, times(testExpectedCounts[1])).getProcedureUriByActionName(testMethod, testActionName); verify(resourceAPI, times(testExpectedCounts[2])).removeClient(); verify(procedure, times(testExpectedCounts[3])).run(any()); verify(procedure, times(testExpectedCounts[4])).removeClient(); @@ -218,8 +218,8 @@ public static Collection requests() { { "PATCH", PATH_INFO, actionName, new int[] { 0, 0, 0, 0, 0, 1 }, SC_METHOD_NOT_ALLOWED, "Cannot patch on resource collection" }, { "DELETE", PATH_INFO, actionName, new int[] { 0, 0, 0, 0, 0, 1 }, SC_METHOD_NOT_ALLOWED, "Cannot delete on resource collection" }, - { "POST", customRestActionPathInfo, actionName, new int[] { 0, 0, 1, 0, 0, 1 }, SC_METHOD_NOT_ALLOWED, "Resource found with supported method" }, - { "GET", customRestActionPathInfo, actionName, new int[] { 0, 0, 1, 0, 0, 1 }, SC_METHOD_NOT_ALLOWED, "Resource found with unsupported method" }, + { "POST", customRestActionPathInfo, actionName, new int[] { 0, 1, 1, 1, 1, 1 }, SC_METHOD_NOT_ALLOWED, "Resource found with supported method" }, + { "GET", customRestActionPathInfo, actionName, new int[] { 0, 1, 1, 1, 1, 1 }, SC_METHOD_NOT_ALLOWED, "Resource found with supported method" }, { "PUT", customRestActionPathInfo, actionName, new int[] { 0, 0, 0, 0, 0, 1 }, SC_METHOD_NOT_ALLOWED, "Method unsupported by custom REST action" }, { "PATCH", customRestActionPathInfo, actionName, new int[] { 0, 0, 0, 0, 0, 1 }, SC_METHOD_NOT_ALLOWED, "Method unsupported by custom REST action" }, { "DELETE", customRestActionPathInfo, actionName, new int[] { 0, 0, 0, 0, 0, 1 }, SC_METHOD_NOT_ALLOWED, "Method unsupported by custom REST action" }