Akka Http 中的自定义指令

Custom directive in Akka Http

我有一些 API 休息 CRUD 操作。 使用 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:

我想做的是像这样删除样板文件:

我找到了这个例子 (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 和 return 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)
              }
           }
        }
     }
  }

您快到了 - 您的密码是:

  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
  2. 返回 UUID
  3. path(Segment) 给你一个 Directive。所以你想使用 flatMap 来获得 Directive 返回(provide return 指令)

所以它会是这样的

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

And, is it possible to encapsulate in a custom directive the code that handles de future?

对,同上。 onComplete return 一个 Directive 所以你必须 flatMap.

至 return BadRequest,在 akka-http 文档中查找拒绝处理程序。