This is an automated email from the ASF dual-hosted git repository.

csantanapr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk.git


The following commit(s) were added to refs/heads/master by this push:
     new cfd34c0  Pretty print webaction JSON response. (#2643)
cfd34c0 is described below

commit cfd34c084bcd995876a3672ee715b7c814459cd4
Author: rodric rabbah <rod...@gmail.com>
AuthorDate: Wed Aug 30 23:16:52 2017 -0400

    Pretty print webaction JSON response. (#2643)
    
    * Pretty print webaction JSON response.
    
    Add pretty/compact printers in singleton common to controller, and use it 
for error responses, API response and webactions.
    
    * Tidy up a match.
    
    * Remove extra space.
---
 .../main/scala/whisk/core/entity/WhiskAction.scala |  7 +++---
 .../src/main/scala/whisk/http/ErrorResponse.scala  |  6 +++--
 .../main/scala/whisk/core/controller/Actions.scala |  4 ++++
 .../scala/whisk/core/controller/Activations.scala  |  3 +++
 .../scala/whisk/core/controller/ApiUtils.scala     |  6 +++++
 .../controller/AuthorizedRouteDispatcher.scala     |  4 ++++
 .../scala/whisk/core/controller/Entities.scala     | 19 +++++++--------
 .../scala/whisk/core/controller/Namespaces.scala   |  3 +++
 .../scala/whisk/core/controller/Packages.scala     |  3 +++
 .../scala/whisk/core/controller/RestAPIs.scala     | 11 +++++++--
 .../main/scala/whisk/core/controller/Rules.scala   |  3 +++
 .../scala/whisk/core/controller/Triggers.scala     |  3 +++
 .../scala/whisk/core/controller/WebActions.scala   | 17 +++++++-------
 .../scala/whisk/core/invoker/InvokerReactive.scala |  2 +-
 .../core/controller/test/WebActionsApiTests.scala  | 27 ++++++++--------------
 15 files changed, 74 insertions(+), 44 deletions(-)

diff --git a/common/scala/src/main/scala/whisk/core/entity/WhiskAction.scala 
b/common/scala/src/main/scala/whisk/core/entity/WhiskAction.scala
index 0e01369..c4e90f4 100644
--- a/common/scala/src/main/scala/whisk/core/entity/WhiskAction.scala
+++ b/common/scala/src/main/scala/whisk/core/entity/WhiskAction.scala
@@ -256,16 +256,15 @@ object WhiskAction
 
         implicit val ec = db.executionContext
 
-        val fa = super.get(db, doc, rev, fromCache = fromCache)
+        val fa = super.get(db, doc, rev, fromCache)
 
         fa.flatMap { action =>
             action.exec match {
-                case exec @ CodeExecAsAttachment(_, Attached(_, _), _) =>
+                case exec @ CodeExecAsAttachment(_, Attached(attachmentName, 
_), _) =>
                     val boas = new ByteArrayOutputStream()
                     val b64s = Base64.getEncoder().wrap(boas)
-                    val manifest = exec.manifest.attached.get
 
-                    getAttachment[A](db, action.docinfo, 
manifest.attachmentName, b64s).map { _ =>
+                    getAttachment[A](db, action.docinfo, attachmentName, 
b64s).map { _ =>
                         b64s.close()
                         val newAction = action.copy(exec = 
exec.inline(boas.toByteArray))
                         newAction.revision(action.rev)
diff --git a/common/scala/src/main/scala/whisk/http/ErrorResponse.scala 
b/common/scala/src/main/scala/whisk/http/ErrorResponse.scala
index 1687630..85f39b6 100644
--- a/common/scala/src/main/scala/whisk/http/ErrorResponse.scala
+++ b/common/scala/src/main/scala/whisk/http/ErrorResponse.scala
@@ -169,13 +169,15 @@ case class ErrorResponse(error: String, code: 
TransactionId)
 
 object ErrorResponse extends Directives with DefaultJsonProtocol {
 
-    def terminate(status: StatusCode, error: String)(implicit transid: 
TransactionId): StandardRoute = {
+    def terminate(status: StatusCode, error: String)(
+        implicit transid: TransactionId, jsonPrinter: JsonPrinter): 
StandardRoute = {
         terminate(status, Option(error) filter { _.trim.nonEmpty } map {
             e => Some(ErrorResponse(e.trim, transid))
         } getOrElse None)
     }
 
-    def terminate(status: StatusCode, error: Option[ErrorResponse] = None, 
asJson: Boolean = true)(implicit transid: TransactionId): StandardRoute = {
+    def terminate(status: StatusCode, error: Option[ErrorResponse] = None, 
asJson: Boolean = true)(
+        implicit transid: TransactionId, jsonPrinter: JsonPrinter): 
StandardRoute = {
         val errorResponse = error getOrElse response(status)
         if (asJson) {
             complete(status, errorResponse)
diff --git a/core/controller/src/main/scala/whisk/core/controller/Actions.scala 
b/core/controller/src/main/scala/whisk/core/controller/Actions.scala
index fc042a7..ba74de8 100644
--- a/core/controller/src/main/scala/whisk/core/controller/Actions.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/Actions.scala
@@ -87,8 +87,12 @@ trait WhiskActionsApi
     /** Database service to get activations. */
     protected val activationStore: ActivationStore
 
+    /** Entity normalizer to JSON object. */
     import RestApiCommons.emptyEntityToJsObject
 
+    /** JSON response formatter. */
+    import RestApiCommons.jsonDefaultResponsePrinter
+
     /**
      * Handles operations on action resources, which encompass these cases:
      *
diff --git 
a/core/controller/src/main/scala/whisk/core/controller/Activations.scala 
b/core/controller/src/main/scala/whisk/core/controller/Activations.scala
index f45accf..8c162ae 100644
--- a/core/controller/src/main/scala/whisk/core/controller/Activations.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/Activations.scala
@@ -55,6 +55,9 @@ trait WhiskActivationsApi
 
     protected override val collection = Collection(Collection.ACTIVATIONS)
 
+    /** JSON response formatter. */
+    import RestApiCommons.jsonDefaultResponsePrinter
+
     /** Database service to GET activations. */
     protected val activationStore: ActivationStore
 
diff --git 
a/core/controller/src/main/scala/whisk/core/controller/ApiUtils.scala 
b/core/controller/src/main/scala/whisk/core/controller/ApiUtils.scala
index 54f424c..a52bd24 100644
--- a/core/controller/src/main/scala/whisk/core/controller/ApiUtils.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/ApiUtils.scala
@@ -118,6 +118,9 @@ trait ReadOps extends Directives {
 
     protected implicit val logging: Logging
 
+    /** JSON response formatter. */
+    import RestApiCommons.jsonDefaultResponsePrinter
+
     /**
      * Get all entities of type A from datastore that match key. Terminates 
HTTP request.
      *
@@ -232,6 +235,9 @@ trait WriteOps extends Directives {
 
     protected implicit val logging: Logging
 
+    /** JSON response formatter. */
+    import RestApiCommons.jsonDefaultResponsePrinter
+
     /**
      * A predicate future that completes with true iff the entity should be
      * stored in the datastore. Future should fail otherwise with RejectPut.
diff --git 
a/core/controller/src/main/scala/whisk/core/controller/AuthorizedRouteDispatcher.scala
 
b/core/controller/src/main/scala/whisk/core/controller/AuthorizedRouteDispatcher.scala
index d82f9e3..7812a37 100644
--- 
a/core/controller/src/main/scala/whisk/core/controller/AuthorizedRouteDispatcher.scala
+++ 
b/core/controller/src/main/scala/whisk/core/controller/AuthorizedRouteDispatcher.scala
@@ -43,6 +43,7 @@ import whisk.http.Messages
 
 /** A trait for routes that require entitlement checks. */
 trait BasicAuthorizedRouteProvider extends Directives {
+
     /** An execution context for futures */
     protected implicit val executionContext: ExecutionContext
 
@@ -61,6 +62,9 @@ trait BasicAuthorizedRouteProvider extends Directives {
     /** Route directives for API. The methods that are supported on entities. 
*/
     protected lazy val entityOps = get
 
+    /** JSON response formatter. */
+    import RestApiCommons.jsonDefaultResponsePrinter
+
     /** Checks entitlement and dispatches to handler if authorized. */
     protected def authorizeAndDispatch(
         method: HttpMethod,
diff --git 
a/core/controller/src/main/scala/whisk/core/controller/Entities.scala 
b/core/controller/src/main/scala/whisk/core/controller/Entities.scala
index ebafac5..fbf75b3 100644
--- a/core/controller/src/main/scala/whisk/core/controller/Entities.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/Entities.scala
@@ -17,18 +17,18 @@
 
 package whisk.core.controller
 
+import scala.concurrent.Future
 import scala.language.postfixOps
 import scala.util.Try
-import scala.concurrent.Future
 
-import akka.http.scaladsl.model.StatusCodes.RequestEntityTooLarge
 import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
+import akka.http.scaladsl.model.StatusCodes.RequestEntityTooLarge
 import akka.http.scaladsl.server.Directive0
 import akka.http.scaladsl.server.Directives
 import akka.http.scaladsl.server.RequestContext
-import akka.http.scaladsl.server.RouteResult
 import akka.http.scaladsl.server.Route
-
+import akka.http.scaladsl.server.RouteResult
+import spray.json.JsonPrinter
 import whisk.common.TransactionId
 import whisk.core.entitlement.Privilege._
 import whisk.core.entitlement.Privilege.Privilege
@@ -41,9 +41,10 @@ import whisk.http.ErrorResponse.terminate
 import whisk.http.Messages
 
 protected[controller] trait ValidateRequestSize extends Directives {
+
     protected def validateSize(check: => Option[SizeError])(
-        implicit tid: TransactionId) = new Directive0 {
-        def tapply(f: Unit => Route) = {
+        implicit tid: TransactionId, jsonPrinter: JsonPrinter) = new 
Directive0 {
+        override def tapply(f: Unit => Route) = {
             check map {
                 case e: SizeError => terminate(RequestEntityTooLarge, 
Messages.entityTooBig(e))
             } getOrElse f(None)
@@ -100,13 +101,13 @@ trait WhiskCollectionAPI
                 case READ => fetch(user, 
FullyQualifiedEntityName(resource.namespace, name), resource.env)
                 case PUT =>
                     entity(as[LimitedWhiskEntityPut]) { e =>
-                        validateSize(e.isWithinSizeLimits)(transid) {
+                        validateSize(e.isWithinSizeLimits)(transid, 
RestApiCommons.jsonDefaultResponsePrinter) {
                             create(user, 
FullyQualifiedEntityName(resource.namespace, name))
                         }
                     }
                 case ACTIVATE =>
-                   extract(_.request.entity.contentLengthOption) { length =>
-                        
validateSize(isWhithinRange(length.getOrElse(0)))(transid) {
+                    extract(_.request.entity.contentLengthOption) { length =>
+                        
validateSize(isWhithinRange(length.getOrElse(0)))(transid, 
RestApiCommons.jsonDefaultResponsePrinter) {
                             activate(user, 
FullyQualifiedEntityName(resource.namespace, name), resource.env)
                         }
                     }
diff --git 
a/core/controller/src/main/scala/whisk/core/controller/Namespaces.scala 
b/core/controller/src/main/scala/whisk/core/controller/Namespaces.scala
index 86dbb8b..d14e3b7 100644
--- a/core/controller/src/main/scala/whisk/core/controller/Namespaces.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/Namespaces.scala
@@ -56,6 +56,9 @@ trait WhiskNamespacesApi
     /** Database service to lookup entities in a namespace. */
     protected val entityStore: EntityStore
 
+    /** JSON response formatter. */
+    import RestApiCommons.jsonDefaultResponsePrinter
+
     /**
      * Rest API for managing namespaces. Defines all the routes handled by 
this API. They are:
      *
diff --git 
a/core/controller/src/main/scala/whisk/core/controller/Packages.scala 
b/core/controller/src/main/scala/whisk/core/controller/Packages.scala
index ce6f4cf..925d5c1 100644
--- a/core/controller/src/main/scala/whisk/core/controller/Packages.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/Packages.scala
@@ -52,6 +52,9 @@ trait WhiskPackagesApi extends WhiskCollectionAPI with 
ReferencedEntities {
     /** Must exclude any private packages when listing those in a namespace 
unless owned by subject. */
     protected override val listRequiresPrivateEntityFilter = true
 
+    /** JSON response formatter. */
+    import RestApiCommons.jsonDefaultResponsePrinter
+
     /**
      * Creates or updates package/binding if it already exists. The PUT 
content is deserialized into a
      * WhiskPackagePut which is a subset of WhiskPackage (it eschews the 
namespace and entity name since
diff --git 
a/core/controller/src/main/scala/whisk/core/controller/RestAPIs.scala 
b/core/controller/src/main/scala/whisk/core/controller/RestAPIs.scala
index 57b03ea..0e374f6 100644
--- a/core/controller/src/main/scala/whisk/core/controller/RestAPIs.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/RestAPIs.scala
@@ -24,6 +24,7 @@ import akka.http.scaladsl.model.Uri
 import akka.http.scaladsl.server.Directives
 import akka.http.scaladsl.server.Route
 import akka.http.scaladsl.model.headers._
+import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
 
 import spray.json._
 import spray.json.DefaultJsonProtocol._
@@ -112,6 +113,12 @@ protected[controller] object RestApiCommons {
             }
         }
     }
+
+    /** Pretty print JSON response. */
+    implicit val jsonPrettyResponsePrinter = PrettyPrinter
+
+    /** Standard compact JSON printer. */
+    implicit val jsonDefaultResponsePrinter = CompactPrinter
 }
 
 /**
@@ -148,7 +155,7 @@ class RestAPIVersion(config: WhiskConfig, apiPath: String, 
apiVersion: String)(
      * Describes details of a particular API path.
      */
     val info = (pathEndOrSingleSlash & get) {
-        complete(OK, JsObject(
+        complete(JsObject(
             "description" -> "OpenWhisk API".toJson,
             "api_version" -> SemVer(1, 0, 0).toJson,
             "api_version_path" -> apiVersion.toJson,
@@ -156,7 +163,7 @@ class RestAPIVersion(config: WhiskConfig, apiPath: String, 
apiVersion: String)(
             "buildno" -> whiskConfig(whiskVersionBuildno).toJson,
             "swagger_paths" -> JsObject(
                 "ui" -> s"/$swaggeruipath".toJson,
-                "api-docs" -> s"/$swaggerdocpath".toJson)).toString)
+                "api-docs" -> s"/$swaggerdocpath".toJson)))
     }
 
     def routes(implicit transid: TransactionId): Route = {
diff --git a/core/controller/src/main/scala/whisk/core/controller/Rules.scala 
b/core/controller/src/main/scala/whisk/core/controller/Rules.scala
index be0e6eb..e65c845 100644
--- a/core/controller/src/main/scala/whisk/core/controller/Rules.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/Rules.scala
@@ -51,6 +51,9 @@ trait WhiskRulesApi extends WhiskCollectionAPI with 
ReferencedEntities {
     /** Database service to CRUD rules. */
     protected val entityStore: EntityStore
 
+    /** JSON response formatter. */
+    import RestApiCommons.jsonDefaultResponsePrinter
+
     /** Path to Rules REST API. */
     protected val rulesPath = "rules"
 
diff --git 
a/core/controller/src/main/scala/whisk/core/controller/Triggers.scala 
b/core/controller/src/main/scala/whisk/core/controller/Triggers.scala
index fe5304f..d77d981 100644
--- a/core/controller/src/main/scala/whisk/core/controller/Triggers.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/Triggers.scala
@@ -76,6 +76,9 @@ trait WhiskTriggersApi extends WhiskCollectionAPI {
     /** Database service to get activations. */
     protected val activationStore: ActivationStore
 
+    /** JSON response formatter. */
+    import RestApiCommons.jsonDefaultResponsePrinter
+
     /** Path to Triggers REST API. */
     protected val triggersPath = "triggers"
 
diff --git 
a/core/controller/src/main/scala/whisk/core/controller/WebActions.scala 
b/core/controller/src/main/scala/whisk/core/controller/WebActions.scala
index e527e8b..a009ed2 100644
--- a/core/controller/src/main/scala/whisk/core/controller/WebActions.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/WebActions.scala
@@ -49,6 +49,7 @@ import spray.json._
 import spray.json.DefaultJsonProtocol._
 
 import WhiskWebActionsApi.MediaExtension
+import RestApiCommons.{ jsonPrettyResponsePrinter => jsonPrettyPrinter }
 
 import whisk.common.TransactionId
 import whisk.core.controller.actions.PostActionActivation
@@ -178,12 +179,12 @@ protected[core] object WhiskWebActionsApi extends 
Directives {
 
     private def resultAsHtml(result: JsValue, transid: TransactionId, rp: 
WebApiDirectives) = result match {
         case JsString(html) => 
complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, html))
-        case _              => terminate(BadRequest, 
Messages.invalidMedia(`text/html`))(transid)
+        case _              => terminate(BadRequest, 
Messages.invalidMedia(`text/html`))(transid, jsonPrettyPrinter)
     }
 
     private def resultAsSvg(result: JsValue, transid: TransactionId, rp: 
WebApiDirectives) = result match {
         case JsString(svg) => complete(HttpEntity(`image/svg+xml`, 
svg.getBytes))
-        case _             => terminate(BadRequest, 
Messages.invalidMedia(`image/svg+xml`))(transid)
+        case _             => terminate(BadRequest, 
Messages.invalidMedia(`image/svg+xml`))(transid, jsonPrettyPrinter)
     }
 
     private def resultAsText(result: JsValue, transid: TransactionId, rp: 
WebApiDirectives) = {
@@ -201,7 +202,7 @@ protected[core] object WhiskWebActionsApi extends 
Directives {
         result match {
             case r: JsObject => complete(OK, r)
             case r: JsArray  => complete(OK, r)
-            case _           => terminate(BadRequest, 
Messages.invalidMedia(`application/json`))(transid)
+            case _           => terminate(BadRequest, 
Messages.invalidMedia(`application/json`))(transid, jsonPrettyPrinter)
         }
     }
 
@@ -238,7 +239,7 @@ protected[core] object WhiskWebActionsApi extends 
Directives {
         } getOrElse {
             // either the result was not a JsObject or there was an exception 
validting the
             // response as an http result
-            terminate(BadRequest, 
Messages.invalidMedia(`message/http`))(transid)
+            terminate(BadRequest, 
Messages.invalidMedia(`message/http`))(transid, jsonPrettyPrinter)
         }
     }
 
@@ -278,7 +279,7 @@ protected[core] object WhiskWebActionsApi extends 
Directives {
                 }
 
             case _ =>
-                terminate(BadRequest, Messages.httpContentTypeError)(transid)
+                terminate(BadRequest, Messages.httpContentTypeError)(transid, 
jsonPrettyPrinter)
         }
     }
 
@@ -297,10 +298,10 @@ protected[core] object WhiskWebActionsApi extends 
Directives {
                 }
 
             case Failure(RejectRequest(code, message)) =>
-                terminate(code, message)(transid)
+                terminate(code, message)(transid, jsonPrettyPrinter)
 
             case _ =>
-                terminate(BadRequest, Messages.httpContentTypeError)(transid)
+                terminate(BadRequest, Messages.httpContentTypeError)(transid, 
jsonPrettyPrinter)
         }
     }
 
@@ -426,7 +427,7 @@ trait WhiskWebActionsApi
                 // as the context body which may be the incoming request when 
the content type is JSON or formdata, or
                 // the raw body as __ow_body (and query parameters as 
__ow_query) otherwise
                 extract(_.request.entity) { e =>
-                    
validateSize(isWhithinRange(e.contentLengthOption.getOrElse(0)))(transid) {
+                    
validateSize(isWhithinRange(e.contentLengthOption.getOrElse(0)))(transid, 
jsonPrettyPrinter) {
                         requestMethodParamsAndPath { context =>
                             provide(fullyQualifiedActionName(actionName)) { 
fullActionName =>
                                 onComplete(verifyWebAction(fullActionName, 
onBehalfOf.isDefined)) {
diff --git 
a/core/invoker/src/main/scala/whisk/core/invoker/InvokerReactive.scala 
b/core/invoker/src/main/scala/whisk/core/invoker/InvokerReactive.scala
index 1f0d760..1f64625 100644
--- a/core/invoker/src/main/scala/whisk/core/invoker/InvokerReactive.scala
+++ b/core/invoker/src/main/scala/whisk/core/invoker/InvokerReactive.scala
@@ -126,7 +126,7 @@ class InvokerReactive(config: WhiskConfig, instance: 
InstanceId, producer: Messa
             val msg = CompletionMessage(transid, res, instance)
             producer.send(s"completed${controllerInstance.toInt}", 
msg).andThen {
                 case Success(_) =>
-                    logging.info(this, s"posted ${if (recovery) "recovery" 
else ""} completion of activation ${activationResult.activationId}")
+                    logging.info(this, s"posted ${if (recovery) "recovery" 
else "completion"} of activation ${activationResult.activationId}")
             }
         }
 
diff --git 
a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala 
b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
index 446d881..fac5076 100644
--- a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
@@ -342,24 +342,6 @@ trait WebActionsApiTests extends ControllerTestCommon with 
BeforeAndAfterEach wi
                 }
         }
 
-        /*
-         * All of the verbs supported by Spray have been added to Web Actions, 
so comment this test out
-         * as it is no longer valid.
-         *
-         it should s"reject unsupported http verbs (auth? ${creds.isDefined})" 
in {
-            implicit val tid = transid()
-
-            Seq((???, MethodNotAllowed)).
-                foreach {
-                    case (m, code) =>
-                        m(s"$testRoutePath/$systemId/proxy/export_c.json") ~> 
Route.seal(routes(creds)) ~> check {
-                            status should be(code)
-                        }
-                }
-         }
-         *
-         */
-
         it should s"reject requests when identity, package or action lookup 
fail or missing annotation (auth? ${creds.isDefined})" in {
             implicit val tid = transid()
 
@@ -602,6 +584,8 @@ trait WebActionsApiTests extends ControllerTestCommon with 
BeforeAndAfterEach wi
                         m(s"$testRoutePath/$path") ~> 
Route.seal(routes(creds)) ~> check {
                             status should be(NotFound)
                             confirmErrorWithTid(responseAs[JsObject], 
Some(Messages.propertyNotFound))
+                            // ensure that error message is pretty printed as 
{ error, code }
+                            responseAs[String].lines should have size 4
                         }
                     }
                 }
@@ -667,6 +651,13 @@ trait WebActionsApiTests extends ControllerTestCommon with 
BeforeAndAfterEach wi
                             status should be(OK)
                             val response = responseAs[JsObject]
                             response shouldBe actionResult.get
+
+                            // ensure response is pretty printed
+                            responseAs[String] shouldBe {
+                                """{
+                                  |  "foobar": "foobar"
+                                  |}""".stripMargin
+                            }
                         }
                     }
                 }

-- 
To stop receiving notification emails like this one, please contact
['"commits@openwhisk.apache.org" <commits@openwhisk.apache.org>'].

Reply via email to