I'm starting to learn Http4s, at work we may need to migrate Rest APIs implemented with Akka Http to Http4s.
As an example I can define a custom directive like this:
trait CustomDirectives {
def extractUUID: Directive1[UUID] = {
path(Segment).flatMap { maybeuuid =>
Try(UUID.fromString(maybeuuid)) match {
case Success(result) => provide(result)
case Failure(_) =>
complete(StatusCodes.BadRequest, s"Invalid uuid: $maybeuuid")
}
}
}
}
So everytime I want to extract an UUID and validate it I can use this directive.
We have other custom directives to make some processing on headers, and many more.
Is there anything similar to akka custom directives but in Http4s?
This is described in Handling Path Parameters section of the documentation
// standard Scala extractor, matching String against UUID
object UUIDVar {
def unapply(maybeuuid: String): Option[UUID] =
Try(UUID.fromString(maybeuuid)).toOption
}
val usersService = HttpRoutes.of[IO] {
// just use extractor in pattern matching
case GET -> Root / "users" / UUIDVar(uuid) =>
Ok(useUUIDForSth(uuid))
}
However, personally, I find it easier to describe endpoints with libraries like Tapir or Endpoint4s since their DSL seem more intuitive to me and I am not coupling my code with a particular implementation.
Related
Hi i would like to use completeWith to use actor per request pattern in my test scala project, but i cannot get reference to this directive from spray. I tried using complete directive, and think that somewhere is magnet which will respond in manner that i want, but this:
pathPrefix("search") {
path("book" / "getAvailable") {
get {
respondWithMediaType(`application/json`) {
complete(instanceOf[Seq[Book]]) { completeFunction =>
Don't work. Do you know what directive in spray works like completeWith in Akka?
Answer is there is no completeWith in spray, i used akka http, since spray is no longer developed:
completeWith(instanceOf[Seq[BookApp]]) { completeFunction =>
system.actorOf(Props(new HandlerActor(bookService, authorService))) ! Handler.AllBooks(completeFunction)
}
I'm using Akka Http 2.4.7. For Json (that use json4s), serialisation is something like this:
entity(as[CaseClass]) { serialisedCaseClass => .... }
for deserialising, I just return a case class object.
I wonder is there a similar way for protobuf?
No, there isn't anything available out of the box (but I agree it would be nice to have). You currently need to build your own custom unmarshaller to do that (as of akka-http 2.4.11).
You can build your own unmarshaller based on an existing protobuf definition. Here's a stub how to do it:
case class Person(...)
implicit val personUnmarshaller: FromEntityUnmarshaller[Person] =
PredefinedFromEntityUnmarshallers.byteArrayUnmarshaller map { bytes =>
// bytes is an Array[Byte]
// call protobuf to do the unmarshalling
}
and then import this definition in your route.
I am having trouble specifying some custom routing logic for my Akka Router. Here is what I have so far:
class OrderRoutingLogic extends RoutingLogic {
private val markets = mutable.Map.empty[Security, ActorRef]
def select(message: Any, routees: IndexedSeq[Routee]): Routee = {
message match {
case order: Order => ActorRefRoutee(markets(order.security))
case _ => NoRoutee // will send to DeadLetters!
}
}
IntelliJ IDEA is telling me that I have not specified the select(message: Any, routees: IndexedSeq[Routee]): Routee and I do not understand why. How to use custom Router in Akka 2.3? has an answer that uses akka.routing.NoRoutee (although without pattern matching). What have I done wrong?
This is because the routees parameter type is not correct: it should be immutable.IndexedSeq[Routee] and not IndexedSeq[Routee]. I agree this is tricky!
I'm using LIFT to serve a RESTful API, and I want this API to allow requests using CORS (Cross-Origin Resource Sharing) for POST. I do have CORS working with GET requests.
I'm having trouble because cross-origin POSTs first call OPTIONS on the given URL, and I haven't figured out how to accept OPTIONS requests with LIFT.
My question is: What do I need to mixin or write to my serve{} block such that I can allow the HTTP verb OPTIONS for a given path in LIFT?
Right now using curl I get:
curl -X OPTIONS http://localhost:8080/path => [404]
I'm using LIFT 2.4-M5 and Scala 2.9.1
EDIT: Based on pr1001's suggestion, I was trying to extend RestHelper like so:
import net.liftweb.http.provider._
import net.liftweb.http._
trait RestHelper extends net.liftweb.http.rest.RestHelper {
protected object Options {
// Compile error here with options_?
// because net.liftweb.http.Req uses LIFT's RequestType
def unapply(r: Req): Option[(List[String], Req)] =
if (r.requestType.options_?) Some(r.path.partPath -> r) else None
}
}
#serializable
abstract class RequestType extends net.liftweb.http.RequestType {
def options_? : Boolean = false
}
#serializable
case object OptionsRequest extends RequestType {
override def options_? = true
def method = "OPTIONS"
}
object RequestType extends net.liftweb.http.RequestType {
def apply(req: HTTPRequest): net.liftweb.http.RequestType = {
req.method.toUpperCase match {
case "OPTIONS" => UnknownRequest("OPTIONS")
case _ => net.liftweb.http.RequestType.apply(req)
}
}
def method = super.method
}
I feel like this is more work then I should need to do because I don't want to have to extend Req with my own RequestType impl.
I'm definitely on the lower level of skill set when it comes to Scala, so I'm hoping someone can provide a bit simpler solution because I'm sure there's something I'm missing.
Are you using RestHelper? If so you'd specify the type of request you want to respond to and return a LiftResponse. There's no OptionRequest in Lift (yet) to use in the partial function you pass to serve() but you should be able to extend RequestType with your own version. Using UnknownRequest – as in UnknownRequest("OPTION") – might also do the trick.
This might also be worth bringing up on the mailing list, as CORS support would be a useful addition...
Many thanks to pr1001 for his suggestion. I was able to get it working with the following:
import net.liftweb.http._
class RequestTypeImproved(requestType: RequestType) {
def options_? : Boolean = requestType.method == "OPTIONS"
}
trait RestHelper extends net.liftweb.http.rest.RestHelper {
implicit def req2ReqImproved(requestType: RequestType): RequestTypeImproved = {
new RequestTypeImproved(requestType)
}
protected object Options {
def unapply(r: Req): Option[(List[String], Req)] =
if (r.requestType.options_?) Some(r.path.partPath -> r) else None
}
}
Then:
serve {
case req # "path" Options _ => {
LiftResponse(...)
}
}
Let there a few separate DAO classes OrderDAO, ProductDAO, and CustomerDAO that store/retrieve data in the database and share a single instance DataSource (the database connection factory).
In order to create a DataSource instance and plug it in DAOs we usually use Spring DI. Now I would like to do that in Scala without any DI framework.
I've read about the cake pattern, and it looks like I should do the following:
trait DatabaseContext { val dataSource:Datasource }
trait OrderDAO {this:DatabaseContext =>
... // use dataSource of DatabaseContext
}
trait ProductDAO {this:DatabaseContext =>
... // use dataSource of DatabaseContext
}
object DAOImpl extends OrderDAO with ProductDAO with DatabaseContext {
val dataSource = ... // init the data source
}
Do I understand the cake pattern correctly?
Can I implement these DAOs differently using the cake pattern ?
What does it provide that DI frameworks like Spring do not ?
How can I create separate OrderDAOImpl and ProductDAOImpl objects sharing the same DataSource instance instead of one big DAOImpl?
The advantages of the cake pattern are:
Unlike configuration-file-based DI solutions, matching contracts to
implementations is done at compile time, which reduces class-finding
and compatibility issues. However, many DI engines have an
alternative in-code configuration feature
No third-party libraries
are used. Self-type annotations which let you use the pattern are a
native language feature. No special syntax is used to retrieve the
implementation of the contract
Forgetting to specify an
implementation for a component needed by another component results in
a runtime error - just check this article
http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html
and try not specifying one of the components or specifying a
trait instead of a concrete class in any of the cake pattern
examples or even forgetting to initialize a val corresponding to a component needed
However, to experience these advantages, you need to more strictly adhere to the architecture of the pattern - check the same article and note the wrapping traits that contain the actual contracts and implementations.
Your examples do not seem to be strictly the cake pattern. In your case you could've just used inheritance to create implementations for your traits and use separate classes for each DAO component. In the cake pattern the consuming code would be a component just like the DAO code, and the code assembling the dependencies together would stand alone from it.
To illustrate the cake pattern, you would have to add consuming classes (domain layer or UI layer) to your example. Or it the case your DAO components accessed each other's features you could illustrate the cake pattern on you DAO alone.
to make it short,
trait OrderDAOComponent {
val dao: OrderDAO
trait OrderDAO {
def create: Order
def delete(id: Int): Unit
//etc
}
}
trait OrderDAOComponentImpl extends OrderDAOComponent {
class OrderDAOJDBCImpl extends OrderDAO {
def create: Order = {/*JDBC-related code here*/}
def delete(id: Int) {/*JDBC-related code here*/}
//etc
}
}
//This one has a dependency
trait OrderWebUIComponentImpl {
this: OrderDAOComponent =>
class OrderWebUI {
def ajaxDelete(request:HttpRequest) = {
val id = request.params("id").toInt
try {
dao.delete(id)
200
}
catch {
case _ => 500
}
}
}
}
//This matches contracts to implementations
object ComponentRegistry extends
OrderDAOComponentImpl with
OrderWebUIComponentImpl
{
val dao = new OrderDAOJDBCImpl
val ui = new OrderWebUI
}
//from some front-end code
val status = ComponentRegistry.ui.ajaxDelete(request)
More on your example. I think it could be more like cake if:
trait DatabaseContext { val dataSource:Datasource }
trait OrderDAOComponent {this:DatabaseContext =>
trait OrderDAOImpl {
... // use dataSource of DatabaseContext
}
}
trait ProductDAOComponent {this:DatabaseContext =>
trait ProductDAOImpl {
... // use dataSource of DatabaseContext
}
}
object Registry extends OrderDAOComponent with ProductDAOComponent with DatabaseContextImpl {
val dataSource = new DatasourceImpl //if Datasource is a custom trait, otherwise wrapping needed
val orderDAO = new OrderDAOImpl
val productDAO = new ProductDAOImpl
}
//now you may use them separately
Registry.orderDAO.//
Maybe:
Statically checked at compile time.