REST API changes for client side errors
For the Intent REST APIs, made the following changes:
- GET requests without a specific resource identifier
return a collection and the response status of OK
- GET requests for a specific resource return the single
item found and a status of OK on success, and NOT FOUND
on failure. For a NOT FOUND, a RestError object is
returned indicating the error.
- POST requests return the objects they create and a status
of CREATED if they are successful. If they fail, a status
of BAD REQUEST is sent. For a BAD REQUEST, a RestError object is
returned indicating the error.
- DELETE requests always return the status NO CONTENT and return
no object.
- standardized method names for REST resource classes:
GET is retrieve()
DELETE is remove()
POST is store()
- removed superfluous checks for null inbound parameters
on GET operations.
Change-Id: I426ce73a96637dc67f30e1c85e9c200334ff758c
diff --git a/pom.xml b/pom.xml
index 629be48..472f644 100644
--- a/pom.xml
+++ b/pom.xml
@@ -522,6 +522,11 @@
</dependency>
<dependency>
<groupId>org.restlet.jse</groupId>
+ <artifactId>org.restlet.ext.json</artifactId>
+ <version>${restlet.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.restlet.jse</groupId>
<artifactId>org.restlet.ext.jackson</artifactId>
<version>${restlet.version}</version>
</dependency>
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighObjectResource.java b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighObjectResource.java
index c4e2ac4..dd6145d 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighObjectResource.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighObjectResource.java
@@ -1,15 +1,14 @@
package net.onrc.onos.core.intent.runtime.web;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.LinkedList;
-
+import net.onrc.onos.api.rest.RestError;
+import net.onrc.onos.api.rest.RestErrorCodes;
import net.onrc.onos.core.intent.Intent;
import net.onrc.onos.core.intent.IntentMap;
import net.onrc.onos.core.intent.IntentOperation;
import net.onrc.onos.core.intent.IntentOperationList;
import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
-
+import org.restlet.data.Status;
+import org.restlet.representation.Representation;
import org.restlet.resource.Delete;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;
@@ -27,14 +26,16 @@
/**
* Gets a single high-level intent.
*
- * @return a Collection with the single high-level intent if found,
- * otherwise null.
+ * @return a Representation of a single high-level intent. If the
+ * intent is not found, return a Representation of a RestError indicating
+ * the problem.
*/
@Get("json")
- public Collection<Intent> retrieve() throws IOException {
+ public Representation retrieve() {
IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
- Collection<Intent> intents = null;
+
+ Representation result;
String intentId = (String) getRequestAttributes().get("intent-id");
if (intentId == null) {
@@ -48,27 +49,29 @@
String applnIntentId = APPLN_ID + ":" + intentId;
Intent intent = intentMap.getIntent(applnIntentId);
if (intent != null) {
- intents = new LinkedList<>();
- intents.add(intent);
+ result = toRepresentation(intent, null);
+ } else {
+ setStatus(Status.CLIENT_ERROR_NOT_FOUND);
+ final RestError notFound =
+ RestError.createRestError(RestErrorCodes.RestErrorCode.INTENT_NOT_FOUND,
+ applnIntentId);
+ result = toRepresentation(notFound, null);
}
- return intents;
+ return result;
}
/**
* Deletes a single high-level intent.
*
- * @return the status of the operation (TBD).
+ * @return a null Representation.
*/
@Delete("json")
- public String store() {
+ public Representation remove() {
IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
String intentId = (String) getRequestAttributes().get("intent-id");
- if (intentId == null) {
- return null; // Missing Intent ID
- }
//
// Remove a single high-level Intent: use the Intent ID to find it
@@ -84,6 +87,7 @@
operations.add(IntentOperation.Operator.REMOVE, intent);
pathRuntime.executeIntentOperations(operations);
}
- return ""; // TODO no reply yet from the purge intents call
+ setStatus(Status.SUCCESS_NO_CONTENT);
+ return null;
}
}
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighResource.java b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighResource.java
index 8229e38..d2ffdce 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighResource.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentHighResource.java
@@ -1,8 +1,5 @@
package net.onrc.onos.core.intent.runtime.web;
-import java.io.IOException;
-import java.util.Collection;
-
import net.floodlightcontroller.util.MACAddress;
import net.onrc.onos.api.intent.ApplicationIntent;
import net.onrc.onos.api.rest.RestError;
@@ -15,9 +12,9 @@
import net.onrc.onos.core.intent.ShortestPathIntent;
import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
import net.onrc.onos.core.util.Dpid;
-
import org.codehaus.jackson.map.ObjectMapper;
import org.restlet.data.Status;
+import org.restlet.representation.Representation;
import org.restlet.resource.Delete;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
@@ -25,6 +22,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.IOException;
+import java.util.Collection;
+
/**
* A class to access the high-level intents.
*/
@@ -36,34 +36,35 @@
/**
* Gets all high-level intents.
*
- * @return a collection with all high-level intents.
+ * @return a Representation for a collection with all of the high-level intents.
*/
@Get("json")
- public Collection<Intent> retrieve() throws IOException {
+ public Representation retrieve() throws IOException {
IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
IntentMap intentMap = pathRuntime.getHighLevelIntents();
Collection<Intent> intents = intentMap.getAllIntents();
- return intents;
+ return toRepresentation(intents, null);
}
/**
* Adds a collection of high-level intents.
*
- * @return the status of the operation (TBD).
+ * @param jsonIntent JSON representation of the intents to add.
+ * @return a Representation of a collection containing the intents that were
+ * created.
*/
@Post("json")
- public String store(String jsonIntent) throws IOException {
+ public Representation store(String jsonIntent) {
IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext()
.getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
if (pathRuntime == null) {
log.warn("Failed to get path calc runtime");
- return "";
+ return null;
}
- String reply = "";
ObjectMapper mapper = new ObjectMapper();
ApplicationIntent[] addOperations = null;
try {
@@ -78,7 +79,7 @@
setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
final RestError error =
RestError.createRestError(RestErrorCodes.RestErrorCode.INTENT_INVALID);
- return mapper.writeValueAsString(error);
+ return toRepresentation(error, null);
}
//
@@ -132,16 +133,16 @@
setStatus(Status.SUCCESS_CREATED);
- return reply;
+ return toRepresentation(intentOperations, null);
}
/**
* Deletes all high-level intents.
*
- * @return the status of the operation (TBD).
+ * @return a null Representation.
*/
@Delete("json")
- public String store() {
+ public Representation remove() {
IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
@@ -150,6 +151,6 @@
// TODO: The deletion should use synchronous Java API?
pathRuntime.purgeIntents();
setStatus(Status.SUCCESS_NO_CONTENT);
- return ""; // TODO no reply yet from the purge intents call
+ return null; // TODO no reply yet from the purge intents call
}
}
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowObjectResource.java b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowObjectResource.java
index 4f5cc8a..1f99152 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowObjectResource.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowObjectResource.java
@@ -1,13 +1,12 @@
package net.onrc.onos.core.intent.runtime.web;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.LinkedList;
-
+import net.onrc.onos.api.rest.RestError;
+import net.onrc.onos.api.rest.RestErrorCodes;
import net.onrc.onos.core.intent.Intent;
import net.onrc.onos.core.intent.IntentMap;
import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
-
+import org.restlet.data.Status;
+import org.restlet.representation.Representation;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;
import org.slf4j.Logger;
@@ -24,19 +23,17 @@
/**
* Gets a single low-level intent.
*
- * @return a Collection with the single low-level intent if found,
- * otherwise null.
+ * @return a Representation of the single low-level intent if found,
+ * otherwise a Representation of a RestError object describing the problem.
*/
@Get("json")
- public Collection<Intent> retrieve() throws IOException {
+ public Representation retrieve() {
IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
- Collection<Intent> intents = null;
+
+ Representation result;
String intentId = (String) getRequestAttributes().get("intent-id");
- if (intentId == null) {
- return null; // Missing Intent ID
- }
//
// Get a single low-level Intent: use the Intent ID to find it
@@ -45,10 +42,15 @@
String applnIntentId = APPLN_ID + ":" + intentId;
Intent intent = intentMap.getIntent(applnIntentId);
if (intent != null) {
- intents = new LinkedList<>();
- intents.add(intent);
+ result = toRepresentation(intent, null);
+ } else {
+ setStatus(Status.CLIENT_ERROR_NOT_FOUND);
+ final RestError notFound =
+ RestError.createRestError(RestErrorCodes.RestErrorCode.INTENT_NOT_FOUND,
+ applnIntentId);
+ result = toRepresentation(notFound, null);
}
- return intents;
+ return result;
}
}
diff --git a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowResource.java b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowResource.java
index bf0b527..7a15c26 100644
--- a/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowResource.java
+++ b/src/main/java/net/onrc/onos/core/intent/runtime/web/IntentLowResource.java
@@ -1,17 +1,16 @@
package net.onrc.onos.core.intent.runtime.web;
-import java.io.IOException;
-import java.util.Collection;
-
import net.onrc.onos.core.intent.Intent;
import net.onrc.onos.core.intent.IntentMap;
import net.onrc.onos.core.intent.runtime.IPathCalcRuntimeService;
-
+import org.restlet.representation.Representation;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Collection;
+
/**
* A class to access the low-level intents.
*/
@@ -21,10 +20,10 @@
/**
* Gets all low-level intents.
*
- * @return a collection of all low-leve intents.
+ * @return a Representation of a collection of all of the low-level intents.
*/
@Get("json")
- public Collection<Intent> retrieve() throws IOException {
+ public Representation retrieve() {
IPathCalcRuntimeService pathRuntime = (IPathCalcRuntimeService) getContext().
getAttributes().get(IPathCalcRuntimeService.class.getCanonicalName());
@@ -34,6 +33,6 @@
IntentMap intentMap = pathRuntime.getPathIntents();
Collection<Intent> intents = intentMap.getAllIntents();
- return intents;
+ return toRepresentation(intents, null);
}
}