【问题标题】:Custom directive in Akka HttpAkka Http 中的自定义指令
【发布时间】:2021-10-29 15:27:57
【问题描述】:

我有一些带有CRUD 操作的API Rest。 每个实体都使用UUID 标识。

例如Create 类似于:

  private val createProduct = post {
    path("product" / Segment) { productUUID =>
        Try(UUID.fromString(productUUID)) match {
          case Failure(_) => // Bad request
          case Success(validUuid) =>
            entity(as[ProductData]) { productData =>
              onComplete(addProduct(validUuid, productData)) {
                case Success(_)  => complete(StatusCodes.OK)
                case Failure(ex) => // some code 
              }
            }
        }
    }
  }

Read(GET)、Update(PUT) 和Delete(DELETE) 的操作类似于 POST:

  • 第一步是获取 uuid
  • 对于PUT,使用entity(as[ProductData]) 获取有效负载(GETDELETE 不需要)
  • 调用一些返回Future[Something]的方法

我想做的是删除样板,例如:

  • 获取UUID,对其进行验证,如果无效则返回Bad Request
  • 创建一些指令/函数来处理未来:如果有异常,则返回500 Internal Server Error,但如果是Success,则继续处理该值(我认为使用provide 指令)。

我找到了这个例子 (https://fmsbeekmans.com/blog/akka-http-2-creating-custom-directives.html):

def simplifiedOnComplete[T](future: Future[T])(timeout: FiniteDuration): Directive1[T] = {
  Try(Await.result(future, Duration.Inf)) match {
    case Success(result) => provide(result)
    case Failure(error) => failWith(error)
  }
}

我说,好吧,在这个例子中有一个尝试!也许我可以将其更改为使用UUID 而不是Future

  def getUUID[T]: Directive1[T] = {
    path(Segment) { maybeuuid =>
      Try(UUID.fromString(maybeuuid)) match {
        case Success(result) => provide(result) // compilation error here
        case Failure(error)  => failWith(error)
      }
    }
  }

代码无法编译并出现错误: Type mismatch. Required: Route, found: Directive1[UUID] 我想问题是我添加了path ...

如何创建Directive 以提取有效的uuid 并在它无效时返回Bad Request? 而且,是否可以将处理未来的代码封装在自定义指令中?

例如,在顶部定义的路由将类似于:

  private val createProduct = post {
     path ("product") {
        extractUUID { validUUID =>
           entity(as[ProductData]) { productData => 
              futureSuccess(addProduct(validUUID, productData)) { successValue =>
                 // code here, for example: complete(OK)
              }
           }
        }
     }
  }

【问题讨论】:

    标签: scala akka akka-http


    【解决方案1】:

    你快到了 - 你的代码是:

      def getUUID[T]: Directive1[T] = {
        path(Segment) { maybeuuid =>
          Try(UUID.fromString(maybeuuid)) match {
            case Success(result) => provide(result) // compilation error here
            case Failure(error)  => failWith(error)
          }
        }
      }
    
    1. 你不需要通用的T,因为你只能从UUID.fromString返回一个UUID
    2. path(Segment) 给你一个Directive。所以你想用flatMap 得到一个Directive 回来(provide 返回一个指令)

    所以应该是这样的

      def getUUID: Directive1[UUID] = {
        path(Segment).flatMap { maybeuuid =>
          Try(UUID.fromString(maybeuuid)) match {
            case Success(result) => provide(result) 
            case Failure(error)  => failWith(error)
          }
        }
      }
    

    并且,是否可以在自定义指令中封装以下代码 处理未来?

    是的,和上面的一样。 onComplete 返回一个Directive,所以你必须flatMap

    要返回 BadRequest,请在 akka-http 文档中查找拒绝处理程序。

    【讨论】:

    • 我发誓我昨天尝试删除类型参数但没有成功(代码未编译)......显然我做错了什么。无论如何,感谢您的帮助,您的代码正在运行!我将阅读拒绝处理程序的文档。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-28
    • 1970-01-01
    • 2023-04-04
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多