vixxx123 / scalasprayslickexample

REST CRUD example using scala / akka /spray / slick
18 stars 5 forks source link

Welcome to rest scala/spray/akka/slick/mysql example

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.

System requirements

Configuration

Adding new REST API

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.

Features

How to run

to do

Have fun