Skip to content

Commit

Permalink
Skeleton Http4s Mongo Service (#10)
Browse files Browse the repository at this point in the history
* Basic Mongo service running on Http4s

* Improved mongo service endpoints
  • Loading branch information
RawToast committed Mar 15, 2018
1 parent e71efe8 commit 34c54cd
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 21 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.vscode
.idea
*.iml
6 changes: 5 additions & 1 deletion dokusho-server/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ val SCALA_VERSION = "2.12.4"
val CIRCE_VERSION = "0.9.1"
val HTTP4S_VERSION = "0.18.1"
val MONGO_VERSION = "2.2.1"
val MONOCLE_VERSION = "1.5.0"

resolvers ++= Seq(
Resolver.sonatypeRepo("releases"),
Expand All @@ -24,7 +25,10 @@ libraryDependencies ++= Seq(

"org.mongodb.scala" %% "mongo-scala-driver" % MONGO_VERSION,

"ch.qos.logback" % "logback-classic" % "1.2.3"
"ch.qos.logback" % "logback-classic" % "1.2.3",

"com.github.julien-truffaut" %% "monocle-core" % MONOCLE_VERSION,
"com.github.julien-truffaut" %% "monocle-macro" % MONOCLE_VERSION
)

scalacOptions ++= Seq("-Ypartial-unification")
2 changes: 1 addition & 1 deletion dokusho-server/dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ COPY . .

RUN sbt compile

CMD sbt run
CMD ["sbt", "run"]
2 changes: 1 addition & 1 deletion dokusho-server/src/main/scala/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ object Main extends StreamApp[IO] {

override def stream(args: List[String], requestShutdown: IO[Unit]): Stream[IO, ExitCode] =
BlazeBuilder[IO]
.bindHttp(8080, "localhost")
.bindHttp(8080, "0.0.0.0")
.mountService(mongoService.routes, "/")
.withBanner(ServerBuilder.DefaultBanner)
.serve
Expand Down
50 changes: 42 additions & 8 deletions dokusho-server/src/main/scala/dokusho/MongoRepository.scala
Original file line number Diff line number Diff line change
@@ -1,37 +1,69 @@
package dokusho

import cats.effect._

import cats.data.OptionT
import cats.effect.IO
import io.circe.generic.auto._
import io.circe.parser._
import io.circe.syntax._
import io.circe.{DecodingFailure, Json, ParsingFailure}
import monocle.macros.GenLens
import org.bson.Document
import org.mongodb.scala.model.Filters._
import org.mongodb.scala.{MongoClient, MongoCollection, Observable, model}
import org.mongodb.scala.{FindObservable, MongoClient, MongoCollection, Observable, model}

import scala.concurrent.ExecutionContext

class MongoRepository(connectionString: String, databaseName: String, collectionName: String) {

private lazy val daysLens = GenLens[UserReadingHistory](_.readingHistory.days)
private lazy val entriesLens = GenLens[Day](_.entries)

implicit val executionContext: ExecutionContext = scala.concurrent.ExecutionContext.Implicits.global

lazy val collection: MongoCollection[Document] =
private lazy val collection: MongoCollection[Document] =
MongoClient(connectionString)
.getDatabase(databaseName)
.getCollection(collectionName)

def get(userId: String) = for {
document <- getDocument(userId)
hs <- toUserReadingHistory(document)
} yield hs
def get(userId: String): IO[Option[UserReadingHistory]] =
OptionT(getDocumentIoOpt(userId))
.semiflatMap(toUserReadingHistory)
.value


def getUnsafe(userId: String): IO[UserReadingHistory] =
getDocumentIO(userId)
.flatMap(toUserReadingHistory)

def put(g: UserReadingHistory): IO[UserReadingHistory] =
collection.replaceOne(equal("uuid", g.userId.toString), Document.parse(g.asJson.spaces2),
model.UpdateOptions().upsert(true)).asIO
.map(_ => g)

def addEntry(userId: String, date: String, entry: Entry): IO[UserReadingHistory] = {
for {
urh <- getUnsafe(userId)
days = urh.readingHistory.days
dayToUpdate = days.find(_.date == userId).getOrElse(Day(date, Seq.empty))
updatedDay = entriesLens.modify(_ :+ entry)(dayToUpdate)
doc = daysLens.modify(upsertDay(updatedDay))(urh)
} yield doc
}

private def upsertDay(day: Day)(days: Seq[Day]): Seq[Day] =
if (days.exists(_.date == day.date)) {
days.withFilter(_.date == day.date)
.map(_ => day)
} else {
days :+ day
}

private def getDocument(id: String): FindObservable[Document] = collection.find(equal("userId", id))

private def getDocument(id: String): IO[Document] = collection.find(equal("userId", id)).asIO
private def getDocumentIO(id: String): IO[Document] = getDocument(id).asIO

private def getDocumentIoOpt(id: String): IO[Option[Document]] = getDocument(id).asIOOpt

private def toUserReadingHistory(task: Document): IO[UserReadingHistory] = {
for {
Expand All @@ -53,6 +85,8 @@ class MongoRepository(connectionString: String, databaseName: String, collection
private implicit class IOSyntax[T](obs: Observable[T]) {
def asIO: IO[T] = IO.fromFuture(IO(obs.head()))

def asIOOpt: IO[Option[T]] = IO.fromFuture(IO(obs.headOption()))

def asSeqIO: IO[Seq[T]] = IO.fromFuture(IO(obs.toFuture()))
}

Expand Down
20 changes: 13 additions & 7 deletions dokusho-server/src/main/scala/dokusho/MongoService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,23 @@ class MongoService(mongoRepository: MongoRepository) {
case class SuccessfulPut(userId: String)

val routes: HttpService[IO] = HttpService[IO] {
case GET -> Root / "mongo" / name =>
case GET -> Root / "history" / userId =>
for {
userReadingHistory <- mongoRepository.get(name)
json: Json = userReadingHistory.asJson
userReadingHistory <- mongoRepository.getUnsafe(userId)
json = userReadingHistory.asJson
response <- Ok(json)
} yield response
case req@PUT -> Root / "mongo" =>
implicit val userDecoder: EntityDecoder[IO, UserReadingHistory] = jsonOf[IO, UserReadingHistory]
case GET -> Root / "history" / "safe" / userId =>
for {
userReadingHistory <- mongoRepository.get(userId)
json: Option[Json] = userReadingHistory.map(_.asJson)
resp <- json.fold(NotFound())(j => Ok(j))
} yield resp
case req@PUT -> Root / "history" / userId =>
implicit val userDecoder: EntityDecoder[IO, ReadingHistory] = jsonOf[IO, ReadingHistory]
for {
userReadingHistory <- req.as[UserReadingHistory]
storedHistory <- mongoRepository.put(userReadingHistory)
userReadingHistory <- req.as[ReadingHistory]
storedHistory <- mongoRepository.put(UserReadingHistory(userId, userReadingHistory))
json: Json = SuccessfulPut(storedHistory.userId).asJson
response <- Ok(json)
} yield response
Expand Down
4 changes: 2 additions & 2 deletions kube/backend-controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ kind: ReplicationController
metadata:
labels:
name: backend
name: backend-controller
name: backend
spec:
replicas: 2
selector:
Expand All @@ -18,4 +18,4 @@ spec:
name: backend
ports:
- containerPort: 8080
name: backend-server
name: backend-server
2 changes: 1 addition & 1 deletion kube/mongo-controller.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ kind: ReplicationController
metadata:
labels:
name: mongo
name: mongo-controller
name: mongo
spec:
replicas: 1
template:
Expand Down

0 comments on commit 34c54cd

Please sign in to comment.