Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pollux): implemented pagination with navigation for schema-registry #195

Merged
merged 1 commit into from
Dec 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.iohk.atala.api.http

import sttp.tapir.model.ServerRequest

case class RequestContext(request: ServerRequest)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package io.iohk.atala.api.http.model

case class CollectionStats(totalCount: Int, filteredCount: Int)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.iohk.atala.api.http.model

import sttp.tapir.Codec.PlainCodec
import sttp.tapir.generic.auto.*
import sttp.tapir.{Codec, DecodeResult, Schema}
import zio.json.{DeriveJsonDecoder, DeriveJsonEncoder}

import java.time.ZonedDateTime
import java.util.{Base64, UUID}
import scala.util.Try

case class PaginationInput(
offset: Option[Int] = None,
limit: Option[Int] = None
) {
def toPagination = Pagination.apply(this)
}

case class Pagination(offset: Int, limit: Int) {
def next = copy(offset = offset + limit)
def prev = copy(offset = Math.max(offset - limit, 0))
}

object Pagination {
def apply(in: PaginationInput): Pagination =
Pagination(in.offset.getOrElse(0), in.limit.getOrElse(100))
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package io.iohk.atala.pollux.schema

import io.iohk.atala.api.http.model.{Order, Pagination}
import io.iohk.atala.api.http.{BadRequest, FailureResponse, InternalServerError, NotFoundResponse}
import io.iohk.atala.api.http.model.{Order, PaginationInput}
import io.iohk.atala.api.http.{BadRequest, FailureResponse, InternalServerError, NotFoundResponse, RequestContext}
import io.iohk.atala.pollux.schema.model.{
VerifiableCredentialSchema,
VerificationCredentialSchemaInput,
VerifiableCredentialSchemaPage
VerifiableCredentialSchemaPage,
VerifiableCredentialSchemaInput
}
import io.iohk.atala.api.http.codec.OrderCodec._
import io.iohk.atala.api.http.codec.OrderCodec.*
import sttp.tapir.EndpointIO.Info
import sttp.tapir.extractFromRequest
import sttp.tapir.json.zio.jsonBody
import sttp.tapir.{
Endpoint,
Expand All @@ -31,15 +32,16 @@ import java.util.UUID
object SchemaRegistryEndpoints {

val createSchemaEndpoint: PublicEndpoint[
VerificationCredentialSchemaInput,
(RequestContext, VerifiableCredentialSchemaInput),
FailureResponse,
VerifiableCredentialSchema,
Any
] =
endpoint.post
.in(extractFromRequest[RequestContext](RequestContext.apply))
.in("schema-registry" / "schemas")
.in(
jsonBody[VerificationCredentialSchemaInput]
jsonBody[VerifiableCredentialSchemaInput]
.copy(info =
Info.empty.description(
"Create schema input object with the metadata and attributes"
Expand All @@ -64,12 +66,13 @@ object SchemaRegistryEndpoints {
.tag("Schema Registry")

val getSchemaByIdEndpoint: PublicEndpoint[
UUID,
(RequestContext, UUID),
FailureResponse,
VerifiableCredentialSchema,
Any
] =
endpoint.get
.in(extractFromRequest[RequestContext](RequestContext.apply))
.in(
"schema-registry" / "schemas" / path[UUID]("id")
.copy(info = Info.empty.description("Get the schema by id"))
Expand All @@ -88,12 +91,18 @@ object SchemaRegistryEndpoints {
.tag("Schema Registry")

val lookupSchemasByQueryEndpoint: PublicEndpoint[
(VerifiableCredentialSchema.Filter, Pagination, Option[Order]),
(
RequestContext,
VerifiableCredentialSchema.Filter,
PaginationInput,
Option[Order]
),
FailureResponse,
VerifiableCredentialSchemaPage,
Any
] =
endpoint.get
.in(extractFromRequest[RequestContext](RequestContext.apply))
.in("schema-registry" / "schemas".description("Lookup schemas by query"))
.in(
query[Option[String]]("author")
Expand All @@ -108,7 +117,7 @@ object SchemaRegistryEndpoints {
.in(
query[Option[Int]]("offset")
.and(query[Option[Int]]("limit"))
.mapTo[Pagination]
.mapTo[PaginationInput]
)
.in(query[Option[Order]]("order"))
.out(jsonBody[VerifiableCredentialSchemaPage])
Expand All @@ -126,4 +135,25 @@ object SchemaRegistryEndpoints {
"Lookup schemas by `author`, `name`, `tags` parameters and control the pagination by `offset` and `limit` parameters "
)
.tag("Schema Registry")

val testEndpoint: PublicEndpoint[
RequestContext,
Unit,
String,
Any
] =
Comment on lines +139 to +144
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be used for testing locally and removed when creating PR?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will be removed later.
we need to figure out and test how to resolve the real Url behind the proxy to form the right Url in the prism-agent.
For instance, prism-agent running locally creates this response for pagination request:
{ "contents": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "version": "string", "tags": [ "string" ], "description": "string", "attributes": [ "string" ], "author": "Prism Agent", "authored": "2022-12-02T07:59:45.153Z", "kind": "VerifiableCredentialSchema", "self": "/schema-registry/schemas/3fa85f64-5717-4562-b3fc-2c963f66afa6" } ], "kind": "VerifiableCredentialSchemaPage", "self": "/schema-registry/schemas", "pageOf": "/schema-registry/schemas" }

but behind the proxy it should be /prism-agent/schema-registry/schemas

endpoint.get
.in(
"schema-registry" / "test"
.copy(info = Info.empty.description("Debug endpoint"))
)
.in(extractFromRequest[RequestContext](RequestContext.apply))
.out(jsonBody[String])
.name("test")
.summary("Trace the request input from the point of view of the server")
.description(
"Trace the request input from the point of view of the server"
)
.tag("Schema Registry")

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package io.iohk.atala.pollux.schema

import io.iohk.atala.api.http.model.{Order, Pagination}
import io.iohk.atala.api.http.{FailureResponse, InternalServerError, NotFoundResponse}
import io.iohk.atala.api.http.model.{CollectionStats, Order, Pagination, PaginationInput}
import io.iohk.atala.api.http.{FailureResponse, InternalServerError, NotFoundResponse, RequestContext}
import io.iohk.atala.pollux.schema.SchemaRegistryEndpoints.{
createSchemaEndpoint,
getSchemaByIdEndpoint,
lookupSchemasByQueryEndpoint
lookupSchemasByQueryEndpoint,
testEndpoint
}
import io.iohk.atala.pollux.schema.model.{
VerifiableCredentialSchema,
VerifiableCredentialSchemaInput,
VerifiableCredentialSchemaPage
}
import io.iohk.atala.pollux.schema.model.VerifiableCredentialSchema
import io.iohk.atala.pollux.service.SchemaRegistryService
import io.iohk.atala.pollux.service.SchemaRegistryService.{createSchema, getSchemaById, lookupSchemas}
import sttp.tapir.redoc.RedocUIOptions
Expand All @@ -16,6 +21,7 @@ import sttp.tapir.server.ServerEndpoint
import sttp.tapir.swagger.bundle.SwaggerInterpreter
import sttp.tapir.ztapir.*
import zio.{Task, URIO, ZIO, ZLayer}
import io.iohk.atala.pollux.schema.controller.SchemaRegistryController

import java.util.UUID

Expand All @@ -27,48 +33,77 @@ class SchemaRegistryServerEndpoints(

// TODO: make the endpoint typed ZServerEndpoint[SchemaRegistryService, Any]
val createSchemaServerEndpoint: ZServerEndpoint[Any, Any] =
createSchemaEndpoint.zServerLogic(schemaInput =>
schemaRegistryService
.createSchema(schemaInput)
.foldZIO(throwableToInternalServerError, schema => ZIO.succeed(schema))
)
createSchemaEndpoint.zServerLogic {
case (
ctx: RequestContext,
schemaInput: VerifiableCredentialSchemaInput
) =>
schemaRegistryService
.createSchema(schemaInput)
.foldZIO(
throwableToInternalServerError,
schema =>
ZIO.succeed(
schema.withBaseUri(ctx.request.uri)
)
)
}

val getSchemaByIdServerEndpoint: ZServerEndpoint[Any, Any] =
getSchemaByIdEndpoint.zServerLogic(id =>
getSchemaByIdEndpoint.zServerLogic { case (ctx: RequestContext, id: UUID) =>
schemaRegistryService
.getSchemaById(id)
.foldZIO(
throwableToInternalServerError,
{
case Some(schema) => ZIO.succeed(schema)
case Some(schema) =>
ZIO.succeed(schema.withSelf(ctx.request.uri.toString))
case None =>
ZIO.fail[FailureResponse](
NotFoundResponse(s"Schema is not found by $id")
)
}
)
)
}

val lookupSchemasByQueryServerEndpoint: ZServerEndpoint[Any, Any] =
lookupSchemasByQueryEndpoint.zServerLogic {
case (
ctx: RequestContext,
filter: VerifiableCredentialSchema.Filter,
page: Pagination,
paginationInput: PaginationInput,
order: Option[Order]
) =>
schemaRegistryService
.lookupSchemas(filter, page, order)
.lookupSchemas(filter, paginationInput.toPagination, order)
.foldZIO(
throwableToInternalServerError,
pageOfVCS => ZIO.succeed(pageOfVCS)
{
case (
page: VerifiableCredentialSchemaPage,
stats: CollectionStats
) =>
ZIO.succeed(
SchemaRegistryController(
ctx,
paginationInput.toPagination,
page,
stats
).result
)
}
)
}

val testServerEndpoint: ZServerEndpoint[Any, Any] =
testEndpoint.zServerLogic(requestContext => ZIO.succeed(requestContext.request.toString))

val all: List[ZServerEndpoint[Any, Any]] =
List(
createSchemaServerEndpoint,
getSchemaByIdServerEndpoint,
lookupSchemasByQueryServerEndpoint
lookupSchemasByQueryServerEndpoint,
testServerEndpoint
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package io.iohk.atala.pollux.schema

import io.iohk.atala.api.http.codec.OrderCodec.*
import io.iohk.atala.api.http.model.{Order, Pagination}
import io.iohk.atala.api.http.model.{Order, PaginationInput}
import io.iohk.atala.api.http.{BadRequest, FailureResponse, InternalServerError, NotFoundResponse}
import io.iohk.atala.pollux.schema.model.{
VerifiableCredentialSchema,
VerificationCredentialSchemaInput,
VerifiableCredentialSchemaInput,
VerifiableCredentialSchemaPage
}
import io.iohk.atala.pollux.schema.model.{
Expand Down Expand Up @@ -143,7 +143,7 @@ object VerificationPolicyEndpoints {
.tag("Verification")

val lookupVerificationPoliciesByQueryEndpoint: PublicEndpoint[
(VerificationPolicy.Filter, Pagination, Option[Order]),
(VerificationPolicy.Filter, PaginationInput, Option[Order]),
FailureResponse,
VerificationPolicyPage,
Any
Expand All @@ -169,7 +169,7 @@ object VerificationPolicyEndpoints {
.in(
query[Option[Int]]("offset")
.and(query[Option[Int]]("limit"))
.mapTo[Pagination]
.mapTo[PaginationInput]
)
.in(query[Option[Order]]("order"))
.out(jsonBody[VerificationPolicyPage])
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.iohk.atala.pollux.schema

import io.iohk.atala.api.http.model.{Order, Pagination}
import io.iohk.atala.api.http.model.{Order, PaginationInput}
import io.iohk.atala.api.http.{FailureResponse, InternalServerError, NotFoundResponse}
import io.iohk.atala.pollux.schema.VerificationPolicyEndpoints.*
import io.iohk.atala.pollux.schema.model.{VerificationPolicy, VerificationPolicyInput}
Expand Down Expand Up @@ -81,7 +81,7 @@ class VerificationPolicyServerEndpoints(
lookupVerificationPoliciesByQueryEndpoint.zServerLogic {
case (
filter: VerificationPolicy.Filter,
page: Pagination,
page: PaginationInput,
order: Option[Order]
) =>
service
Expand Down
Loading