I have created this project during my research on scala/spray/akka/slick/mysql REST service.
It may be used to learn a bit on how to use those technologies to create REST service. It's just a prove of concept though and it's not production ready. It definitely can be used as a good start.
Additionally websocket (https://github.com/wandoulabs/spray-websocket) was added to project. All events in the REST system like create/update/delete of resource are publishing information to all connected clients via websocket.
The database underneath is mysql, but it can be easily switch to any other which is supported by slick.
class CompanyApi(val actorContext: ActorContext, companyDao: CompanyDao, override val authorization: Authorization)
extends BaseResourceApi with Logging {
/**
* Handler val names must be unique in the system - all
*/
private val companyCreateHandler = actorContext.actorOf(RoundRobinPool(2).props(CreateActor.props(companyDao)), CreateActor.Name)
private val companyPutHandler = actorContext.actorOf(RoundRobinPool(5).props(UpdateActor.props(companyDao)), UpdateActor.Name)
private val companyGetHandler = actorContext.actorOf(RoundRobinPool(20).props(GetActor.props(companyDao)), GetActor.Name)
private val companyDeleteHandler = actorContext.actorOf(RoundRobinPool(2).props(DeleteActor.props(companyDao)), DeleteActor.Name)
override val logTag: String = getClass.getName
override def init() = {
companyDao.initTable()
super.init()
}
override def authorisedResource = true
override def route(implicit userAuth: RestApiUser) = {
pathPrefix(ResourceName) {
pathEnd {
get {
ctx => companyGetHandler ! GetMessage(ctx, None)
} ~
post {
entity(as[Company]) {
company =>
ctx => companyCreateHandler ! CreateMessage(ctx, company)
}
}
} ~
pathPrefix(IntNumber) {
entityId => {
pathEnd {
get {
ctx => companyGetHandler ! GetMessage(ctx, Some(entityId))
} ~ put {
entity(as[Company]) { entity =>
ctx => companyPutHandler ! PutMessage(ctx, entity.copy(id = Some(entityId)))
}
} ~ delete {
ctx => companyDeleteHandler ! DeleteMessage(ctx, entityId)
} ~ patch {
entity(as[List[JsonNotation]]) { patch =>
ctx => companyPutHandler ! PatchMessage(ctx, patch, entityId)
}
}
}
}
}
}
}
}
class CompanyApiBuilder extends Api{
override def create(actorContext: ActorContext, authorization: Authorization): BaseResourceApi = {
new CompanyApi(actorContext, new CompanyDao, authorization)
}
}
object RestExampleApp extends App {
new Rest(ActorSystem("on-spray-can"), List(PersonApi, CompanyApi), List(new ConsoleLogger))
}
PersonApi class is just an example you don't have to implement handling incoming request same way, but I think it's quite good design. It give a possibility to configure number of workers per request type etc. Of course it is possible to handle request inline and no additional actors are needed.