From ae05a69571688a2dea8c1846676e095843c3c75c Mon Sep 17 00:00:00 2001 From: Simon Date: Fri, 22 Sep 2023 13:18:38 +0200 Subject: [PATCH] Also allows post for the multi-fetch operation (#4290) * Allow post for the multi-fetch operation --------- Co-authored-by: Simon Dumas --- .../nexus/delta/routes/MultiFetchRoutes.scala | 2 +- .../delta/routes/ResourcesTrialRoutes.scala | 3 +-- .../delta/routes/MultiFetchRoutesSpec.scala | 26 ++++++++++++------- .../routes/ResourcesTrialRoutesSpec.scala | 14 +++++----- .../paradox/docs/delta/api/multi-fetch.md | 2 +- docs/src/main/paradox/docs/delta/api/trial.md | 2 +- .../nexus/tests/kg/MultiFetchSpec.scala | 17 +++++++----- .../tests/resources/ResourcesTrialSpec.scala | 16 ++++++------ 8 files changed, 47 insertions(+), 35 deletions(-) diff --git a/delta/app/src/main/scala/ch/epfl/bluebrain/nexus/delta/routes/MultiFetchRoutes.scala b/delta/app/src/main/scala/ch/epfl/bluebrain/nexus/delta/routes/MultiFetchRoutes.scala index 5672aa1049..02ddd6fd4f 100644 --- a/delta/app/src/main/scala/ch/epfl/bluebrain/nexus/delta/routes/MultiFetchRoutes.scala +++ b/delta/app/src/main/scala/ch/epfl/bluebrain/nexus/delta/routes/MultiFetchRoutes.scala @@ -38,7 +38,7 @@ class MultiFetchRoutes( pathPrefix("multi-fetch") { pathPrefix("resources") { extractCaller { implicit caller => - (get & entity(as[MultiFetchRequest])) { request => + ((get | post) & entity(as[MultiFetchRequest])) { request => implicit val printer: Printer = selectPrinter(request) emit(multiFetch(request).flatMap(_.asJson)) } diff --git a/delta/app/src/main/scala/ch/epfl/bluebrain/nexus/delta/routes/ResourcesTrialRoutes.scala b/delta/app/src/main/scala/ch/epfl/bluebrain/nexus/delta/routes/ResourcesTrialRoutes.scala index 0a1e688917..738c9d1a04 100644 --- a/delta/app/src/main/scala/ch/epfl/bluebrain/nexus/delta/routes/ResourcesTrialRoutes.scala +++ b/delta/app/src/main/scala/ch/epfl/bluebrain/nexus/delta/routes/ResourcesTrialRoutes.scala @@ -76,7 +76,7 @@ final class ResourcesTrialRoutes( } private def generateRoute: Route = - (get & pathPrefix("trial") & pathPrefix("resources")) { + (pathPrefix("trial") & pathPrefix("resources") & post) { extractCaller { implicit caller => (resolveProjectRef & pathEndOrSingleSlash) { project => authorizeFor(project, Write).apply { @@ -100,7 +100,6 @@ final class ResourcesTrialRoutes( } ) } - } object ResourcesTrialRoutes { diff --git a/delta/app/src/test/scala/ch/epfl/bluebrain/nexus/delta/routes/MultiFetchRoutesSpec.scala b/delta/app/src/test/scala/ch/epfl/bluebrain/nexus/delta/routes/MultiFetchRoutesSpec.scala index cfc91f6d9d..a7fe8b6d87 100644 --- a/delta/app/src/test/scala/ch/epfl/bluebrain/nexus/delta/routes/MultiFetchRoutesSpec.scala +++ b/delta/app/src/test/scala/ch/epfl/bluebrain/nexus/delta/routes/MultiFetchRoutesSpec.scala @@ -16,6 +16,7 @@ import ch.epfl.bluebrain.nexus.delta.sdk.utils.BaseRouteSpec import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.{Anonymous, Authenticated, Group} import ch.epfl.bluebrain.nexus.delta.sourcing.model.ProjectRef import ch.epfl.bluebrain.nexus.delta.sourcing.model.ResourceRef.Latest +import io.circe.Json import monix.bio.UIO class MultiFetchRoutesSpec extends BaseRouteSpec { @@ -73,33 +74,40 @@ class MultiFetchRoutesSpec extends BaseRouteSpec { ] }""" + def multiFetchQuery[T](payload: Json)(checks: => T) = + List(Get, Post).foreach { method => + method(endpoint, payload.toEntity) ~> asAlice ~> routes ~> check { checks } + } + "return unauthorised results for a user with no access" in { val entity = request(ResourceRepresentation.CompactedJsonLd).toEntity - Get(endpoint, entity) ~> routes ~> check { - status shouldEqual StatusCodes.OK - response.asJson shouldEqual jsonContentOf("multi-fetch/all-unauthorized.json") + List(Get, Post).foreach { method => + method(endpoint, entity) ~> routes ~> check { + status shouldEqual StatusCodes.OK + response.asJson shouldEqual jsonContentOf("multi-fetch/all-unauthorized.json") + } } } "return expected results as compacted json-ld for a user with limited access" in { - val entity = request(ResourceRepresentation.CompactedJsonLd).toEntity - Get(endpoint, entity) ~> asAlice ~> routes ~> check { + val payload = request(ResourceRepresentation.CompactedJsonLd) + multiFetchQuery(payload) { status shouldEqual StatusCodes.OK response.asJson shouldEqual jsonContentOf("multi-fetch/compacted-response.json") } } "return expected results as annotated source for a user with limited access" in { - val entity = request(ResourceRepresentation.AnnotatedSourceJson).toEntity - Get(endpoint, entity) ~> asAlice ~> routes ~> check { + val payload = request(ResourceRepresentation.AnnotatedSourceJson) + multiFetchQuery(payload) { status shouldEqual StatusCodes.OK response.asJson shouldEqual jsonContentOf("multi-fetch/annotated-source-response.json") } } "return expected results as original payloads for a user with limited access" in { - val entity = request(ResourceRepresentation.SourceJson).toEntity - Get(endpoint, entity) ~> asAlice ~> routes ~> check { + val payload = request(ResourceRepresentation.SourceJson) + multiFetchQuery(payload) { status shouldEqual StatusCodes.OK response.asJson shouldEqual jsonContentOf("multi-fetch/source-response.json") } diff --git a/delta/app/src/test/scala/ch/epfl/bluebrain/nexus/delta/routes/ResourcesTrialRoutesSpec.scala b/delta/app/src/test/scala/ch/epfl/bluebrain/nexus/delta/routes/ResourcesTrialRoutesSpec.scala index af1b8a7852..7661a1279f 100644 --- a/delta/app/src/test/scala/ch/epfl/bluebrain/nexus/delta/routes/ResourcesTrialRoutesSpec.scala +++ b/delta/app/src/test/scala/ch/epfl/bluebrain/nexus/delta/routes/ResourcesTrialRoutesSpec.scala @@ -129,7 +129,7 @@ class ResourcesTrialRoutesSpec extends BaseRouteSpec with ResourceInstanceFixtur "fail to generate a resource for a user without access" in { val payload = json"""{ "resource": $validSource }""" - Get(s"/v1/trial/resources/$projectRef/", payload.toEntity) ~> routes ~> check { + Post(s"/v1/trial/resources/$projectRef/", payload.toEntity) ~> routes ~> check { response.status shouldEqual StatusCodes.Forbidden response.asJson shouldEqual jsonContentOf("errors/authorization-failed.json") } @@ -137,7 +137,7 @@ class ResourcesTrialRoutesSpec extends BaseRouteSpec with ResourceInstanceFixtur "generate a resource without passing a schema" in { val payload = json"""{ "resource": $validSource }""" - Get(s"/v1/trial/resources/$projectRef/", payload.toEntity) ~> asAlice ~> routes ~> check { + Post(s"/v1/trial/resources/$projectRef/", payload.toEntity) ~> asAlice ~> routes ~> check { response.status shouldEqual StatusCodes.OK val jsonResponse = response.asJsonObject jsonResponse("schema") shouldBe empty @@ -146,9 +146,9 @@ class ResourcesTrialRoutesSpec extends BaseRouteSpec with ResourceInstanceFixtur } } - "generate a resource passing a new schema" in { + "generate a resource passing a new schema and using post" in { val payload = json"""{ "schema": $schemaSource, "resource": $validSource }""" - Get(s"/v1/trial/resources/$projectRef/", payload.toEntity) ~> asAlice ~> routes ~> check { + Post(s"/v1/trial/resources/$projectRef/", payload.toEntity) ~> asAlice ~> routes ~> check { response.status shouldEqual StatusCodes.OK val jsonResponse = response.asJsonObject jsonResponse("schema") should not be empty @@ -159,7 +159,7 @@ class ResourcesTrialRoutesSpec extends BaseRouteSpec with ResourceInstanceFixtur "fails to generate a resource when passing an invalid new schema" in { val payload = json"""{ "schema": { "invalid": "xxx" }, "resource": $validSource }""" - Get(s"/v1/trial/resources/$projectRef/", payload.toEntity) ~> asAlice ~> routes ~> check { + Post(s"/v1/trial/resources/$projectRef/", payload.toEntity) ~> asAlice ~> routes ~> check { response.status shouldEqual StatusCodes.BadRequest response.asJson shouldEqual json"""{ @@ -174,7 +174,7 @@ class ResourcesTrialRoutesSpec extends BaseRouteSpec with ResourceInstanceFixtur "fails to generate a resource when the resource payload is invalid and without passing a schema" in { val payload = json"""{ "resource": $invalidSource }""" - Get(s"/v1/trial/resources/$projectRef/", payload.toEntity) ~> asAlice ~> routes ~> check { + Post(s"/v1/trial/resources/$projectRef/", payload.toEntity) ~> asAlice ~> routes ~> check { response.status shouldEqual StatusCodes.OK response.asJson shouldEqual json""" @@ -190,7 +190,7 @@ class ResourcesTrialRoutesSpec extends BaseRouteSpec with ResourceInstanceFixtur "fail to generate a resource passing a new schema" in { val payload = json"""{ "schema": $schemaSource, "resource": $invalidSource }""" - Get(s"/v1/trial/resources/$projectRef/", payload.toEntity) ~> asAlice ~> routes ~> check { + Post(s"/v1/trial/resources/$projectRef/", payload.toEntity) ~> asAlice ~> routes ~> check { response.status shouldEqual StatusCodes.OK val jsonResponse = response.asJsonObject jsonResponse("schema") should not be empty diff --git a/docs/src/main/paradox/docs/delta/api/multi-fetch.md b/docs/src/main/paradox/docs/delta/api/multi-fetch.md index f6d9530fb8..66dfbc2ede 100644 --- a/docs/src/main/paradox/docs/delta/api/multi-fetch.md +++ b/docs/src/main/paradox/docs/delta/api/multi-fetch.md @@ -19,7 +19,7 @@ Please visit @ref:[Authentication & authorization](authentication.md) section to ## Payload ``` -GET /v1/multi-fetch/resources +GET|POST /v1/multi-fetch/resources { "format": {format} diff --git a/docs/src/main/paradox/docs/delta/api/trial.md b/docs/src/main/paradox/docs/delta/api/trial.md index 80131023a5..ec7330c201 100644 --- a/docs/src/main/paradox/docs/delta/api/trial.md +++ b/docs/src/main/paradox/docs/delta/api/trial.md @@ -19,7 +19,7 @@ It applies the same validation steps than the creation/update of resources, the that nothing is persisted. ``` -GET /v1/trial/resources/{org_label}/{project_label} +POST /v1/trial/resources/{org_label}/{project_label} { "schema": {schema}, diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/MultiFetchSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/MultiFetchSpec.scala index 4a1bc8fc82..ea23be932c 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/MultiFetchSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/MultiFetchSpec.scala @@ -1,12 +1,13 @@ package ch.epfl.bluebrain.nexus.tests.kg -import akka.http.scaladsl.model.{ContentTypes, StatusCodes} -import ch.epfl.bluebrain.nexus.tests.BaseSpec +import akka.http.scaladsl.model.{ContentTypes, HttpResponse, StatusCodes} +import ch.epfl.bluebrain.nexus.tests.{BaseSpec, Identity} import ch.epfl.bluebrain.nexus.tests.Identity.listings.{Alice, Bob} import ch.epfl.bluebrain.nexus.tests.Optics._ import ch.epfl.bluebrain.nexus.tests.iam.types.Permission.Resources import ch.epfl.bluebrain.nexus.tests.resources.SimpleResource import io.circe.Json +import org.scalatest.Assertion class MultiFetchSpec extends BaseSpec { @@ -57,6 +58,11 @@ class MultiFetchSpec extends BaseSpec { ] }""" + def multiFetchRequest(payload: Json, identity: Identity)(check: (Json, HttpResponse) => Assertion) = { + deltaClient.getWithBody[Json]("/multi-fetch/resources", payload, identity) { check } + deltaClient.post[Json]("/multi-fetch/resources", payload, identity) { check } + } + "get all resources for a user with all access" in { val expected = jsonContentOf( "/kg/multi-fetch/all-success.json", @@ -64,7 +70,7 @@ class MultiFetchSpec extends BaseSpec { "project2" -> ref12 ) - deltaClient.getWithBody[Json]("/multi-fetch/resources", request("source"), Bob) { (json, response) => + multiFetchRequest(request("source"), Bob) { (json, response) => response.status shouldEqual StatusCodes.OK filterNestedKeys("_uuid")(json) shouldEqual expected } @@ -77,7 +83,7 @@ class MultiFetchSpec extends BaseSpec { "project2" -> ref12 ) - deltaClient.getWithBody[Json]("/multi-fetch/resources", request("source"), Alice) { (json, response) => + multiFetchRequest(request("source"), Alice) { (json, response) => response.status shouldEqual StatusCodes.OK filterNestedKeys("_uuid")(json) shouldEqual expected } @@ -95,12 +101,11 @@ class MultiFetchSpec extends BaseSpec { val expected = jsonContentOf("/kg/multi-fetch/unknown.json", "project1" -> ref11) - deltaClient.getWithBody[Json]("/multi-fetch/resources", request, Bob) { (json, response) => + multiFetchRequest(request, Bob) { (json, response) => response.status shouldEqual StatusCodes.OK json shouldEqual expected } } - } } diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/resources/ResourcesTrialSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/resources/ResourcesTrialSpec.scala index 363eb2a9af..5bb562025d 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/resources/ResourcesTrialSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/resources/ResourcesTrialSpec.scala @@ -43,15 +43,15 @@ class ResourcesTrialSpec extends BaseSpec with CirceEq { def schema = root.schema.`@id`.string.getOption(_) "fail for a user without access" in { - deltaClient.getWithBody[Json](s"/trial/resources/$ref/", payloadWithoutSchema, Alice)(expectForbidden) + deltaClient.post[Json](s"/trial/resources/$ref/", payloadWithoutSchema, Alice)(expectForbidden) } "fail for an unknown project" in { - deltaClient.getWithBody[Json](s"/trial/resources/$org/xxx/", payloadWithoutSchema, Alice)(expectForbidden) + deltaClient.post[Json](s"/trial/resources/$org/xxx/", payloadWithoutSchema, Alice)(expectForbidden) } "succeed for a payload without schema" in { - deltaClient.getWithBody[Json](s"/trial/resources/$ref/", payloadWithoutSchema, Bob) { (json, response) => + deltaClient.post[Json](s"/trial/resources/$ref/", payloadWithoutSchema, Bob) { (json, response) => response.status shouldEqual StatusCodes.OK resultId(json).value shouldEqual resourceId schema(json) shouldBe empty @@ -60,7 +60,7 @@ class ResourcesTrialSpec extends BaseSpec with CirceEq { } "succeed for a payload with an existing schema" in { - deltaClient.getWithBody[Json](s"/trial/resources/$ref/", payloadWithExistingSchema, Bob) { (json, response) => + deltaClient.post[Json](s"/trial/resources/$ref/", payloadWithExistingSchema, Bob) { (json, response) => response.status shouldEqual StatusCodes.OK resultId(json).value shouldEqual resourceId schema(json) shouldBe empty @@ -69,7 +69,7 @@ class ResourcesTrialSpec extends BaseSpec with CirceEq { } "succeed for a payload with a new schema" in { - deltaClient.getWithBody[Json](s"/trial/resources/$ref/", payloadWithNewSchema, Bob) { (json, response) => + deltaClient.post[Json](s"/trial/resources/$ref/", payloadWithNewSchema, Bob) { (json, response) => response.status shouldEqual StatusCodes.OK resultId(json).value shouldEqual resourceId schema(json).value shouldBe newSchemaId @@ -79,7 +79,7 @@ class ResourcesTrialSpec extends BaseSpec with CirceEq { "fail for a resource with an invalid context without generating any schema" in { val payload = json"""{ "resource": { "@context": [ "https://bbp.epfl.ch/unknown-context" ], "test": "fail" } }""" - deltaClient.getWithBody[Json](s"/trial/resources/$ref/", payload, Bob) { (json, response) => + deltaClient.post[Json](s"/trial/resources/$ref/", payload, Bob) { (json, response) => response.status shouldEqual StatusCodes.OK resultId(json) shouldBe empty schema(json) shouldBe empty @@ -90,7 +90,7 @@ class ResourcesTrialSpec extends BaseSpec with CirceEq { "fail for a resource with an invalid context but also returning the generated schema" in { val resourcePayload = json"""{ "@context": [ "https://bbp.epfl.ch/unknown-context" ], "test": "fail" }""" val payload = json"""{ "schema": $newSchemaPayload, "resource": $resourcePayload }""" - deltaClient.getWithBody[Json](s"/trial/resources/$ref/", payload, Bob) { (json, response) => + deltaClient.post[Json](s"/trial/resources/$ref/", payload, Bob) { (json, response) => response.status shouldEqual StatusCodes.OK resultId(json) shouldBe empty schema(json).value shouldBe newSchemaId @@ -101,7 +101,7 @@ class ResourcesTrialSpec extends BaseSpec with CirceEq { "fail for a resource when shacl validation fails returning the generated " in { val resourcePayload = SimpleResource.sourcePayloadWithType("nxv:UnexpectedType", 99) val payload = json"""{ "schema": $newSchemaPayload ,"resource": $resourcePayload }""" - deltaClient.getWithBody[Json](s"/trial/resources/$ref/", payload, Bob) { (json, response) => + deltaClient.post[Json](s"/trial/resources/$ref/", payload, Bob) { (json, response) => response.status shouldEqual StatusCodes.OK resultId(json) shouldBe empty schema(json).value shouldBe newSchemaId