org.http4s.dsl.Http4sDsl Scala Examples
The following examples show how to use org.http4s.dsl.Http4sDsl.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example.
Example 1
Source File: CategoryRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes import cats._ import org.http4s._ import org.http4s.dsl.Http4sDsl import org.http4s.server.Router import shop.algebras.Categories import shop.http.json._ final class CategoryRoutes[F[_]: Defer: Monad]( categories: Categories[F] ) extends Http4sDsl[F] { private[routes] val prefixPath = "/categories" private val httpRoutes: HttpRoutes[F] = HttpRoutes.of[F] { case GET -> Root => Ok(categories.findAll) } val routes: HttpRoutes[F] = Router( prefixPath -> httpRoutes ) }
Example 2
Source File: UserRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes import cats._ import cats.implicits._ import org.http4s._ import org.http4s.circe.JsonDecoder import org.http4s.dsl.Http4sDsl import org.http4s.server.Router import shop.algebras.Auth import shop.domain.auth._ import shop.effects._ import shop.http.decoder._ import shop.http.json._ final class UserRoutes[F[_]: Defer: JsonDecoder: MonadThrow]( auth: Auth[F] ) extends Http4sDsl[F] { private[routes] val prefixPath = "/auth" private val httpRoutes: HttpRoutes[F] = HttpRoutes.of[F] { case req @ POST -> Root / "users" => req .decodeR[CreateUser] { user => auth .newUser(user.username.toDomain, user.password.toDomain) .flatMap(Created(_)) .recoverWith { case UserNameInUse(u) => Conflict(u.value) } } } val routes: HttpRoutes[F] = Router( prefixPath -> httpRoutes ) }
Example 3
Source File: CartRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes.secured import cats._ import cats.implicits._ import org.http4s._ import org.http4s.circe._ import org.http4s.dsl.Http4sDsl import org.http4s.server._ import shop.algebras.ShoppingCart import shop.domain.cart._ import shop.domain.item._ import shop.http.auth.users.CommonUser import shop.http.json._ final class CartRoutes[F[_]: Defer: JsonDecoder: Monad]( shoppingCart: ShoppingCart[F] ) extends Http4sDsl[F] { private[routes] val prefixPath = "/cart" private val httpRoutes: AuthedRoutes[CommonUser, F] = AuthedRoutes.of { // Get shopping cart case GET -> Root as user => Ok(shoppingCart.get(user.value.id)) // Add items to the cart case ar @ POST -> Root as user => ar.req.asJsonDecode[Cart].flatMap { cart => cart.items .map { case (id, quantity) => shoppingCart.add(user.value.id, id, quantity) } .toList .sequence *> Created() } // Modify items in the cart case ar @ PUT -> Root as user => ar.req.asJsonDecode[Cart].flatMap { cart => shoppingCart.update(user.value.id, cart) *> Ok() } // Remove item from the cart case DELETE -> Root / UUIDVar(uuid) as user => shoppingCart.removeItem(user.value.id, ItemId(uuid)) *> NoContent() } def routes(authMiddleware: AuthMiddleware[F, CommonUser]): HttpRoutes[F] = Router( prefixPath -> authMiddleware(httpRoutes) ) }
Example 4
Source File: CheckoutRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes.secured import cats.Defer import cats.implicits._ import org.http4s._ import org.http4s.circe.JsonDecoder import org.http4s.dsl.Http4sDsl import org.http4s.server._ import shop.domain.cart._ import shop.domain.checkout._ import shop.domain.order._ import shop.effects._ import shop.http.auth.users.CommonUser import shop.http.decoder._ import shop.http.json._ import shop.programs.CheckoutProgram final class CheckoutRoutes[F[_]: Defer: JsonDecoder: MonadThrow]( program: CheckoutProgram[F] ) extends Http4sDsl[F] { private[routes] val prefixPath = "/checkout" private val httpRoutes: AuthedRoutes[CommonUser, F] = AuthedRoutes.of { case ar @ POST -> Root as user => ar.req.decodeR[Card] { card => program .checkout(user.value.id, card) .flatMap(Created(_)) .recoverWith { case CartNotFound(userId) => NotFound(s"Cart not found for user: ${userId.value}") case EmptyCartError => BadRequest("Shopping cart is empty!") case PaymentError(cause) => BadRequest(cause) case OrderError(cause) => BadRequest(cause) } } } def routes(authMiddleware: AuthMiddleware[F, CommonUser]): HttpRoutes[F] = Router( prefixPath -> authMiddleware(httpRoutes) ) }
Example 5
Source File: OrderRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes.secured import cats._ import org.http4s._ import org.http4s.dsl.Http4sDsl import org.http4s.server._ import shop.algebras.Orders import shop.domain.order._ import shop.http.auth.users.CommonUser import shop.http.json._ final class OrderRoutes[F[_]: Defer: Monad]( orders: Orders[F] ) extends Http4sDsl[F] { private[routes] val prefixPath = "/orders" private val httpRoutes: AuthedRoutes[CommonUser, F] = AuthedRoutes.of { case GET -> Root as user => Ok(orders.findBy(user.value.id)) case GET -> Root / UUIDVar(orderId) as user => Ok(orders.get(user.value.id, OrderId(orderId))) } def routes(authMiddleware: AuthMiddleware[F, CommonUser]): HttpRoutes[F] = Router( prefixPath -> authMiddleware(httpRoutes) ) }
Example 6
Source File: BrandRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes import cats._ import org.http4s._ import org.http4s.dsl.Http4sDsl import org.http4s.server.Router import shop.algebras.Brands import shop.http.json._ final class BrandRoutes[F[_]: Defer: Monad]( brands: Brands[F] ) extends Http4sDsl[F] { private[routes] val prefixPath = "/brands" private val httpRoutes: HttpRoutes[F] = HttpRoutes.of[F] { case GET -> Root => Ok(brands.findAll) } val routes: HttpRoutes[F] = Router( prefixPath -> httpRoutes ) }
Example 7
Source File: HealthRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes import cats._ import org.http4s._ import org.http4s.dsl.Http4sDsl import org.http4s.server.Router import shop.algebras.HealthCheck import shop.http.json._ final class HealthRoutes[F[_]: Defer: Monad]( healthCheck: HealthCheck[F] ) extends Http4sDsl[F] { private[routes] val prefixPath = "/healthcheck" private val httpRoutes: HttpRoutes[F] = HttpRoutes.of[F] { case GET -> Root => Ok(healthCheck.status) } val routes: HttpRoutes[F] = Router( prefixPath -> httpRoutes ) }
Example 8
Source File: AdminBrandRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes.admin import cats._ import io.circe.refined._ import org.http4s._ import org.http4s.circe.JsonDecoder import org.http4s.dsl.Http4sDsl import org.http4s.server._ import shop.algebras.Brands import shop.domain.brand._ import shop.http.auth.users.AdminUser import shop.effects._ import shop.http.decoder._ import shop.http.json._ final class AdminBrandRoutes[F[_]: Defer: JsonDecoder: MonadThrow]( brands: Brands[F] ) extends Http4sDsl[F] { private[admin] val prefixPath = "/brands" private val httpRoutes: AuthedRoutes[AdminUser, F] = AuthedRoutes.of { case ar @ POST -> Root as _ => ar.req.decodeR[BrandParam] { bp => Created(brands.create(bp.toDomain)) } } def routes(authMiddleware: AuthMiddleware[F, AdminUser]): HttpRoutes[F] = Router( prefixPath -> authMiddleware(httpRoutes) ) }
Example 9
Source File: AdminCategoryRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes.admin import cats._ import io.circe.refined._ import org.http4s._ import org.http4s.circe.JsonDecoder import org.http4s.dsl.Http4sDsl import org.http4s.server._ import shop.algebras.Categories import shop.domain.category._ import shop.effects._ import shop.http.auth.users.AdminUser import shop.http.decoder._ import shop.http.json._ final class AdminCategoryRoutes[F[_]: Defer: JsonDecoder: MonadThrow]( categories: Categories[F] ) extends Http4sDsl[F] { private[admin] val prefixPath = "/categories" private val httpRoutes: AuthedRoutes[AdminUser, F] = AuthedRoutes.of { case ar @ POST -> Root as _ => ar.req.decodeR[CategoryParam] { c => Created(categories.create(c.toDomain)) } } def routes(authMiddleware: AuthMiddleware[F, AdminUser]): HttpRoutes[F] = Router( prefixPath -> authMiddleware(httpRoutes) ) }
Example 10
Source File: AdminItemRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes.admin import cats._ import org.http4s._ import org.http4s.circe.JsonDecoder import org.http4s.dsl.Http4sDsl import org.http4s.server._ import shop.algebras.Items import shop.domain.item._ import shop.effects._ import shop.http.auth.users.AdminUser import shop.http.decoder._ import shop.http.json._ final class AdminItemRoutes[F[_]: Defer: JsonDecoder: MonadThrow]( items: Items[F] ) extends Http4sDsl[F] { private[admin] val prefixPath = "/items" private val httpRoutes: AuthedRoutes[AdminUser, F] = AuthedRoutes.of { // Create new item case ar @ POST -> Root as _ => ar.req.decodeR[CreateItemParam] { item => Created(items.create(item.toDomain)) } // Update price of item case ar @ PUT -> Root as _ => ar.req.decodeR[UpdateItemParam] { item => Ok(items.update(item.toDomain)) } } def routes(authMiddleware: AuthMiddleware[F, AdminUser]): HttpRoutes[F] = Router( prefixPath -> authMiddleware(httpRoutes) ) }
Example 11
Source File: LogoutRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes import cats._ import cats.implicits._ import dev.profunktor.auth.AuthHeaders import org.http4s._ import org.http4s.dsl.Http4sDsl import org.http4s.server._ import shop.algebras.Auth import shop.http.auth.users._ final class LogoutRoutes[F[_]: Defer: Monad]( auth: Auth[F] ) extends Http4sDsl[F] { private[routes] val prefixPath = "/auth" private val httpRoutes: AuthedRoutes[CommonUser, F] = AuthedRoutes.of { case ar @ POST -> Root / "logout" as user => AuthHeaders .getBearerToken(ar.req) .traverse_(t => auth.logout(t, user.value.name)) *> NoContent() } def routes(authMiddleware: AuthMiddleware[F, CommonUser]): HttpRoutes[F] = Router( prefixPath -> authMiddleware(httpRoutes) ) }
Example 12
Source File: AuthExampleApp.scala From caliban with Apache License 2.0 | 5 votes |
package caliban.http4s import caliban.GraphQL._ import caliban.schema.GenericSchema import caliban.{ Http4sAdapter, RootResolver } import org.http4s.HttpRoutes import org.http4s.dsl.Http4sDsl import org.http4s.implicits._ import org.http4s.server.blaze.BlazeServerBuilder import org.http4s.server.{ Router, ServiceErrorHandler } import org.http4s.util.CaseInsensitiveString import zio._ import zio.interop.catz._ import zio.interop.catz.implicits._ import scala.concurrent.ExecutionContext object AuthExampleApp extends CatsApp { // Simple service that returns the token coming from the request type Auth = Has[Auth.Service] object Auth { trait Service { def token: String } } type AuthTask[A] = RIO[Auth, A] case class MissingToken() extends Throwable // http4s middleware that extracts a token from the request and eliminate the Auth layer dependency object AuthMiddleware { def apply(route: HttpRoutes[AuthTask]): HttpRoutes[Task] = Http4sAdapter.provideLayerFromRequest( route, _.headers.get(CaseInsensitiveString("token")) match { case Some(value) => ZLayer.succeed(new Auth.Service { override def token: String = value.value }) case None => ZLayer.fail(MissingToken()) } ) } // http4s error handler to customize the response for our throwable object dsl extends Http4sDsl[Task] import dsl._ val errorHandler: ServiceErrorHandler[Task] = _ => { case MissingToken() => Forbidden() } // our GraphQL API val schema: GenericSchema[Auth] = new GenericSchema[Auth] {} import schema._ case class Query(token: RIO[Auth, String]) private val resolver = RootResolver(Query(ZIO.access[Auth](_.get[Auth.Service].token))) private val api = graphQL(resolver) override def run(args: List[String]): ZIO[ZEnv, Nothing, ExitCode] = (for { interpreter <- api.interpreter route = AuthMiddleware(Http4sAdapter.makeHttpService(interpreter)) _ <- BlazeServerBuilder[Task](ExecutionContext.global) .withServiceErrorHandler(errorHandler) .bindHttp(8088, "localhost") .withHttpApp(Router[Task]("/api/graphql" -> route).orNotFound) .resource .toManaged .useForever } yield ()).exitCode }
Example 13
Source File: AirlinesHttpEndpoint.scala From core with Apache License 2.0 | 5 votes |
package com.smartbackpackerapp.http import cats.Monad import cats.syntax.flatMap._ import cats.syntax.functor._ import com.smartbackpackerapp.model.AirlineName import com.smartbackpackerapp.service.AirlineService import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s._ import org.http4s.circe._ import org.http4s.dsl.Http4sDsl class AirlinesHttpEndpoint[F[_] : Monad](airlineService: AirlineService[F]) (implicit handler: HttpErrorHandler[F]) extends Http4sDsl[F] { object AirlineNameQueryParamMatcher extends QueryParamDecoderMatcher[String]("name") val service: AuthedService[String, F] = AuthedService { case GET -> Root / ApiVersion / "airlines" :? AirlineNameQueryParamMatcher(airline) as _ => for { policy <- airlineService.baggagePolicy(AirlineName(airline)) response <- policy.fold(handler.handle, x => Ok(x.asJson)) } yield response } }
Example 14
Source File: HealthInfoHttpEndpoint.scala From core with Apache License 2.0 | 5 votes |
package com.smartbackpackerapp.http import cats.Monad import cats.syntax.flatMap._ import cats.syntax.functor._ import com.smartbackpackerapp.model.CountryCode import com.smartbackpackerapp.service.HealthService import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s._ import org.http4s.circe._ import org.http4s.dsl.Http4sDsl class HealthInfoHttpEndpoint[F[_] : Monad](healthService: HealthService[F]) (implicit handler: HttpErrorHandler[F]) extends Http4sDsl[F] { val service: AuthedService[String, F] = AuthedService { case GET -> Root / ApiVersion / "health" / countryCode as _ => for { healthInfo <- healthService.findHealthInfo(CountryCode(countryCode)) response <- healthInfo.fold(handler.handle, x => Ok(x.asJson)) } yield response } }
Example 15
Source File: VisaRestrictionIndexHttpEndpoint.scala From core with Apache License 2.0 | 5 votes |
package com.smartbackpackerapp.http import cats.Monad import cats.syntax.flatMap._ import cats.syntax.functor._ import com.smartbackpackerapp.model.CountryCode import com.smartbackpackerapp.service.VisaRestrictionIndexService import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s._ import org.http4s.circe._ import org.http4s.dsl.Http4sDsl class VisaRestrictionIndexHttpEndpoint[F[_] : Monad](visaRestrictionIndexService: VisaRestrictionIndexService[F]) (implicit handler: HttpErrorHandler[F]) extends Http4sDsl[F] { val service: AuthedService[String, F] = AuthedService { case GET -> Root / ApiVersion / "ranking" / countryCode as _ => for { index <- visaRestrictionIndexService.findIndex(CountryCode(countryCode)) response <- index.fold(handler.handle, x => Ok(x.asJson)) } yield response } }
Example 16
Source File: DestinationInfoHttpEndpoint.scala From core with Apache License 2.0 | 5 votes |
package com.smartbackpackerapp.http import cats.Monad import cats.syntax.flatMap._ import cats.syntax.functor._ import com.smartbackpackerapp.model.{CountryCode, Currency} import com.smartbackpackerapp.service.DestinationInfoService import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s._ import org.http4s.circe._ import org.http4s.dsl.Http4sDsl class DestinationInfoHttpEndpoint[F[_] : Monad](destinationInfoService: DestinationInfoService[F]) (implicit handler: HttpErrorHandler[F]) extends Http4sDsl[F] { object BaseCurrencyQueryParamMatcher extends QueryParamDecoderMatcher[String]("baseCurrency") val service: AuthedService[String, F] = AuthedService { case GET -> Root / ApiVersion / "traveling" / from / "to" / to :? BaseCurrencyQueryParamMatcher(baseCurrency) as _ => for { info <- destinationInfoService.find(CountryCode(from), CountryCode(to), Currency(baseCurrency)) response <- info.fold(handler.handle, x => Ok(x.asJson)) } yield response } }
Example 17
Source File: JwtTokenAuthMiddleware.scala From core with Apache License 2.0 | 5 votes |
package com.smartbackpackerapp.http.auth import cats.data.{EitherT, Kleisli, OptionT} import cats.effect.Sync import cats.syntax.applicativeError._ import cats.syntax.functor._ import com.smartbackpackerapp.http.auth.JwtTokenAuthMiddleware.AuthConfig import org.http4s.Credentials.Token import org.http4s.dsl.Http4sDsl import org.http4s.{AuthScheme, AuthedService, Request} import org.http4s.headers.Authorization import org.http4s.server.AuthMiddleware import tsec.jws.mac.JWTMac import tsec.mac.imports._ object JwtTokenAuthMiddleware { def apply[F[_] : Sync](apiToken: Option[String]): F[AuthMiddleware[F, String]] = new Middleware[F](apiToken).middleware case class AuthConfig(jwtKey: MacSigningKey[HMACSHA256]) } class Middleware[F[_]](apiToken: Option[String])(implicit F: Sync[F]) { private val ifEmpty = F.raiseError[AuthMiddleware[F, String]](new Exception("Api Token not found")) private def generateJwtKey(token: String): F[MacSigningKey[HMACSHA256]] = { F.catchNonFatal(HMACSHA256.buildKeyUnsafe(token.getBytes)) } val middleware: F[AuthMiddleware[F, String]] = apiToken.fold(ifEmpty) { token => generateJwtKey(token).map { jwtKey => val config = AuthConfig(jwtKey) new JwtTokenAuthMiddleware[F](config).middleware } } } class JwtTokenAuthMiddleware[F[_] : Sync](config: AuthConfig) extends Http4sDsl[F] { private val onFailure: AuthedService[String, F] = Kleisli(req => OptionT.liftF(Forbidden(req.authInfo))) private def bearerTokenFromRequest(request: Request[F]): OptionT[F, String] = OptionT.fromOption[F] { request.headers.get(Authorization).collect { case Authorization(Token(AuthScheme.Bearer, token)) => token } } private def verifyToken(request: Request[F], jwtKey: MacSigningKey[HMACSHA256]): OptionT[F, String] = for { token <- bearerTokenFromRequest(request) verified <- OptionT.liftF(JWTMac.verifyAndParse[F, HMACSHA256](token, jwtKey)) accessToken <- OptionT.fromOption[F](verified.body.subject) } yield accessToken private def authUser(jwtKey: MacSigningKey[HMACSHA256]): Kleisli[F, Request[F], Either[String, String]] = Kleisli { request => verifyToken(request, jwtKey).value.map { option => Either.cond[String, String](option.isDefined, option.get, "Unable to authorize token") }.recoverWith { case MacVerificationError(msg) => EitherT.leftT(msg).value } } def middleware: AuthMiddleware[F, String] = AuthMiddleware(authUser(config.jwtKey), onFailure) }
Example 18
Source File: LoginTest.scala From scala-pet-store with Apache License 2.0 | 5 votes |
package io.github.pauljamescleary.petstore package infrastructure.endpoint import cats.data.Kleisli import cats.effect.IO import domain.authentication.{LoginRequest, SignupRequest} import domain.users.{Role, User} import org.http4s.circe.{jsonEncoderOf, jsonOf} import org.http4s.client.dsl.Http4sClientDsl import org.http4s.{EntityDecoder, EntityEncoder, HttpApp, Request, Response} import org.http4s.implicits._ import org.http4s.headers.Authorization import io.circe.generic.auto._ import org.http4s.dsl.Http4sDsl trait LoginTest extends Http4sClientDsl[IO] with Http4sDsl[IO] { implicit val userEnc: EntityEncoder[IO, User] = jsonEncoderOf implicit val userDec: EntityDecoder[IO, User] = jsonOf implicit val signUpRequestEnc: EntityEncoder[IO, SignupRequest] = jsonEncoderOf implicit val signUpRequestDec: EntityDecoder[IO, SignupRequest] = jsonOf implicit val loginRequestEnc: EntityEncoder[IO, LoginRequest] = jsonEncoderOf implicit val loginRequestDec: EntityDecoder[IO, LoginRequest] = jsonOf def signUpAndLogIn( userSignUp: SignupRequest, userEndpoint: HttpApp[IO], ): IO[(User, Option[Authorization])] = for { signUpRq <- POST(userSignUp, uri"/users") signUpResp <- userEndpoint.run(signUpRq) user <- signUpResp.as[User] loginBody = LoginRequest(userSignUp.userName, userSignUp.password) loginRq <- POST(loginBody, uri"/users/login") loginResp <- userEndpoint.run(loginRq) } yield { user -> loginResp.headers.get(Authorization) } def signUpAndLogInAsAdmin( userSignUp: SignupRequest, userEndpoint: Kleisli[IO, Request[IO], Response[IO]], ): IO[(User, Option[Authorization])] = signUpAndLogIn(userSignUp.copy(role = Role.Admin), userEndpoint) def signUpAndLogInAsCustomer( userSignUp: SignupRequest, userEndpoint: Kleisli[IO, Request[IO], Response[IO]], ): IO[(User, Option[Authorization])] = signUpAndLogIn(userSignUp.copy(role = Role.Customer), userEndpoint) }
Example 19
Source File: OrderEndpoints.scala From scala-pet-store with Apache License 2.0 | 5 votes |
package io.github.pauljamescleary.petstore package infrastructure.endpoint import cats.effect.Sync import cats.implicits._ import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s._ import org.http4s.circe._ import org.http4s.dsl.Http4sDsl import domain.OrderNotFoundError import domain.authentication.Auth import domain.orders.{Order, OrderService} import io.github.pauljamescleary.petstore.domain.users.User import tsec.authentication.{AugmentedJWT, SecuredRequestHandler, asAuthed} import tsec.jwt.algorithms.JWTMacAlgo class OrderEndpoints[F[_]: Sync, Auth: JWTMacAlgo] extends Http4sDsl[F] { implicit val orderDecoder: EntityDecoder[F, Order] = jsonOf private def placeOrderEndpoint(orderService: OrderService[F]): AuthEndpoint[F, Auth] = { case req @ POST -> Root asAuthed user => for { order <- req.request .as[Order] .map(_.copy(userId = user.id)) saved <- orderService.placeOrder(order) resp <- Ok(saved.asJson) } yield resp } private def getOrderEndpoint(orderService: OrderService[F]): AuthEndpoint[F, Auth] = { case GET -> Root / LongVar(id) asAuthed _ => orderService.get(id).value.flatMap { case Right(found) => Ok(found.asJson) case Left(OrderNotFoundError) => NotFound("The order was not found") } } private def deleteOrderEndpoint(orderService: OrderService[F]): AuthEndpoint[F, Auth] = { case DELETE -> Root / LongVar(id) asAuthed _ => for { _ <- orderService.delete(id) resp <- Ok() } yield resp } def endpoints( orderService: OrderService[F], auth: SecuredRequestHandler[F, Long, User, AugmentedJWT[Auth, Long]], ): HttpRoutes[F] = { val authEndpoints: AuthService[F, Auth] = Auth.allRolesHandler(placeOrderEndpoint(orderService).orElse(getOrderEndpoint(orderService))) { Auth.adminOnly(deleteOrderEndpoint(orderService)) } auth.liftService(authEndpoints) } } object OrderEndpoints { def endpoints[F[_]: Sync, Auth: JWTMacAlgo]( orderService: OrderService[F], auth: SecuredRequestHandler[F, Long, User, AugmentedJWT[Auth, Long]], ): HttpRoutes[F] = new OrderEndpoints[F, Auth].endpoints(orderService, auth) }
Example 20
Source File: HealthCheckRoutes.scala From http4s-poc-api with MIT License | 5 votes |
package server import cats.effect.Sync import log.effect.LogWriter import model.DomainModel._ import org.http4s.dsl.Http4sDsl import org.http4s.{EntityEncoder, HttpRoutes, Method} import cats.syntax.flatMap._ sealed abstract class HealthCheckRoutes[F[_]: Sync]( implicit responseEncoder: EntityEncoder[F, ServiceSignature] ) extends Http4sDsl[F] { def make(log: LogWriter[F]): HttpRoutes[F] = HttpRoutes.of[F] { case Method.GET -> Root => log.debug(s"Serving HealthCheck request") >> Ok(serviceSignature) } private val serviceSignature = ServiceSignature( name = BuildInfo.name, version = BuildInfo.version, scalaVersion = BuildInfo.scalaVersion, scalaOrganization = BuildInfo.scalaOrganization, buildTime = BuildInfo.buildTime ) } object HealthCheckRoutes { def apply[F[_]: Sync: EntityEncoder[*[_], ServiceSignature]]: HealthCheckRoutes[F] = new HealthCheckRoutes[F] {} }
Example 21
Source File: CorrelationIdMiddlewareTest.scala From scala-server-toolkit with MIT License | 5 votes |
package com.avast.sst.http4s.server.middleware import java.net.InetSocketAddress import cats.effect.{ContextShift, IO, Resource, Timer} import com.avast.sst.http4s.server.Http4sRouting import org.http4s.client.blaze.BlazeClientBuilder import org.http4s.dsl.Http4sDsl import org.http4s.server.blaze.BlazeServerBuilder import org.http4s.util.CaseInsensitiveString import org.http4s.{Header, HttpRoutes, Request, Uri} import org.scalatest.funsuite.AsyncFunSuite import scala.concurrent.ExecutionContext @SuppressWarnings(Array("scalafix:Disable.get", "scalafix:Disable.toString", "scalafix:Disable.createUnresolved")) class CorrelationIdMiddlewareTest extends AsyncFunSuite with Http4sDsl[IO] { implicit private val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global) implicit private val timer: Timer[IO] = IO.timer(ExecutionContext.global) test("CorrelationIdMiddleware fills Request attributes and HTTP response header") { val test = for { middleware <- Resource.liftF(CorrelationIdMiddleware.default[IO]) routes = Http4sRouting.make { middleware.wrap { HttpRoutes.of[IO] { case req @ GET -> Root / "test" => val id = middleware.retrieveCorrelationId(req) Ok("test").map(_.withHeaders(Header("Attribute-Value", id.toString))) } } } server <- BlazeServerBuilder[IO](ExecutionContext.global) .bindSocketAddress(InetSocketAddress.createUnresolved("127.0.0.1", 0)) .withHttpApp(routes) .resource client <- BlazeClientBuilder[IO](ExecutionContext.global).resource } yield (server, client) test .use { case (server, client) => client .run( Request[IO](uri = Uri.unsafeFromString(s"http://${server.address.getHostString}:${server.address.getPort}/test")) .withHeaders(Header("Correlation-Id", "test-value")) ) .use { response => IO.delay { assert(response.headers.get(CaseInsensitiveString("Correlation-Id")).get.value === "test-value") assert(response.headers.get(CaseInsensitiveString("Attribute-Value")).get.value === "Some(CorrelationId(test-value))") } } } .unsafeToFuture() } }
Example 22
Source File: Http4sBlazeServerModuleTest.scala From scala-server-toolkit with MIT License | 5 votes |
package com.avast.sst.http4s.server import cats.effect.{ContextShift, IO, Timer} import com.avast.sst.http4s.client.{Http4sBlazeClientConfig, Http4sBlazeClientModule} import org.http4s.HttpRoutes import org.http4s.dsl.Http4sDsl import org.scalatest.funsuite.AsyncFunSuite import scala.concurrent.ExecutionContext class Http4sBlazeServerModuleTest extends AsyncFunSuite with Http4sDsl[IO] { implicit private val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global) implicit private val timer: Timer[IO] = IO.timer(ExecutionContext.global) test("Simple HTTP server") { val routes = Http4sRouting.make(HttpRoutes.of[IO] { case GET -> Root / "test" => Ok("test") }) val test = for { server <- Http4sBlazeServerModule.make[IO](Http4sBlazeServerConfig("127.0.0.1", 0), routes, ExecutionContext.global) client <- Http4sBlazeClientModule.make[IO](Http4sBlazeClientConfig(), ExecutionContext.global) } yield (server, client) test .use { case (server, client) => client .expect[String](s"http://${server.address.getHostString}:${server.address.getPort}/test") .map(response => assert(response === "test")) } .unsafeToFuture() } }
Example 23
Source File: Http4sRoutingModule.scala From scala-server-toolkit with MIT License | 5 votes |
package com.avast.sst.example.module import cats.implicits._ import com.avast.sst.example.service.RandomService import com.avast.sst.http4s.server.Http4sRouting import com.avast.sst.http4s.server.micrometer.MicrometerHttp4sServerMetricsModule import org.http4s.client.Client import org.http4s.dsl.Http4sDsl import org.http4s.{HttpApp, HttpRoutes} import zio.Task import zio.interop.catz._ class Http4sRoutingModule( randomService: RandomService, client: Client[Task], serverMetricsModule: MicrometerHttp4sServerMetricsModule[Task] ) extends Http4sDsl[Task] { import serverMetricsModule._ private val helloWorldRoute = routeMetrics.wrap("hello")(Ok("Hello World!")) private val routes = HttpRoutes.of[Task] { case GET -> Root / "hello" => helloWorldRoute case GET -> Root / "random" => randomService.randomNumber.map(_.show).flatMap(Ok(_)) case GET -> Root / "circuit-breaker" => client.expect[String]("https://httpbin.org/status/500").flatMap(Ok(_)) } val router: HttpApp[Task] = Http4sRouting.make { serverMetrics { routes } } }
Example 24
Source File: PushEvents.scala From event-sourcing-kafka-streams with MIT License | 5 votes |
package org.amitayh.invoices.web import java.util.UUID import cats.effect._ import fs2.concurrent.Topic import io.circe.generic.auto._ import io.circe.syntax._ import org.amitayh.invoices.common.domain.{CommandResult, InvoiceSnapshot} import org.amitayh.invoices.dao.InvoiceRecord import org.amitayh.invoices.web.PushEvents._ import org.http4s.dsl.Http4sDsl import org.http4s.{HttpRoutes, ServerSentEvent} class PushEvents[F[_]: Concurrent] extends Http4sDsl[F] { private val maxQueued = 16 def service(commandResultsTopic: Topic[F, CommandResultRecord], invoiceUpdatesTopic: Topic[F, InvoiceSnapshotRecord]): HttpRoutes[F] = HttpRoutes.of[F] { case GET -> Root / UuidVar(originId) => val commandResults = commandResultsTopic.subscribe(maxQueued).collect { case Some((_, result)) if result.originId == originId => Event(result).asServerSentEvent } val invoiceUpdates = invoiceUpdatesTopic.subscribe(maxQueued).collect { case Some((id, snapshot)) => Event(id, snapshot).asServerSentEvent } Ok(commandResults merge invoiceUpdates) } } object PushEvents { type CommandResultRecord = Option[(UUID, CommandResult)] type InvoiceSnapshotRecord = Option[(UUID, InvoiceSnapshot)] def apply[F[_]: Concurrent]: PushEvents[F] = new PushEvents[F] } sealed trait Event { def asServerSentEvent: ServerSentEvent = ServerSentEvent(this.asJson.noSpaces) } case class CommandSucceeded(commandId: UUID) extends Event case class CommandFailed(commandId: UUID, cause: String) extends Event case class InvoiceUpdated(record: InvoiceRecord) extends Event object Event { def apply(result: CommandResult): Event = result match { case CommandResult(_, commandId, _: CommandResult.Success) => CommandSucceeded(commandId) case CommandResult(_, commandId, CommandResult.Failure(cause)) => CommandFailed(commandId, cause.message) } def apply(id: UUID, snapshot: InvoiceSnapshot): Event = InvoiceUpdated(InvoiceRecord(id, snapshot)) }
Example 25
Source File: Statics.scala From event-sourcing-kafka-streams with MIT License | 5 votes |
package org.amitayh.invoices.web import cats.effect.{ContextShift, Sync} import org.http4s.dsl.Http4sDsl import org.http4s.{HttpRoutes, StaticFile} import scala.concurrent.ExecutionContext.global class Statics[F[_]: Sync: ContextShift] extends Http4sDsl[F] { val service: HttpRoutes[F] = HttpRoutes.of[F] { case request @ GET -> fileName => StaticFile .fromResource( name = s"/statics$fileName", blockingExecutionContext = global, req = Some(request), preferGzipped = true) .getOrElseF(NotFound()) } } object Statics { def apply[F[_]: Sync: ContextShift]: Statics[F] = new Statics[F] }
Example 26
Source File: InvoicesApi.scala From event-sourcing-kafka-streams with MIT License | 5 votes |
package org.amitayh.invoices.web import java.util.UUID import cats.effect.{Concurrent, Timer} import cats.implicits._ import fs2.Stream import fs2.concurrent.Topic import io.circe._ import io.circe.generic.auto._ import io.circe.syntax._ import org.amitayh.invoices.common.domain.CommandResult.{Failure, Success} import org.amitayh.invoices.common.domain.{Command, CommandResult} import org.amitayh.invoices.dao.InvoiceList import org.amitayh.invoices.web.CommandDto._ import org.amitayh.invoices.web.PushEvents.CommandResultRecord import org.http4s.circe._ import org.http4s.dsl.Http4sDsl import org.http4s.{EntityDecoder, HttpRoutes, Response} import scala.concurrent.duration._ class InvoicesApi[F[_]: Concurrent: Timer] extends Http4sDsl[F] { private val maxQueued = 16 implicit val commandEntityDecoder: EntityDecoder[F, Command] = jsonOf[F, Command] def service(invoiceList: InvoiceList[F], producer: Kafka.Producer[F, UUID, Command], commandResultsTopic: Topic[F, CommandResultRecord]): HttpRoutes[F] = HttpRoutes.of[F] { case GET -> Root / "invoices" => invoiceList.get.flatMap(invoices => Ok(invoices.asJson)) case request @ POST -> Root / "execute" / "async" / UuidVar(invoiceId) => request .as[Command] .flatMap(producer.send(invoiceId, _)) .flatMap(metaData => Accepted(Json.fromLong(metaData.timestamp))) case request @ POST -> Root / "execute" / UuidVar(invoiceId) => request.as[Command].flatMap { command => val response = resultStream(commandResultsTopic, command.commandId) merge timeoutStream producer.send(invoiceId, command) *> response.head.compile.toList.map(_.head) } } private def resultStream(commandResultsTopic: Topic[F, CommandResultRecord], commandId: UUID): Stream[F, Response[F]] = commandResultsTopic.subscribe(maxQueued).collectFirst { case Some((_, CommandResult(_, `commandId`, outcome))) => outcome }.flatMap { case Success(_, _, snapshot) => Stream.eval(Ok(snapshot.asJson)) case Failure(cause) => Stream.eval(UnprocessableEntity(cause.message)) } private def timeoutStream: Stream[F, Response[F]] = Stream.eval(Timer[F].sleep(5.seconds) *> RequestTimeout("timeout")) } object InvoicesApi { def apply[F[_]: Concurrent: Timer]: InvoicesApi[F] = new InvoicesApi[F] }
Example 27
Source File: SwaggerHttp4s.scala From tapir with Apache License 2.0 | 5 votes |
package sttp.tapir.swagger.http4s import java.util.Properties import cats.effect.{Blocker, ContextShift, Sync} import org.http4s.{HttpRoutes, StaticFile, Uri} import org.http4s.dsl.Http4sDsl import org.http4s.headers.Location import scala.concurrent.ExecutionContext class SwaggerHttp4s( yaml: String, contextPath: String = "docs", yamlName: String = "docs.yaml", redirectQuery: Map[String, Seq[String]] = Map.empty ) { private val swaggerVersion = { val p = new Properties() val pomProperties = getClass.getResourceAsStream("/META-INF/maven/org.webjars/swagger-ui/pom.properties") try p.load(pomProperties) finally pomProperties.close() p.getProperty("version") } def routes[F[_]: ContextShift: Sync]: HttpRoutes[F] = { val dsl = Http4sDsl[F] import dsl._ HttpRoutes.of[F] { case path @ GET -> Root / `contextPath` => val queryParameters = Map("url" -> Seq(s"${path.uri}/$yamlName")) ++ redirectQuery Uri .fromString(s"${path.uri}/index.html") .map(uri => uri.setQueryParams(queryParameters)) .map(uri => PermanentRedirect(Location(uri))) .getOrElse(NotFound()) case GET -> Root / `contextPath` / `yamlName` => Ok(yaml) case GET -> Root / `contextPath` / swaggerResource => StaticFile .fromResource( s"/META-INF/resources/webjars/swagger-ui/$swaggerVersion/$swaggerResource", Blocker.liftExecutionContext(ExecutionContext.global) ) .getOrElseF(NotFound()) } } }
Example 28
Source File: RedocHttp4s.scala From tapir with Apache License 2.0 | 5 votes |
package sttp.tapir.redoc.http4s import cats.effect.{ContextShift, Sync} import org.http4s.dsl.Http4sDsl import org.http4s.headers._ import org.http4s.{Charset, HttpRoutes, MediaType} import scala.io.Source class RedocHttp4s(title: String, yaml: String, yamlName: String = "docs.yaml") { private lazy val html = { val fileName = "redoc.html" val is = getClass.getClassLoader.getResourceAsStream(fileName) assert(Option(is).nonEmpty, s"Could not find file ${fileName} on classpath.") val rawHtml = Source.fromInputStream(is).mkString // very poor man's templating engine rawHtml.replaceAllLiterally("{{docsPath}}", yamlName).replaceAllLiterally("{{title}}", title) } def routes[F[_]: ContextShift: Sync]: HttpRoutes[F] = { val dsl = Http4sDsl[F] import dsl._ HttpRoutes.of[F] { case req @ GET -> Root if req.pathInfo.endsWith("/") => Ok(html, `Content-Type`(MediaType.text.html, Charset.`UTF-8`)) // as the url to the yaml file is relative, it is important that there is a trailing slash case req @ GET -> Root => val uri = req.uri PermanentRedirect(Location(uri.withPath(uri.path.concat("/")))) case GET -> Root / `yamlName` => Ok(yaml, `Content-Type`(MediaType.text.yaml, Charset.`UTF-8`)) } } }
Example 29
Source File: PriceRoutes.scala From http4s-poc-api with MIT License | 5 votes |
package server import cats.effect.Sync import cats.syntax.applicativeError._ import cats.syntax.flatMap._ import cats.syntax.functor._ import cats.syntax.show._ import errors.PriceServiceError import errors.PriceServiceError._ import external.library.syntax.response._ import model.DomainModel._ import org.http4s.dsl.Http4sDsl import org.http4s.{EntityDecoder, EntityEncoder, HttpRoutes, Method, Request, Response} import service.PriceService sealed abstract class PriceRoutes[F[_]: Sync]( implicit requestDecoder: EntityDecoder[F, PricesRequestPayload], responseEncoder: EntityEncoder[F, List[Price]] ) extends Http4sDsl[F] { def make(priceService: PriceService[F]): HttpRoutes[F] = HttpRoutes.of[F] { case req @ Method.POST -> Root => postResponse(req, priceService) handlingFailures priceServiceErrors handleErrorWith unhandledThrowable } private[this] def postResponse(request: Request[F], priceService: PriceService[F]): F[Response[F]] = for { payload <- request.as[PricesRequestPayload] prices <- priceService.prices(payload.userId, payload.productIds) resp <- Ok(prices) } yield resp private[this] def priceServiceErrors: PriceServiceError => F[Response[F]] = { case UserErr(r) => FailedDependency(r) case PreferenceErr(r) => FailedDependency(r) case ProductErr(r) => FailedDependency(r) case ProductPriceErr(r) => FailedDependency(r) case CacheLookupError(r) => FailedDependency(r) case CacheStoreError(r) => FailedDependency(r) case InvalidShippingCountry(r) => BadRequest(r) } private[this] def unhandledThrowable: Throwable => F[Response[F]] = { th => import external.library.instances.throwable._ InternalServerError(th.show) } } object PriceRoutes { def apply[ F[_]: Sync: EntityDecoder[*[_], PricesRequestPayload]: EntityEncoder[*[_], List[Price]] ]: PriceRoutes[F] = new PriceRoutes[F] {} }
Example 30
Source File: SagaEndpoint.scala From zio-saga with MIT License | 5 votes |
package com.vladkopanev.zio.saga.example.endpoint import com.vladkopanev.zio.saga.example.{ OrderSagaCoordinator, TaskC } import com.vladkopanev.zio.saga.example.model.OrderInfo import org.http4s.circe._ import org.http4s.dsl.Http4sDsl import org.http4s.implicits._ import org.http4s.{ HttpApp, HttpRoutes } import zio.interop.catz._ final class SagaEndpoint(orderSagaCoordinator: OrderSagaCoordinator) extends Http4sDsl[TaskC] { private implicit val decoder = jsonOf[TaskC, OrderInfo] val service: HttpApp[TaskC] = HttpRoutes .of[TaskC] { case req @ POST -> Root / "saga" / "finishOrder" => for { OrderInfo(userId, orderId, money, bonuses) <- req.as[OrderInfo] resp <- orderSagaCoordinator .runSaga(userId, orderId, money, bonuses, None) .foldM(fail => InternalServerError(fail.getMessage), _ => Ok("Saga submitted")) } yield resp } .orNotFound }
Example 31
Source File: BidderHttpAppBuilder.scala From scala-openrtb with Apache License 2.0 | 5 votes |
package com.powerspace.openrtb.examples.rtb.http4s.bidder import com.google.openrtb.BidRequest import com.powerspace.openrtb.examples.rtb.http4s.common.ExampleSerdeModule import io.circe.Decoder import monix.eval.Task import org.http4s.dsl.Http4sDsl import org.http4s.{EntityDecoder, HttpApp} object BidderHttpAppBuilder { private val bidder = new Bidder[Task] private val dsl = Http4sDsl[Task] private val serdeModule = ExampleSerdeModule private def handleBid(bidRequest: BidRequest) = { import dsl._ import org.http4s.circe._ bidder .bidOn(bidRequest) .flatMap { case Some(bidResponse) => // encode the bidResponse to a json object as part of the http response body Ok(serdeModule.bidResponseEncoder(bidResponse)) case None => Ok() } } }
Example 32
Source File: StatusesService.scala From zio-telemetry with Apache License 2.0 | 5 votes |
package zio.telemetry.opentelemetry.example.http import io.circe.Encoder import io.opentelemetry.OpenTelemetry import io.opentelemetry.context.propagation.HttpTextFormat.Setter import io.opentelemetry.trace.{ Span, Status => TraceStatus } import org.http4s.circe.jsonEncoderOf import org.http4s.dsl.Http4sDsl import org.http4s.{ EntityEncoder, HttpRoutes } import zio.UIO import zio.interop.catz._ import zio.telemetry.opentelemetry.Tracing.root import zio.telemetry.opentelemetry.attributevalue.AttributeValueConverterInstances._ import zio.telemetry.opentelemetry.Tracing import scala.collection.mutable object StatusesService { val dsl: Http4sDsl[AppTask] = Http4sDsl[AppTask] import dsl._ implicit def encoder[A: Encoder]: EntityEncoder[AppTask, A] = jsonEncoderOf[AppTask, A] val httpTextFormat = OpenTelemetry.getPropagators.getHttpTextFormat val setter: Setter[mutable.Map[String, String]] = (carrier, key, value) => carrier.update(key, value) val errorMapper: PartialFunction[Throwable, TraceStatus] = { case _ => TraceStatus.UNKNOWN } val routes: HttpRoutes[AppTask] = HttpRoutes.of[AppTask] { case GET -> Root / "statuses" => root("/statuses", Span.Kind.SERVER, errorMapper) { for { carrier <- UIO(mutable.Map[String, String]().empty) _ <- Tracing.setAttribute("http.method", "get") _ <- Tracing.addEvent("proxy-event") _ <- Tracing.inject(httpTextFormat, carrier, setter) res <- Client.status(carrier.toMap).flatMap(Ok(_)) } yield res } } }
Example 33
Source File: StatusService.scala From zio-telemetry with Apache License 2.0 | 5 votes |
package zio.telemetry.opentelemetry.example.http import io.circe.Encoder import io.circe.syntax._ import io.opentelemetry.OpenTelemetry import io.opentelemetry.context.propagation.HttpTextFormat import io.opentelemetry.context.propagation.HttpTextFormat.Getter import io.opentelemetry.trace.Span import org.http4s._ import org.http4s.circe.jsonEncoderOf import org.http4s.dsl.Http4sDsl import org.http4s.util.CaseInsensitiveString import zio.interop.catz._ import zio.telemetry.opentelemetry.Tracing import zio.telemetry.opentelemetry.TracingSyntax._ import zio.telemetry.opentelemetry.example.http.{ Status => ServiceStatus } object StatusService { val dsl: Http4sDsl[AppTask] = Http4sDsl[AppTask] import dsl._ implicit def encoder[A: Encoder]: EntityEncoder[AppTask, A] = jsonEncoderOf[AppTask, A] val httpTextFormat: HttpTextFormat = OpenTelemetry.getPropagators.getHttpTextFormat val getter: Getter[Headers] = (carrier, key) => carrier.get(CaseInsensitiveString(key)).map(_.value).orNull val routes: HttpRoutes[AppTask] = HttpRoutes.of[AppTask] { case request @ GET -> Root / "status" => val response = for { _ <- Tracing.addEvent("event from backend before response") response <- Ok(ServiceStatus.up("backend").asJson) _ <- Tracing.addEvent("event from backend after response") } yield response response.spanFrom(httpTextFormat, request.headers, getter, "/status", Span.Kind.SERVER) } }
Example 34
Source File: StatusesService.scala From zio-telemetry with Apache License 2.0 | 5 votes |
package zio.telemetry.opentracing.example.http import io.circe.Encoder import io.opentracing.propagation.Format.Builtin.{ HTTP_HEADERS => HttpHeadersFormat } import io.opentracing.propagation.TextMapAdapter import io.opentracing.tag.Tags import org.http4s.circe.jsonEncoderOf import org.http4s.dsl.Http4sDsl import org.http4s.{ EntityEncoder, HttpRoutes } import sttp.model.Uri import zio.clock.Clock import zio.interop.catz._ import zio.telemetry.opentracing.OpenTracing import zio.UIO import zio.ZIO import zio.ZLayer import scala.collection.mutable import scala.jdk.CollectionConverters._ object StatusesService { def statuses(backendUri: Uri, service: ZLayer[Clock, Throwable, Clock with OpenTracing]): HttpRoutes[AppTask] = { val dsl: Http4sDsl[AppTask] = Http4sDsl[AppTask] import dsl._ implicit def encoder[A: Encoder]: EntityEncoder[AppTask, A] = jsonEncoderOf[AppTask, A] HttpRoutes.of[AppTask] { case GET -> Root / "statuses" => val zio = for { env <- ZIO.environment[OpenTracing] _ <- env.get.root("/statuses") _ <- OpenTracing.tag(Tags.SPAN_KIND.getKey, Tags.SPAN_KIND_CLIENT) _ <- OpenTracing.tag(Tags.HTTP_METHOD.getKey, GET.name) _ <- OpenTracing.setBaggageItem("proxy-baggage-item-key", "proxy-baggage-item-value") buffer <- UIO.succeed(new TextMapAdapter(mutable.Map.empty[String, String].asJava)) _ <- OpenTracing.inject(HttpHeadersFormat, buffer) headers <- extractHeaders(buffer) up = Status.up("proxy") res <- Client .status(backendUri.path("status"), headers) .map(_.body) .flatMap { case Right(s) => Ok(Statuses(List(s, up))) case _ => Ok(Statuses(List(Status.down("backend"), up))) } } yield res zio.provideLayer(service) } } private def extractHeaders(adapter: TextMapAdapter): UIO[Map[String, String]] = { val m = mutable.Map.empty[String, String] UIO(adapter.forEach { entry => m.put(entry.getKey, entry.getValue) () }).as(m.toMap) } }
Example 35
Source File: StatusService.scala From zio-telemetry with Apache License 2.0 | 5 votes |
package zio.telemetry.opentracing.example.http import io.circe.Encoder import io.circe.syntax._ import io.opentracing.propagation.Format.Builtin.{ HTTP_HEADERS => HttpHeadersFormat } import io.opentracing.propagation.TextMapAdapter import org.http4s._ import org.http4s.circe.jsonEncoderOf import org.http4s.dsl.Http4sDsl import zio.clock.Clock import zio.interop.catz._ import zio.telemetry.opentracing.example.http.{ Status => ServiceStatus } import zio.telemetry.opentracing._ import zio.ZIO import zio.ZLayer import scala.jdk.CollectionConverters._ object StatusService { val dsl: Http4sDsl[AppTask] = Http4sDsl[AppTask] import dsl._ implicit def encoder[A: Encoder]: EntityEncoder[AppTask, A] = jsonEncoderOf[AppTask, A] def status(service: ZLayer[Clock, Throwable, Clock with OpenTracing]): HttpRoutes[AppTask] = HttpRoutes.of[AppTask] { case request @ GET -> Root / "status" => val headers = request.headers.toList.map(h => h.name.value -> h.value).toMap ZIO.unit .spanFrom(HttpHeadersFormat, new TextMapAdapter(headers.asJava), "/status") .provideLayer(service) *> Ok(ServiceStatus.up("backend").asJson) } }
Example 36
Source File: decoder.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http import cats.implicits._ import io.circe.Decoder import org.http4s._ import org.http4s.dsl.Http4sDsl import org.http4s.circe._ import shop.effects._ object decoder { implicit class RefinedRequestDecoder[F[_]: JsonDecoder: MonadThrow](req: Request[F]) extends Http4sDsl[F] { def decodeR[A: Decoder](f: A => F[Response[F]]): F[Response[F]] = req.asJsonDecode[A].attempt.flatMap { case Left(e) => Option(e.getCause) match { case Some(c) if c.getMessage.startsWith("Predicate") => BadRequest(c.getMessage) case _ => UnprocessableEntity() } case Right(a) => f(a) } } }
Example 37
Source File: ItemRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes import cats._ import org.http4s._ import org.http4s.dsl.Http4sDsl import org.http4s.server.Router import shop.algebras.Items import shop.domain.brand._ import shop.http.json._ import shop.http.params._ final class ItemRoutes[F[_]: Defer: Monad]( items: Items[F] ) extends Http4sDsl[F] { private[routes] val prefixPath = "/items" object BrandQueryParam extends OptionalQueryParamDecoderMatcher[BrandParam]("brand") private val httpRoutes: HttpRoutes[F] = HttpRoutes.of[F] { case GET -> Root :? BrandQueryParam(brand) => Ok(brand.fold(items.findAll)(b => items.findBy(b.toDomain))) } val routes: HttpRoutes[F] = Router( prefixPath -> httpRoutes ) }
Example 38
Source File: LoginRoutes.scala From pfps-shopping-cart with Apache License 2.0 | 5 votes |
package shop.http.routes import cats._ import cats.implicits._ import org.http4s._ import org.http4s.circe.JsonDecoder import org.http4s.dsl.Http4sDsl import org.http4s.server.Router import shop.algebras.Auth import shop.domain.auth._ import shop.effects._ import shop.http.decoder._ import shop.http.json._ final class LoginRoutes[F[_]: Defer: JsonDecoder: MonadThrow]( auth: Auth[F] ) extends Http4sDsl[F] { private[routes] val prefixPath = "/auth" private val httpRoutes: HttpRoutes[F] = HttpRoutes.of[F] { case req @ POST -> Root / "login" => req.decodeR[LoginUser] { user => auth .login(user.username.toDomain, user.password.toDomain) .flatMap(Ok(_)) .recoverWith { case InvalidUserOrPassword(_) => Forbidden() } } } val routes: HttpRoutes[F] = Router( prefixPath -> httpRoutes ) }
Example 39
Source File: GenericApi.scala From freestyle with Apache License 2.0 | 5 votes |
package examples.todolist package http import cats.effect.Effect import cats.implicits._ import examples.todolist.model.Pong import freestyle.tagless.logging.LoggingM import io.circe.Json import org.http4s.circe._ import org.http4s.dsl.Http4sDsl import org.http4s.HttpService class GenericApi[F[_]: Effect](implicit log: LoggingM[F]) extends Http4sDsl[F] { val endpoints = HttpService[F] { case GET -> Root / "ping" => for { _ <- log.error("Not really an error") _ <- log.warn("Not really a warn") _ <- log.debug("GET /ping") response <- Ok(Json.fromLong(Pong.current.time)) } yield response case GET -> Root / "hello" => for { _ <- log.error("Not really an error") _ <- log.warn("Not really a warn") _ <- log.debug("GET /Hello") response <- Ok("Hello World") } yield response } } object GenericApi { implicit def instance[F[_]: Effect](implicit log: LoggingM[F]): GenericApi[F] = new GenericApi[F] }
Example 40
Source File: UserRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.common.Ident import docspell.restapi.model._ import docspell.restserver.conv.Conversions._ import docspell.restserver.http4s.ResponseGenerator import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object UserRoutes { def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = { val dsl = new Http4sDsl[F] with ResponseGenerator[F] {} import dsl._ HttpRoutes.of { case req @ POST -> Root / "changePassword" => for { data <- req.as[PasswordChange] res <- backend.collective.changePassword( user.account, data.currentPassword, data.newPassword ) resp <- Ok(basicResult(res)) } yield resp case GET -> Root => for { all <- backend.collective.listUser(user.account.collective) res <- Ok(UserList(all.map(mkUser).toList)) } yield res case req @ POST -> Root => for { data <- req.as[User] nuser <- newUser(data, user.account.collective) added <- backend.collective.add(nuser) resp <- Ok(basicResult(added, "User created.")) } yield resp case req @ PUT -> Root => for { data <- req.as[User] nuser = changeUser(data, user.account.collective) update <- backend.collective.update(nuser) resp <- Ok(basicResult(update, "User updated.")) } yield resp case DELETE -> Root / Ident(id) => for { ar <- backend.collective.deleteUser(id, user.account.collective) resp <- Ok(basicResult(ar, "User deleted.")) } yield resp } } }
Example 41
Source File: EquipmentRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.common.Ident import docspell.restapi.model._ import docspell.restserver.conv.Conversions._ import docspell.restserver.http4s.QueryParam import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object EquipmentRoutes { def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of { case GET -> Root :? QueryParam.QueryOpt(q) => for { data <- backend.equipment.findAll(user.account, q.map(_.q)) resp <- Ok(EquipmentList(data.map(mkEquipment).toList)) } yield resp case req @ POST -> Root => for { data <- req.as[Equipment] equip <- newEquipment(data, user.account.collective) res <- backend.equipment.add(equip) resp <- Ok(basicResult(res, "Equipment created")) } yield resp case req @ PUT -> Root => for { data <- req.as[Equipment] equip = changeEquipment(data, user.account.collective) res <- backend.equipment.update(equip) resp <- Ok(basicResult(res, "Equipment updated.")) } yield resp case DELETE -> Root / Ident(id) => for { del <- backend.equipment.delete(id, user.account.collective) resp <- Ok(basicResult(del, "Equipment deleted.")) } yield resp } } }
Example 42
Source File: CalEventCheckRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.common._ import docspell.restapi.model._ import com.github.eikek.calev.CalEvent import org.http4s._ import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object CalEventCheckRoutes { def apply[F[_]: Effect](): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of { case req @ POST -> Root => for { data <- req.as[CalEventCheck] res <- testEvent(data.event) resp <- Ok(res) } yield resp } } def testEvent[F[_]: Sync](str: String): F[CalEventCheckResult] = Timestamp.current[F].map { now => CalEvent.parse(str) match { case Right(ev) => val next = ev .nextElapses(now.toUtcDateTime, 2) .map(Timestamp.atUtc) CalEventCheckResult(true, "Valid.", ev.some, next) case Left(err) => CalEventCheckResult(false, err, None, Nil) } } }
Example 43
Source File: TagRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.common.Ident import docspell.restapi.model._ import docspell.restserver.conv.Conversions._ import docspell.restserver.http4s._ import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object TagRoutes { def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = { val dsl = new Http4sDsl[F] with ResponseGenerator[F] {} import dsl._ HttpRoutes.of { case GET -> Root :? QueryParam.QueryOpt(q) => for { all <- backend.tag.findAll(user.account, q.map(_.q)) resp <- Ok(TagList(all.size, all.map(mkTag).toList)) } yield resp case req @ POST -> Root => for { data <- req.as[Tag] tag <- newTag(data, user.account.collective) res <- backend.tag.add(tag) resp <- Ok(basicResult(res, "Tag successfully created.")) } yield resp case req @ PUT -> Root => for { data <- req.as[Tag] tag = changeTag(data, user.account.collective) res <- backend.tag.update(tag) resp <- Ok(basicResult(res, "Tag successfully updated.")) } yield resp case DELETE -> Root / Ident(id) => for { del <- backend.tag.delete(id, user.account.collective) resp <- Ok(basicResult(del, "Tag successfully deleted.")) } yield resp } } }
Example 44
Source File: UploadRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.common._ import docspell.restserver.Config import docspell.restserver.conv.Conversions._ import docspell.restserver.http4s.ResponseGenerator import org.http4s._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl import org.http4s.multipart.Multipart import org.log4s._ object UploadRoutes { private[this] val logger = getLogger def secured[F[_]: Effect]( backend: BackendApp[F], cfg: Config, user: AuthToken ): HttpRoutes[F] = { val dsl = new Http4sDsl[F] with ResponseGenerator[F] {} import dsl._ val submitting = submitFiles[F](backend, cfg, Right(user.account)) _ HttpRoutes.of { case req @ POST -> Root / "item" => submitting(req, None, Priority.High, dsl) case req @ POST -> Root / "item" / Ident(itemId) => submitting(req, Some(itemId), Priority.High, dsl) } } def open[F[_]: Effect](backend: BackendApp[F], cfg: Config): HttpRoutes[F] = { val dsl = new Http4sDsl[F] with ResponseGenerator[F] {} import dsl._ HttpRoutes.of { case req @ POST -> Root / "item" / Ident(id) => submitFiles(backend, cfg, Left(id))(req, None, Priority.Low, dsl) case req @ POST -> Root / "item" / Ident(itemId) / Ident(id) => submitFiles(backend, cfg, Left(id))(req, Some(itemId), Priority.Low, dsl) } } private def submitFiles[F[_]: Effect]( backend: BackendApp[F], cfg: Config, accOrSrc: Either[Ident, AccountId] )( req: Request[F], itemId: Option[Ident], prio: Priority, dsl: Http4sDsl[F] ): F[Response[F]] = { import dsl._ for { multipart <- req.as[Multipart[F]] updata <- readMultipart( multipart, logger, prio, cfg.backend.files.validMimeTypes ) result <- backend.upload.submitEither(updata, accOrSrc, true, itemId) res <- Ok(basicResult(result)) } yield res } }
Example 45
Source File: InfoRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect.Sync import docspell.restapi.model.VersionInfo import docspell.restserver.BuildInfo import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object InfoRoutes { def apply[F[_]: Sync](): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of[F] { case GET -> (Root / "version") => Ok( VersionInfo( BuildInfo.version, BuildInfo.builtAtMillis, BuildInfo.builtAtString, BuildInfo.gitHeadCommit.getOrElse(""), BuildInfo.gitDescribedVersion.getOrElse("") ) ) } } }
Example 46
Source File: ResponseGenerator.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.http4s import cats.Applicative import cats.implicits._ import org.http4s.dsl.Http4sDsl import org.http4s.{EntityEncoder, Header, Response} trait ResponseGenerator[F[_]] { self: Http4sDsl[F] => implicit final class EitherResponses[A, B](e: Either[A, B]) { def toResponse(headers: Header*)(implicit F: Applicative[F], w0: EntityEncoder[F, A], w1: EntityEncoder[F, B] ): F[Response[F]] = e.fold( a => UnprocessableEntity(a), b => Ok(b) ).map(_.withHeaders(headers: _*)) } implicit final class OptionResponse[A](o: Option[A]) { def toResponse( headers: Header* )(implicit F: Applicative[F], w0: EntityEncoder[F, A]): F[Response[F]] = o.map(a => Ok(a)).getOrElse(NotFound()).map(_.withHeaders(headers: _*)) } } object ResponseGenerator {}
Example 47
Source File: JoexRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.routes import cats.effect._ import cats.implicits._ import docspell.common.{Duration, Ident, Timestamp} import docspell.joex.JoexApp import docspell.joexapi.model._ import docspell.store.records.{RJob, RJobLog} import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object JoexRoutes { def apply[F[_]: ConcurrentEffect: Timer](app: JoexApp[F]): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of[F] { case POST -> Root / "notify" => for { _ <- app.scheduler.notifyChange _ <- app.periodicScheduler.notifyChange resp <- Ok(BasicResult(true, "Schedulers notified.")) } yield resp case GET -> Root / "running" => for { jobs <- app.scheduler.getRunning jj = jobs.map(mkJob) resp <- Ok(JobList(jj.toList)) } yield resp case POST -> Root / "shutdownAndExit" => for { _ <- ConcurrentEffect[F].start( Timer[F].sleep(Duration.seconds(1).toScala) *> app.initShutdown ) resp <- Ok(BasicResult(true, "Shutdown initiated.")) } yield resp case GET -> Root / "job" / Ident(id) => for { optJob <- app.scheduler.getRunning.map(_.find(_.id == id)) optLog <- optJob.traverse(j => app.findLogs(j.id)) jAndL = for { job <- optJob; log <- optLog } yield mkJobLog(job, log) resp <- jAndL.map(Ok(_)).getOrElse(NotFound(BasicResult(false, "Not found"))) } yield resp case POST -> Root / "job" / Ident(id) / "cancel" => for { flag <- app.scheduler.requestCancel(id) resp <- Ok( BasicResult(flag, if (flag) "Cancel request submitted" else "Job not found") ) } yield resp } } def mkJob(j: RJob): Job = Job( j.id, j.subject, j.submitted, j.priority, j.retries, j.progress, j.started.getOrElse(Timestamp.Epoch) ) def mkJobLog(j: RJob, jl: Vector[RJobLog]): JobAndLog = JobAndLog(mkJob(j), jl.map(r => JobLogEvent(r.created, r.level, r.message)).toList) }
Example 48
Source File: InfoRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.joex.routes import cats.effect.Sync import docspell.joex.BuildInfo import docspell.joexapi.model.VersionInfo import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object InfoRoutes { def apply[F[_]: Sync](): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of[F] { case GET -> (Root / "version") => Ok( VersionInfo( BuildInfo.version, BuildInfo.builtAtMillis, BuildInfo.builtAtString, BuildInfo.gitHeadCommit.getOrElse(""), BuildInfo.gitDescribedVersion.getOrElse("") ) ) } } }
Example 49
Source File: Authenticate.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.data._ import cats.effect._ import cats.implicits._ import docspell.backend.auth._ import docspell.restserver.auth._ import org.http4s._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl import org.http4s.server._ object Authenticate { def authenticateRequest[F[_]: Effect]( auth: String => F[Login.Result] )(req: Request[F]): F[Login.Result] = CookieData.authenticator(req) match { case Right(str) => auth(str) case Left(_) => Login.Result.invalidAuth.pure[F] } def of[F[_]: Effect](S: Login[F], cfg: Login.Config)( pf: PartialFunction[AuthedRequest[F, AuthToken], F[Response[F]]] ): HttpRoutes[F] = { val dsl: Http4sDsl[F] = new Http4sDsl[F] {} import dsl._ val authUser = getUser[F](S.loginSession(cfg)) val onFailure: AuthedRoutes[String, F] = Kleisli(req => OptionT.liftF(Forbidden(req.context))) val middleware: AuthMiddleware[F, AuthToken] = AuthMiddleware(authUser, onFailure) middleware(AuthedRoutes.of(pf)) } def apply[F[_]: Effect](S: Login[F], cfg: Login.Config)( f: AuthToken => HttpRoutes[F] ): HttpRoutes[F] = { val dsl: Http4sDsl[F] = new Http4sDsl[F] {} import dsl._ val authUser = getUser[F](S.loginSession(cfg)) val onFailure: AuthedRoutes[String, F] = Kleisli(req => OptionT.liftF(Forbidden(req.context))) val middleware: AuthMiddleware[F, AuthToken] = AuthMiddleware(authUser, onFailure) middleware(AuthedRoutes(authReq => f(authReq.context).run(authReq.req))) } private def getUser[F[_]: Effect]( auth: String => F[Login.Result] ): Kleisli[F, Request[F], Either[String, AuthToken]] = Kleisli(r => authenticateRequest(auth)(r).map(_.toEither)) }
Example 50
Source File: TodoListApi.scala From freestyle with Apache License 2.0 | 5 votes |
package examples.todolist package http import cats.effect.Effect import cats.implicits._ import examples.todolist.service.TodoListService import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s._ import org.http4s.circe._ import org.http4s.dsl.Http4sDsl class TodoListApi[F[_]: Effect](implicit service: TodoListService[F]) extends Http4sDsl[F] { import codecs._ private val prefix = "lists" val endpoints = HttpService[F] { case POST -> Root / prefix => service.reset.flatMap(e => Ok(e.asJson)) case GET -> Root / prefix / IntVar(id) => service.retrieve(id) flatMap { item => item.fold(NotFound(s"Could not find ${service.model} with $id"))(todoList => Ok(todoList.asJson)) } case GET -> Root / prefix => service.list.flatMap(l => Ok(l.asJson)) case req @ POST -> Root / prefix => for { todoList <- req.as[TodoList] insertedTodoList <- service.insert(todoList) response <- Ok(insertedTodoList.asJson) } yield response case req @ PUT -> Root / prefix / IntVar(id) => for { todoList <- req.as[TodoList] updatedTodoList <- service.update(todoList.copy(id = Some(id))) reponse <- Ok(updatedTodoList.asJson) } yield reponse case DELETE -> Root / prefix / IntVar(id) => service.destroy(id) *> Ok() } } object TodoListApi { implicit def instance[F[_]: Effect](implicit service: TodoListService[F]): TodoListApi[F] = new TodoListApi[F] }
Example 51
Source File: TagApi.scala From freestyle with Apache License 2.0 | 5 votes |
package examples.todolist package http import cats.effect.Effect import cats.implicits._ import examples.todolist.service.TagService import examples.todolist.Tag import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s._ import org.http4s.circe._ import org.http4s.dsl.Http4sDsl class TagApi[F[_]: Effect](implicit service: TagService[F]) extends Http4sDsl[F] { import codecs._ private val prefix = "tags" val endpoints = HttpService[F] { case POST -> Root / prefix / "reset" => service.reset.flatMap(e => Ok(e.asJson)) case GET -> Root / prefix / IntVar(id) => service.retrieve(id) flatMap { item => item.fold(NotFound(s"Could not find ${service.model} with $id"))(tag => Ok(tag.asJson)) } case GET -> Root / prefix => service.list.flatMap(l => Ok(l.asJson)) case req @ POST -> Root / prefix => for { tag <- req.as[Tag] insertedTag <- service.insert(tag) response <- Ok(insertedTag.asJson) } yield response case req @ PUT -> Root / prefix / IntVar(id) => for { tag <- req.as[Tag] updatedTag <- service.update(tag.copy(id = Some(id))) reponse <- Ok(updatedTag.asJson) } yield reponse case DELETE -> Root / prefix / IntVar(id) => service.destroy(id) *> Ok() } } object TagApi { implicit def instance[F[_]: Effect](implicit service: TagService[F]): TagApi[F] = new TagApi[F] }
Example 52
Source File: AppApi.scala From freestyle with Apache License 2.0 | 5 votes |
package examples.todolist package http import cats.effect.Effect import cats.implicits._ import examples.todolist.service.AppService import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s._ import org.http4s.circe._ import org.http4s.dsl.Http4sDsl class AppApi[F[_]: Effect](implicit service: AppService[F]) extends Http4sDsl[F] { import codecs._ val endpoints = HttpService[F] { case POST -> Root / "reset" => service.reset.flatMap(e => Ok(e.asJson)) case GET -> Root / "list" => service.list.flatMap(l => Ok(l.asJson)) case req @ POST -> Root / "insert" => for { form <- req.as[TodoForm] insertedForm <- service.insert(form) response <- Ok(insertedForm.asJson) } yield response case req @ PUT -> Root / "update" => for { form <- req.as[TodoForm] updatedForm <- service.update(form) response <- Ok(updatedForm.asJson) } yield response case req @ DELETE -> Root / "delete" => for { form <- req.as[TodoForm] deleted <- service.destroy(form) response <- Ok(deleted.asJson) } yield response } } object AppApi { implicit def instance[F[_]: Effect](implicit service: AppService[F]): AppApi[F] = new AppApi[F] }
Example 53
Source File: TodoItemApi.scala From freestyle with Apache License 2.0 | 5 votes |
package examples.todolist package http import cats.effect.Effect import cats.implicits._ import examples.todolist.service.TodoItemService import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s._ import org.http4s.circe._ import org.http4s.dsl.Http4sDsl class TodoItemApi[F[_]: Effect](implicit service: TodoItemService[F]) extends Http4sDsl[F] { import codecs._ private val prefix = "items" val endpoints = HttpService[F] { case POST -> Root / prefix => service.reset *> Ok() case GET -> Root / prefix / IntVar(id) => service.retrieve(id) flatMap { item => item.fold(NotFound(s"Could not find ${service.model} with $id"))(todoItem => Ok(todoItem.asJson)) } case GET -> Root / prefix => service.list.flatMap(l => Ok(l.asJson)) case req @ POST -> Root / prefix => for { todoItem <- req.as[TodoItem] insertedItem <- service.insert(todoItem) response <- Ok(insertedItem.asJson) } yield response case req @ PUT -> Root / prefix / IntVar(id) => for { todoItem <- req.as[TodoItem] updatedItem <- service.update(todoItem.copy(id = Some(id))) reponse <- Ok(updatedItem.asJson) } yield reponse case DELETE -> Root / prefix / IntVar(id) => service.destroy(id) *> Ok() } } object TodoItemApi { implicit def instance[F[_]: Effect](implicit service: TodoItemService[F]): TodoItemApi[F] = new TodoItemApi[F] }
Example 54
Source File: Server.scala From Learn-Scala-Programming with MIT License | 5 votes |
package ch14 import cats.effect.IO import fs2.{Stream, StreamApp} import fs2.StreamApp.ExitCode import org.http4s.dsl.Http4sDsl import org.http4s.server.blaze.BlazeBuilder import scala.concurrent.ExecutionContext.Implicits.global object Server extends StreamApp[IO] with Http4sDsl[IO] { override def stream(args: List[String], requestShutdown: IO[Unit]): Stream[IO, ExitCode] = { val config = Config.load("application.conf") createServer(config).flatMap(_.serve) } def createServer(config: IO[Config]): Stream[IO, BlazeBuilder[IO]] = { for { config <- Stream.eval(config) transactor <- Stream.eval(DB.transactor(config.database)) _ <- Stream.eval(DB.initialize(transactor)) } yield BlazeBuilder[IO] .bindHttp(config.server.port, config.server.host) .mountService(new Service(new Repository(transactor)).service, "/") } }
Example 55
Source File: Service.scala From Learn-Scala-Programming with MIT License | 5 votes |
package ch14 import cats.effect.IO import ch14.Model.{Inventory, Purchase, Restock} import org.http4s.{HttpService, MediaType, Response} import org.http4s.dsl.Http4sDsl import org.http4s.circe._ import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s.headers.`Content-Type` import fs2.Stream class Service(repo: Repository) extends Http4sDsl[IO] { val service = HttpService[IO] { case DELETE -> Root / "articles" / name => repo.deleteArticle(name).flatMap { if (_) NoContent() else NotFound() } case POST -> Root / "articles" / name => repo.createArticle(name).flatMap { if (_) NoContent() else Conflict() } case GET -> Root / "articles" / name => renderInventory(repo.getArticle(name)) case req @ POST -> Root / "purchase" => val changes: Stream[IO, Inventory] = for { purchase <- Stream.eval(req.decodeJson[Purchase]) before <- repo.getInventory _ <- repo.updateStock(purchase.inventory) after <- repo.getInventory } yield diff(purchase.order.keys, before, after) renderInventory(changes) case req @ POST -> Root / "restock" => val newState = for { purchase <- Stream.eval(req.decodeJson[Restock]) _ <- repo.updateStock(purchase.inventory) inventory <- repo.getInventory } yield inventory renderInventory(newState) case GET -> Root / "inventory" => getInventory } private def diff[A](keys: Iterable[A], before: Map[A, Int], after: Map[A, Int]): Map[A, Int] = keys.filter(before.contains).map { key => key -> (before(key) - after(key)) }.toMap private def getInventory: IO[Response[IO]] = renderInventory(repo.getInventory) private def renderInventory(inventory: Stream[IO, Inventory]) = Ok(inventory.map(_.asJson.noSpaces), `Content-Type`(MediaType.`application/json`)) }
Example 56
Source File: Hook.scala From canoe with MIT License | 5 votes |
package canoe.api.sources import canoe.api.{TelegramClient} import canoe.methods.webhooks.{DeleteWebhook, SetWebhook} import canoe.models.{InputFile, Update} import canoe.syntax.methodOps import cats.Monad import cats.effect.{ConcurrentEffect, Resource, Timer} import cats.syntax.all._ import fs2.Stream import fs2.concurrent.Queue import io.chrisdavenport.log4cats.Logger import io.chrisdavenport.log4cats.slf4j.Slf4jLogger import org.http4s._ import org.http4s.circe.jsonOf import org.http4s.dsl.Http4sDsl import org.http4s.implicits._ import org.http4s.server.Server import org.http4s.server.blaze.BlazeServerBuilder class Hook[F[_]](queue: Queue[F, Update]) { def updates: Stream[F, Update] = queue.dequeue } object Hook { private def listenServer[F[_]: ConcurrentEffect: Timer: Logger](port: Int): Resource[F, Hook[F]] = { val dsl = Http4sDsl[F] import dsl._ def app(queue: Queue[F, Update]): HttpApp[F] = HttpRoutes .of[F] { case req @ POST -> Root => req .decodeWith(jsonOf[F, Update], strict = true)(queue.enqueue1(_) *> Ok()) .recoverWith { case InvalidMessageBodyFailure(details, _) => F.error(s"Received unknown type of update. $details") *> Ok() } } .orNotFound def server(queue: Queue[F, Update]): Resource[F, Server[F]] = BlazeServerBuilder[F].bindHttp(port).withHttpApp(app(queue)).resource Resource.suspend(Queue.unbounded[F, Update].map(q => server(q).map(_ => new Hook[F](q)))) } }
Example 57
Source File: http4s.scala From sup with Apache License 2.0 | 5 votes |
package sup.modules import cats.effect.Sync import cats.Monad import cats.Reducible import org.http4s.dsl.Http4sDsl import org.http4s.EntityEncoder import org.http4s.HttpRoutes import org.http4s.Response import sup.HealthCheck import sup.HealthResult import cats.implicits._ object http4s { def healthCheckRoutes[F[_]: Sync, H[_]: Reducible]( healthCheck: HealthCheck[F, H], path: String = "health-check" )( implicit encoder: EntityEncoder[F, HealthResult[H]] ): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of[F] { case GET -> Root / `path` => healthCheckResponse(healthCheck) } } def healthCheckResponse[F[_]: Monad, H[_]: Reducible]( healthCheck: HealthCheck[F, H] )( implicit encoder: EntityEncoder[F, HealthResult[H]] ): F[Response[F]] = { val dsl = new Http4sDsl[F] {} import dsl._ healthCheck.check.flatMap { check => if (check.value.reduce.isHealthy) Ok(check) else ServiceUnavailable(check) } } }
Example 58
Source File: JobQueueRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.common.Ident import docspell.restserver.conv.Conversions import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object JobQueueRoutes { def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of { case GET -> Root / "state" => for { js <- backend.job.queueState(user.account.collective, 200) res = Conversions.mkJobQueueState(js) resp <- Ok(res) } yield resp case POST -> Root / Ident(id) / "cancel" => for { result <- backend.job.cancelJob(id, user.account.collective) resp <- Ok(Conversions.basicResult(result)) } yield resp } } }
Example 59
Source File: AccountRoute.scala From aecor with MIT License | 5 votes |
package aecor.example.account import cats.implicits._ import org.http4s.circe._ import io.circe.generic.auto._ import cats.effect._ import org.http4s._ import org.http4s.dsl.Http4sDsl trait AccountService[F[_]] { def openAccount(accountId: AccountId, checkBalance: Boolean): F[Either[String, Unit]] } object AccountRoute { class Builder[F[_]: Sync](service: AccountService[F]) extends Http4sDsl[F] with CirceEntityDecoder { def routes: HttpRoutes[F] = HttpRoutes.of[F] { case req @ POST -> Root / "accounts" => for { openAccountRequest <- req.as[OpenAccountRequest] resp <- service.openAccount(openAccountRequest.accountId, openAccountRequest.checkBalance).flatMap { case Left(e) => BadRequest(e.toString) case Right(_) => Ok("") } } yield resp } } final case class OpenAccountRequest(accountId: AccountId, checkBalance: Boolean) implicit val openAccountRequestDecoder = io.circe.generic.semiauto.deriveDecoder[OpenAccountRequest] def apply[F[_]: Sync](service: AccountService[F]): HttpRoutes[F] = new Builder(service).routes }
Example 60
Source File: TransactionRoute.scala From aecor with MIT License | 5 votes |
package aecor.example.transaction import java.util.UUID import aecor.example.account import aecor.example.account.AccountId import aecor.example.common.Amount import cats.effect.{Effect, Sync} import cats.implicits._ import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityDecoder import org.http4s.dsl.Http4sDsl import io.circe.generic.auto._ trait TransactionService[F[_]] { def authorizePayment(transactionId: TransactionId, from: From[AccountId], to: To[AccountId], amount: Amount): F[TransactionRoute.ApiResult] } object TransactionRoute { sealed trait ApiResult object ApiResult { case object Authorized extends ApiResult case class Declined(reason: String) extends ApiResult } final case class CreateTransactionRequest(from: From[AccountId], to: To[AccountId], amount: Amount) object TransactionIdVar { def unapply(arg: String): Option[TransactionId] = TransactionId(arg).some } private final class Builder[F[_]: Sync](service: TransactionService[F]) extends Http4sDsl[F] with CirceEntityDecoder { def routes: HttpRoutes[F] = HttpRoutes.of[F] { case req @ PUT -> Root / "transactions" / TransactionIdVar(transactionId) => for { body <- req.as[CreateTransactionRequest] CreateTransactionRequest(from, to, amount) = body resp <- service.authorizePayment(transactionId, from, to, amount).flatMap { case ApiResult.Authorized => Ok("Authorized") case ApiResult.Declined(reason) => BadRequest(s"Declined: $reason") } } yield resp case POST -> Root / "test" => service .authorizePayment( TransactionId(UUID.randomUUID.toString), From(account.EventsourcedAlgebra.rootAccountId), To(AccountId("foo")), Amount(1) ) .flatMap { case ApiResult.Authorized => Ok("Authorized") case ApiResult.Declined(reason) => BadRequest(s"Declined: $reason") } } } def apply[F[_]: Effect](api: TransactionService[F]): HttpRoutes[F] = new Builder(api).routes }
Example 61
Source File: BookingRoutes.scala From ticket-booking-aecor with Apache License 2.0 | 5 votes |
package ru.pavkin.booking.booking.endpoint import cats.effect.Effect import cats.implicits._ import io.circe.syntax._ import org.http4s.HttpRoutes import org.http4s.circe._ import org.http4s.dsl.Http4sDsl import ru.pavkin.booking.common.models.{BookingKey, ClientId} final class BookingRoutes[F[_]: Effect](ops: BookingEndpoint[F]) extends Http4sDsl[F] { implicit val placeBookingDecoder = jsonOf[F, PlaceBookingRequest] implicit val cancelBookingDecoder = jsonOf[F, CancelBookingRequest] private val placeBooking: HttpRoutes[F] = HttpRoutes.of { case r @ POST -> Root / userId / "bookings" => r.as[PlaceBookingRequest] .flatMap( r => ops.placeBooking(ClientId(userId), r.concertId, r.seats).flatMap { case Left(err) => BadRequest(err.toString) case Right(_) => Ok() } ) } private val cancelBooking: HttpRoutes[F] = HttpRoutes.of { case r @ DELETE -> Root / userId / "bookings" / bookingId => r.as[CancelBookingRequest] .flatMap( r => ops.cancelBooking(ClientId(userId), BookingKey(bookingId), r.reason).flatMap { case Left(err) => BadRequest(err.toString) case Right(_) => Ok() } ) } private val clientBookings: HttpRoutes[F] = HttpRoutes.of { case GET -> Root / userId / "bookings" => ops.clientBookings(ClientId(userId)).flatMap { bookings => Ok(bookings.asJson) } } val routes: HttpRoutes[F] = placeBooking <+> clientBookings <+> cancelBooking }
Example 62
Source File: TestRoutes.scala From scala-server-lambda with MIT License | 5 votes |
package io.github.howardjohn.lambda.http4s import cats.{Applicative, MonadError} import cats.effect.Sync import cats.implicits._ import io.github.howardjohn.lambda.LambdaHandlerBehavior import io.github.howardjohn.lambda.LambdaHandlerBehavior._ import org.http4s.dsl.Http4sDsl import org.http4s.{EntityDecoder, Header, HttpRoutes} import org.http4s.circe._ import io.circe.generic.auto._ import io.circe.syntax._ import org.http4s.dsl.impl.OptionalQueryParamDecoderMatcher class TestRoutes[F[_]] { object TimesQueryMatcher extends OptionalQueryParamDecoderMatcher[Int]("times") val dsl = Http4sDsl[F] import dsl._ def routes(implicit sync: Sync[F], jsonDecoder: EntityDecoder[F, JsonBody], me: MonadError[F, Throwable], stringDecoder: EntityDecoder[F, String], ap: Applicative[F]): HttpRoutes[F] = HttpRoutes.of[F] { case GET -> Root / "hello" :? TimesQueryMatcher(times) => Ok { Seq .fill(times.getOrElse(1))("Hello World!") .mkString(" ") } case GET -> Root / "long" => Applicative[F].pure(Thread.sleep(1000)).flatMap(_ => Ok("Hello World!")) case GET -> Root / "exception" => throw RouteException() case GET -> Root / "error" => InternalServerError() case req@GET -> Root / "header" => val header = req.headers.find(h => h.name.value == inputHeader).map(_.value).getOrElse("Header Not Found") Ok(header, Header(outputHeader, outputHeaderValue)) case req@POST -> Root / "post" => req.as[String].flatMap(s => Ok(s)) case req@POST -> Root / "json" => req.as[JsonBody].flatMap(s => Ok(LambdaHandlerBehavior.jsonReturn.asJson)) } }
Example 63
Source File: TimeService.scala From get-programming-with-scala with MIT License | 5 votes |
package org.example.time import java.time.format.DateTimeFormatter import cats.effect.IO import org.http4s.HttpService import org.http4s.dsl.Http4sDsl class TimeService extends Http4sDsl[IO] { private val printer = new TimePrinter(DateTimeFormatter.RFC_1123_DATE_TIME) val service = HttpService[IO] { case GET -> Root / "datetime" / country => try { Ok(printer.now(country)) } catch { case ex: IllegalStateException => NotFound(ex.getMessage) } } }
Example 64
Source File: SearchService.scala From franklin with Apache License 2.0 | 5 votes |
package com.azavea.franklin.api.services import cats.effect._ import cats.implicits._ import com.azavea.franklin.api.endpoints.SearchEndpoints import com.azavea.franklin.api.implicits._ import com.azavea.franklin.database.{SearchFilters, StacItemDao} import com.azavea.franklin.datamodel.SearchMethod import doobie.implicits._ import doobie.util.transactor.Transactor import eu.timepit.refined.types.numeric.NonNegInt import eu.timepit.refined.types.string.NonEmptyString import io.circe._ import io.circe.syntax._ import org.http4s._ import org.http4s.dsl.Http4sDsl import sttp.tapir.server.http4s._ class SearchService[F[_]: Sync]( apiHost: NonEmptyString, defaultLimit: NonNegInt, enableTiles: Boolean, xa: Transactor[F] )( implicit contextShift: ContextShift[F] ) extends Http4sDsl[F] { def search(searchFilters: SearchFilters, searchMethod: SearchMethod): F[Either[Unit, Json]] = { for { searchResult <- StacItemDao .getSearchResult( searchFilters, searchFilters.limit getOrElse defaultLimit, apiHost, searchMethod ) .transact(xa) } yield { val updatedFeatures = searchResult.features.map { item => (item.collection, enableTiles) match { case (Some(collectionId), true) => item.addTilesLink(apiHost.value, collectionId, item.id) case _ => item } } Either.right(searchResult.copy(features = updatedFeatures).asJson) } } val routes: HttpRoutes[F] = SearchEndpoints.searchGet.toRoutes(searchFilters => search(searchFilters, SearchMethod.Get)) <+> SearchEndpoints.searchPost .toRoutes { case searchFilters => search(searchFilters, SearchMethod.Post) } }
Example 65
Source File: LandingPageService.scala From franklin with Apache License 2.0 | 5 votes |
package com.azavea.franklin.api.services import cats._ import cats.effect._ import cats.implicits._ import com.azavea.franklin.api.commands.ApiConfig import com.azavea.franklin.api.endpoints.LandingPageEndpoints import com.azavea.franklin.api.implicits._ import com.azavea.franklin.datamodel.{LandingPage, Link, Conformance => FranklinConformance} import com.azavea.stac4s.StacLinkType import com.azavea.stac4s._ import eu.timepit.refined.auto._ import eu.timepit.refined.types.string.NonEmptyString import io.circe._ import io.circe.syntax._ import org.http4s._ import org.http4s.dsl.Http4sDsl import sttp.tapir.server.http4s._ class LandingPageService[F[_]: Sync](apiConfig: ApiConfig)(implicit contextShift: ContextShift[F]) extends Http4sDsl[F] { val links = List( Link( apiConfig.apiHost, StacLinkType.Self, Some(`application/json`), Some("Franklin Powered Catalog") ), Link( apiConfig.apiHost + "/open-api/spec.yaml", StacLinkType.ServiceDesc, Some(VendorMediaType("application/vnd.oai.openapi+json;version=3.0")), Some("Open API 3 Documentation") ), Link( apiConfig.apiHost + "/conformance", StacLinkType.Conformance, Some(`application/json`), None ), Link( apiConfig.apiHost + "/collections", StacLinkType.Data, Some(`application/json`), Some("Collections Listing") ), Link( apiConfig.apiHost + "/search", StacLinkType.Data, Some(`application/geo+json`), Some("Franklin Powered STAC") ) ) def landingPage(): F[Either[Unit, Json]] = { Applicative[F].pure { val title: NonEmptyString = "Franklin Powered OGC API - Features and STAC web service" val description: NonEmptyString = "Web service powered by [Franklin](https://github.com/azavea/franklin)" Right(LandingPage(title, description, links).asJson) } } def conformancePage(): F[Either[Unit, Json]] = { Applicative[F].pure { val uriList: List[NonEmptyString] = List( "http://www.opengis.net/spec/ogcapi-features-1/1.0/req/core", "http://www.opengis.net/spec/ogcapi-features-1/1.0/req/oas30", "http://www.opengis.net/spec/ogcapi-features-1/1.0/req/geojson" ) Right(FranklinConformance(uriList).asJson) } } val routes: HttpRoutes[F] = LandingPageEndpoints.landingPageEndpoint.toRoutes(_ => landingPage()) <+> LandingPageEndpoints.conformanceEndpoint.toRoutes(_ => conformancePage()) }
Example 66
Source File: CollectiveRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.backend.ops.OCollective import docspell.restapi.model._ import docspell.restserver.conv.Conversions import docspell.restserver.http4s._ import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object CollectiveRoutes { def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = { val dsl = new Http4sDsl[F] with ResponseGenerator[F] {} import dsl._ HttpRoutes.of { case GET -> Root / "insights" => for { ins <- backend.collective.insights(user.account.collective) resp <- Ok(Conversions.mkItemInsights(ins)) } yield resp case req @ POST -> Root / "settings" => for { settings <- req.as[CollectiveSettings] sett = OCollective.Settings(settings.language, settings.integrationEnabled) res <- backend.collective .updateSettings(user.account.collective, sett) resp <- Ok(Conversions.basicResult(res, "Settings updated.")) } yield resp case GET -> Root / "settings" => for { collDb <- backend.collective.find(user.account.collective) sett = collDb.map(c => CollectiveSettings(c.language, c.integrationEnabled)) resp <- sett.toResponse() } yield resp case GET -> Root / "contacts" :? QueryParam.QueryOpt(q) +& QueryParam .ContactKindOpt(kind) => for { res <- backend.collective .getContacts(user.account.collective, q.map(_.q), kind) .take(50) .compile .toList resp <- Ok(ContactList(res.map(Conversions.mkContact))) } yield resp case GET -> Root => for { collDb <- backend.collective.find(user.account.collective) coll = collDb.map(c => Collective(c.id, c.state, c.created)) resp <- coll.toResponse() } yield resp } } }
Example 67
Source File: RegisterRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.ops.OCollective.RegisterData import docspell.backend.signup.{NewInviteResult, SignupResult} import docspell.restapi.model._ import docspell.restserver.Config import docspell.restserver.http4s.ResponseGenerator import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl import org.log4s._ object RegisterRoutes { private[this] val logger = getLogger def apply[F[_]: Effect](backend: BackendApp[F], cfg: Config): HttpRoutes[F] = { val dsl = new Http4sDsl[F] with ResponseGenerator[F] {} import dsl._ HttpRoutes.of { case req @ POST -> Root / "register" => for { data <- req.as[Registration] res <- backend.signup.register(cfg.backend.signup)(convert(data)) resp <- Ok(convert(res)) } yield resp case req @ POST -> Root / "newinvite" => for { data <- req.as[GenInvite] res <- backend.signup.newInvite(cfg.backend.signup)(data.password) resp <- Ok(convert(res)) } yield resp } } def convert(r: NewInviteResult): InviteResult = r match { case NewInviteResult.Success(id) => InviteResult(true, "New invitation created.", Some(id)) case NewInviteResult.InvitationDisabled => InviteResult(false, "Signing up is not enabled for invitations.", None) case NewInviteResult.PasswordMismatch => InviteResult(false, "Password is invalid.", None) } def convert(r: SignupResult): BasicResult = r match { case SignupResult.CollectiveExists => BasicResult(false, "A collective with this name already exists.") case SignupResult.InvalidInvitationKey => BasicResult(false, "Invalid invitation key.") case SignupResult.SignupClosed => BasicResult(false, "Sorry, registration is closed.") case SignupResult.Failure(ex) => logger.error(ex)("Error signing up") BasicResult(false, s"Internal error: ${ex.getMessage}") case SignupResult.Success => BasicResult(true, "Signup successful") } def convert(r: Registration): RegisterData = RegisterData(r.collectiveName, r.login, r.password, r.invite) }
Example 68
Source File: Http4sRpcServer.scala From iotchain with MIT License | 5 votes |
package jbok.network.rpc.http import cats.effect.{ConcurrentEffect, Resource, Sync, Timer} import cats.implicits._ import io.circe.Json import io.circe.syntax._ import jbok.network.rpc.{RpcRequest, RpcService} import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityCodec._ import org.http4s.dsl.Http4sDsl import org.http4s.implicits._ import org.http4s.server.Server import org.http4s.server.blaze.BlazeServerBuilder object Http4sRpcServer { def routes[F[_]](service: RpcService[F, Json])(implicit F: Sync[F]): HttpRoutes[F] = { val dsl = Http4sDsl[F] import dsl._ HttpRoutes.of[F] { case req @ POST -> path => for { json <- req.as[Json] result <- service.handle(RpcRequest(path.toList, json)) resp <- Ok(result.asJson) } yield resp } } def server[F[_]](service: RpcService[F, Json])(implicit F: ConcurrentEffect[F], T: Timer[F]): Resource[F, Server[F]] = BlazeServerBuilder[F] .bindLocal(0) .withHttpApp(routes[F](service).orNotFound) .withWebSockets(true) .resource }
Example 69
Source File: LoginRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.auth._ import docspell.restapi.model._ import docspell.restserver._ import docspell.restserver.auth._ import org.http4s._ import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object LoginRoutes { def login[F[_]: Effect](S: Login[F], cfg: Config): HttpRoutes[F] = { val dsl: Http4sDsl[F] = new Http4sDsl[F] {} import dsl._ HttpRoutes.of[F] { case req @ POST -> Root / "login" => for { up <- req.as[UserPass] res <- S.loginUserPass(cfg.auth)(Login.UserPass(up.account, up.password)) resp <- makeResponse(dsl, cfg, res, up.account) } yield resp } } def session[F[_]: Effect](S: Login[F], cfg: Config): HttpRoutes[F] = { val dsl: Http4sDsl[F] = new Http4sDsl[F] {} import dsl._ HttpRoutes.of[F] { case req @ POST -> Root / "session" => Authenticate .authenticateRequest(S.loginSession(cfg.auth))(req) .flatMap(res => makeResponse(dsl, cfg, res, "")) case POST -> Root / "logout" => Ok().map(_.addCookie(CookieData.deleteCookie(cfg))) } } def makeResponse[F[_]: Effect]( dsl: Http4sDsl[F], cfg: Config, res: Login.Result, account: String ): F[Response[F]] = { import dsl._ res match { case Login.Result.Ok(token) => for { cd <- AuthToken.user(token.account, cfg.auth.serverSecret).map(CookieData.apply) resp <- Ok( AuthResult( token.account.collective.id, token.account.user.id, true, "Login successful", Some(cd.asString), cfg.auth.sessionValid.millis ) ).map(_.addCookie(cd.asCookie(cfg))) } yield resp case _ => Ok(AuthResult("", account, false, "Login failed.", None, 0L)) } } }
Example 70
Source File: CheckFileRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.common.Ident import docspell.restapi.model.{BasicItem, CheckFileResult} import docspell.restserver.http4s.ResponseGenerator import docspell.store.records.RItem import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object CheckFileRoutes { def secured[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = { val dsl = new Http4sDsl[F] with ResponseGenerator[F] {} import dsl._ HttpRoutes.of { case GET -> Root / checksum => for { items <- backend.itemSearch.findByFileCollective(checksum, user.account.collective) resp <- Ok(convert(items)) } yield resp } } def open[F[_]: Effect](backend: BackendApp[F]): HttpRoutes[F] = { val dsl = new Http4sDsl[F] with ResponseGenerator[F] {} import dsl._ HttpRoutes.of { case GET -> Root / Ident(id) / checksum => for { items <- backend.itemSearch.findByFileSource(checksum, id) resp <- Ok(convert(items)) } yield resp } } def convert(v: Vector[RItem]): CheckFileResult = CheckFileResult( v.nonEmpty, v.map(r => BasicItem(r.id, r.name, r.direction, r.state, r.created, r.itemDate)) .toList ) }
Example 71
Source File: SentMailRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.data.OptionT import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.backend.ops.OMail.Sent import docspell.common._ import docspell.restapi.model._ import emil.javamail.syntax._ import org.http4s._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object SentMailRoutes { def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of { case GET -> Root / "item" / Ident(id) => for { all <- backend.mail.getSentMailsForItem(user.account, id) resp <- Ok(SentMails(all.map(convert).toList)) } yield resp case GET -> Root / "mail" / Ident(mailId) => (for { mail <- backend.mail.getSentMail(user.account, mailId) resp <- OptionT.liftF(Ok(convert(mail))) } yield resp).getOrElseF(NotFound()) case DELETE -> Root / "mail" / Ident(mailId) => for { n <- backend.mail.deleteSentMail(user.account, mailId) resp <- Ok(BasicResult(n > 0, s"Mails deleted: $n")) } yield resp } } def convert(s: Sent): SentMail = SentMail( s.id, s.senderLogin, s.connectionName, s.recipients.map(_.asUnicodeString), s.subject, s.body, s.created ) }
Example 72
Source File: PersonRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.common.Ident import docspell.common.syntax.all._ import docspell.restapi.model._ import docspell.restserver.conv.Conversions._ import docspell.restserver.http4s.QueryParam import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl import org.log4s._ object PersonRoutes { private[this] val logger = getLogger def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of { case GET -> Root :? QueryParam.FullOpt(full) +& QueryParam.QueryOpt(q) => if (full.getOrElse(false)) for { data <- backend.organization.findAllPerson(user.account, q.map(_.q)) resp <- Ok(PersonList(data.map(mkPerson).toList)) } yield resp else for { data <- backend.organization.findAllPersonRefs(user.account, q.map(_.q)) resp <- Ok(ReferenceList(data.map(mkIdName).toList)) } yield resp case req @ POST -> Root => for { data <- req.as[Person] newPer <- newPerson(data, user.account.collective) added <- backend.organization.addPerson(newPer) resp <- Ok(basicResult(added, "New person saved.")) } yield resp case req @ PUT -> Root => for { data <- req.as[Person] upPer <- changePerson(data, user.account.collective) update <- backend.organization.updatePerson(upPer) resp <- Ok(basicResult(update, "Person updated.")) } yield resp case DELETE -> Root / Ident(id) => for { _ <- logger.fdebug(s"Deleting person ${id.id}") delOrg <- backend.organization.deletePerson(id, user.account.collective) resp <- Ok(basicResult(delOrg, "Person deleted.")) } yield resp } } }
Example 73
Source File: SourceRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.common.Ident import docspell.restapi.model._ import docspell.restserver.conv.Conversions._ import docspell.restserver.http4s.ResponseGenerator import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object SourceRoutes { def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = { val dsl = new Http4sDsl[F] with ResponseGenerator[F] {} import dsl._ HttpRoutes.of { case GET -> Root => for { all <- backend.source.findAll(user.account) res <- Ok(SourceList(all.map(mkSource).toList)) } yield res case req @ POST -> Root => for { data <- req.as[Source] src <- newSource(data, user.account.collective) added <- backend.source.add(src) resp <- Ok(basicResult(added, "Source added.")) } yield resp case req @ PUT -> Root => for { data <- req.as[Source] src = changeSource(data, user.account.collective) updated <- backend.source.update(src) resp <- Ok(basicResult(updated, "Source updated.")) } yield resp case DELETE -> Root / Ident(id) => for { del <- backend.source.delete(id, user.account.collective) resp <- Ok(basicResult(del, "Source deleted.")) } yield resp } } }
Example 74
Source File: MailSendRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.backend.ops.OMail.{AttachSelection, ItemMail} import docspell.backend.ops.SendResult import docspell.common._ import docspell.restapi.model._ import emil.MailAddress import emil.javamail.syntax._ import org.http4s._ import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object MailSendRoutes { def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of { case req @ POST -> Root / Ident(name) / Ident(id) => for { in <- req.as[SimpleMail] mail = convertIn(id, in) res <- mail.traverse(m => backend.mail.sendMail(user.account, name, m)) resp <- res.fold( err => Ok(BasicResult(false, s"Invalid mail data: $err")), res => Ok(convertOut(res)) ) } yield resp } } def convertIn(item: Ident, s: SimpleMail): Either[String, ItemMail] = for { rec <- s.recipients.traverse(MailAddress.parse) fileIds <- s.attachmentIds.traverse(Ident.fromString) sel = if (s.addAllAttachments) AttachSelection.All else AttachSelection.Selected(fileIds) } yield ItemMail(item, s.subject, rec, s.body, sel) def convertOut(res: SendResult): BasicResult = res match { case SendResult.Success(_) => BasicResult(true, "Mail sent.") case SendResult.SendFailure(ex) => BasicResult(false, s"Mail sending failed: ${ex.getMessage}") case SendResult.StoreFailure(ex) => BasicResult( false, s"Mail was sent, but could not be store to database: ${ex.getMessage}" ) case SendResult.NotFound => BasicResult(false, s"There was no mail-connection or item found.") } }
Example 75
Source File: FullTextIndexRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.data.OptionT import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.common._ import docspell.restserver.Config import docspell.restserver.conv.Conversions import org.http4s._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object FullTextIndexRoutes { def secured[F[_]: Effect]( cfg: Config, backend: BackendApp[F], user: AuthToken ): HttpRoutes[F] = if (!cfg.fullTextSearch.enabled) notFound[F] else { val dsl = Http4sDsl[F] import dsl._ HttpRoutes.of { case POST -> Root / "reIndex" => for { res <- backend.fulltext.reindexCollective(user.account).attempt resp <- Ok(Conversions.basicResult(res, "Full-text index will be re-created.")) } yield resp } } def open[F[_]: Effect](cfg: Config, backend: BackendApp[F]): HttpRoutes[F] = if (!cfg.fullTextSearch.enabled) notFound[F] else { val dsl = Http4sDsl[F] import dsl._ HttpRoutes.of { case POST -> Root / "reIndexAll" / Ident(id) => for { res <- if (id.nonEmpty && id == cfg.fullTextSearch.recreateKey) backend.fulltext.reindexAll.attempt else Left(new Exception("The provided key is invalid.")).pure[F] resp <- Ok(Conversions.basicResult(res, "Full-text index will be re-created.")) } yield resp } } private def notFound[F[_]: Effect]: HttpRoutes[F] = HttpRoutes(_ => OptionT.pure(Response.notFound[F])) }
Example 76
Source File: OrganizationRoutes.scala From docspell with GNU General Public License v3.0 | 5 votes |
package docspell.restserver.routes import cats.effect._ import cats.implicits._ import docspell.backend.BackendApp import docspell.backend.auth.AuthToken import docspell.common.Ident import docspell.restapi.model._ import docspell.restserver.conv.Conversions._ import docspell.restserver.http4s.QueryParam import org.http4s.HttpRoutes import org.http4s.circe.CirceEntityDecoder._ import org.http4s.circe.CirceEntityEncoder._ import org.http4s.dsl.Http4sDsl object OrganizationRoutes { def apply[F[_]: Effect](backend: BackendApp[F], user: AuthToken): HttpRoutes[F] = { val dsl = new Http4sDsl[F] {} import dsl._ HttpRoutes.of { case GET -> Root :? QueryParam.FullOpt(full) +& QueryParam.QueryOpt(q) => if (full.getOrElse(false)) for { data <- backend.organization.findAllOrg(user.account, q.map(_.q)) resp <- Ok(OrganizationList(data.map(mkOrg).toList)) } yield resp else for { data <- backend.organization.findAllOrgRefs(user.account, q.map(_.q)) resp <- Ok(ReferenceList(data.map(mkIdName).toList)) } yield resp case req @ POST -> Root => for { data <- req.as[Organization] newOrg <- newOrg(data, user.account.collective) added <- backend.organization.addOrg(newOrg) resp <- Ok(basicResult(added, "New organization saved.")) } yield resp case req @ PUT -> Root => for { data <- req.as[Organization] upOrg <- changeOrg(data, user.account.collective) update <- backend.organization.updateOrg(upOrg) resp <- Ok(basicResult(update, "Organization updated.")) } yield resp case DELETE -> Root / Ident(id) => for { delOrg <- backend.organization.deleteOrg(id, user.account.collective) resp <- Ok(basicResult(delOrg, "Organization deleted.")) } yield resp } } }