com.twitter.finagle.http.Response Scala Examples
The following examples show how to use com.twitter.finagle.http.Response.
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: CirceSpec.scala From featherbed with Apache License 2.0 | 6 votes |
package featherbed.circe import cats.implicits._ import com.twitter.util.Future import io.circe._ import io.circe.generic.auto._ import io.circe.parser.parse import io.circe.syntax._ import org.scalatest.FlatSpec import shapeless.{Coproduct, Witness} import shapeless.union.Union case class Foo(someText: String, someInt: Int) class CirceSpec extends FlatSpec { "post request of a case class" should "derive JSON encoder" in { import com.twitter.util.{Future, Await} import com.twitter.finagle.{Service, Http} import com.twitter.finagle.http.{Request, Response} import java.net.InetSocketAddress val server = Http.serve(new InetSocketAddress(8766), new Service[Request, Response] { def apply(request: Request): Future[Response] = Future { val rep = Response() rep.contentString = s"${request.contentString}" rep.setContentTypeJson() rep } }) import java.net.URL val client = new featherbed.Client(new URL("http://localhost:8766/api/")) import io.circe.generic.auto._ val req = client.post("foo/bar") .withContent(Foo("Hello world!", 42), "application/json") .accept[Coproduct.`"application/json"`.T] val result = Await.result { req.send[Foo]() } Foo("test", 42).asJson.toString parse("""{"someText": "test", "someInt": 42}""").toValidated.map(_.as[Foo]) Await.result(server.close()) } "API example" should "compile" in { import shapeless.Coproduct import java.net.URL import com.twitter.util.Await case class Post(userId: Int, id: Int, title: String, body: String) case class Comment(postId: Int, id: Int, name: String, email: String, body: String) class JSONPlaceholderAPI(baseUrl: URL) { private val client = new featherbed.Client(baseUrl) type JSON = Coproduct.`"application/json"`.T object posts { private val listRequest = client.get("posts").accept[JSON] private val getRequest = (id: Int) => client.get(s"posts/$id").accept[JSON] def list(): Future[Seq[Post]] = listRequest.send[Seq[Post]]() def get(id: Int): Future[Post] = getRequest(id).send[Post]() } object comments { private val listRequest = client.get("comments").accept[JSON] private val getRequest = (id: Int) => client.get(s"comments/$id").accept[JSON] def list(): Future[Seq[Comment]] = listRequest.send[Seq[Comment]]() def get(id: Int): Future[Comment] = getRequest(id).send[Comment]() } } val apiClient = new JSONPlaceholderAPI(new URL("http://jsonplaceholder.typicode.com/")) Await.result(apiClient.posts.list()) } }
Example 2
Source File: package.scala From featherbed with Apache License 2.0 | 5 votes |
package featherbed import scala.annotation.implicitNotFound import scala.language.higherKinds import cats.data.Validated.Valid import com.twitter.finagle.http.Response import shapeless._ package object support { @implicitNotFound("""In order to decode a request to ${A}, it must be known that a decoder exists to ${A} from all the content types that you Accept, which is currently ${ContentTypes}. You may have forgotten to specify Accept types with the `accept(..)` method, or you may be missing Decoder instances for some content types. """) sealed trait DecodeAll[A, ContentTypes <: Coproduct] { val instances: List[content.Decoder.Aux[_, A]] def findInstance(ct: String): Option[content.Decoder.Aux[_, A]] = instances.find(_.contentType == ct) orElse instances.find(_.contentType == "**" def apply(response: Response) = Valid(response) } :: Nil } } }
Example 3
Source File: package.scala From featherbed with Apache License 2.0 | 5 votes |
package featherbed import java.nio.CharBuffer import java.nio.charset.{Charset, CodingErrorAction} import scala.util.Try import cats.data.{Validated, ValidatedNel} import com.twitter.finagle.http.Response import com.twitter.io.Buf import shapeless.Witness import sun.nio.cs.ThreadLocalCoders package object content { type ContentType = String trait Decoder[ContentType] { type Out val contentType: String //widened version of ContentType def apply(buf: Response): ValidatedNel[Throwable, Out] } object Decoder extends LowPriorityDecoders { type Aux[CT, A1] = Decoder[CT] { type Out = A1 } def of[T <: ContentType, A1](t: T)(fn: Response => ValidatedNel[Throwable, A1]): Decoder.Aux[t.type, A1] = new Decoder[t.type] { type Out = A1 val contentType = t def apply(response: Response) = fn(response) } def decodeString(response: Response): ValidatedNel[Throwable, String] = { Validated.fromTry(Try { response.charset.map(Charset.forName).getOrElse(Charset.defaultCharset) }).andThen { charset: Charset => val decoder = ThreadLocalCoders.decoderFor(charset) Validated.fromTry( Try( decoder .onMalformedInput(CodingErrorAction.REPORT) .onUnmappableCharacter(CodingErrorAction.REPORT) .decode(Buf.ByteBuffer.Owned.extract(response.content).asReadOnlyBuffer()))).map[String](_.toString) }.toValidatedNel } } private[featherbed] trait LowPriorityDecoders { implicit val plainTextDecoder: Decoder.Aux[Witness.`"text/plain"`.T, String] = Decoder.of("text/plain") { response => Decoder.decodeString(response) } implicit val anyResponseDecoder: Decoder.Aux[Witness.`"**") { response => Validated.Valid(response) } } trait Encoder[A, ForContentType] { def apply(value: A, charset: Charset): ValidatedNel[Throwable, Buf] } object Encoder extends LowPriorityEncoders { def of[A, T <: ContentType](t: T)(fn: (A, Charset) => ValidatedNel[Throwable, Buf]): Encoder[A, t.type] = new Encoder[A, t.type] { def apply(value: A, charset: Charset) = fn(value, charset) } def encodeString(value: String, charset: Charset): ValidatedNel[Throwable, Buf] = { val encoder = ThreadLocalCoders.encoderFor(charset) Validated.fromTry(Try(encoder .onMalformedInput(CodingErrorAction.REPORT) .onUnmappableCharacter(CodingErrorAction.REPORT) .encode(CharBuffer.wrap(value)))).toValidatedNel.map[Buf](Buf.ByteBuffer.Owned(_)) } } private[featherbed] trait LowPriorityEncoders { implicit val plainTextEncoder: Encoder[String, Witness.`"text/plain"`.T] = Encoder.of("text/plain") { case (value, charset) => Encoder.encodeString(value, charset) } } }
Example 4
Source File: Http_02_ObjectMapping.scala From airframe with Apache License 2.0 | 5 votes |
package wvlet.airframe.examples.http import com.twitter.finagle.http.Response import wvlet.airframe.control.Control.withResource import wvlet.airframe.http.finagle.{Finagle, FinagleClient, FinagleServer} import wvlet.airframe.http.{Endpoint, HttpMethod, Router} import wvlet.log.LogSupport object Http_02_ObjectMapping extends App with LogSupport { import wvlet.airframe._ case class ListRequest(name: String, page: Int) case class ListResponse(name: String, page: Int, nextPageToken: Option[String], data: String) case class AppInfo(name: String, version: String = "1.0") trait MyApp extends LogSupport { @Endpoint(method = HttpMethod.GET, path = "/v1/info") def appInfo: AppInfo = { info(s"showing app info") AppInfo("myapp") } @Endpoint(method = HttpMethod.GET, path = "/v1/list") def list(listRequest: ListRequest): ListResponse = { ListResponse( name = listRequest.name, page = listRequest.page, nextPageToken = Some("xxxxxx"), data = "yyyyyy" ) } @Endpoint(method = HttpMethod.GET, path = "/v1/resource/*path") def getResource(path: String): Response = { val response = Response() response.contentString = s"resource at ${path}" response } private val session = bind[Session] @Endpoint(method = HttpMethod.POST, path = "/admin/shutdown") def shutdown: Unit = { warn(s"shutting down the server") session.shutdown } } val router = Router.add[MyApp] val design = Finagle.server .withName("myapp") .withRouter(router) .design design.build[FinagleServer] { server => withResource(FinagleClient.newSyncClient(server.localAddress)) { client => val appInfo = client.get[AppInfo]("/v1/info") info(appInfo) // AppInfo(myapp,1.0) client.get[ListResponse]("/v1/list") client.get[Response]("/v1/resource/resource_path") } // Add this code to keep running the server process //server.waitServerTermination } }
Example 5
Source File: HttpRecord.scala From airframe with Apache License 2.0 | 5 votes |
package wvlet.airframe.http.recorder import java.sql.{Connection, ResultSet} import java.time.Instant import com.twitter.finagle.http.{Response, Status, Version} import com.twitter.io.Buf import wvlet.airframe.codec._ import wvlet.airframe.control.Control.withResource import wvlet.airframe.http.recorder.HttpRecord.headerCodec import wvlet.log.LogSupport case class HttpRecord( session: String, requestHash: Int, method: String, destHost: String, path: String, requestHeader: Seq[(String, String)], requestBody: String, responseCode: Int, responseHeader: Seq[(String, String)], responseBody: String, createdAt: Instant ) { def summary: String = { s"${method}(${responseCode}) ${destHost}${path}: ${responseBody.substring(0, 30.min(responseBody.size))} ..." } def toResponse: Response = { val r = Response(Version.Http11, Status.fromCode(responseCode)) responseHeader.foreach { x => r.headerMap.set(x._1, x._2) } // Decode binary contents with Base64 val contentBytes = HttpRecordStore.decodeFromBase64(responseBody) r.content = Buf.ByteArray.Owned(contentBytes) r.contentLength = contentBytes.length r } def insertInto(tableName: String, conn: Connection): Unit = { withResource(conn.prepareStatement(s"""|insert into "${tableName}" values( |?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? |) """.stripMargin)) { prep => // TODO Implement this logic in JDBCResultSetCodec prep.setString(1, session) prep.setInt(2, requestHash) prep.setString(3, method) prep.setString(4, destHost) prep.setString(5, path) prep.setString(6, JSONCodec.toJson(headerCodec.toMsgPack(requestHeader))) prep.setString(7, requestBody) prep.setInt(8, responseCode) prep.setString(9, JSONCodec.toJson(headerCodec.toMsgPack(responseHeader))) prep.setString(10, responseBody) prep.setString(11, createdAt.toString) prep.execute() } } } object HttpRecord extends LogSupport { private[recorder] val headerCodec = MessageCodec.of[Seq[(String, String)]] private[recorder] val recordCodec = MessageCodec.of[HttpRecord] private[recorder] def createTableSQL(tableName: String): String = // TODO: Add a method to generate this SQL statement in airframe-codec s"""create table if not exists "${tableName}" ( | session string, | requestHash string, | method string, | destHost string, | path string, | requestHeader string, | requestBody string, | responseCode int, | responseHeader string, | responseBody string, | createdAt string |) """.stripMargin private[recorder] def read(rs: ResultSet): Seq[HttpRecord] = { val resultSetCodec = JDBCCodec(rs) resultSetCodec .mapMsgPackMapRows(msgpack => recordCodec.unpackBytes(msgpack)) .filter(_.isDefined) .map(_.get) .toSeq } }
Example 6
Source File: PathOnlyMatcherTest.scala From airframe with Apache License 2.0 | 5 votes |
package wvlet.airframe.http.recorder import com.twitter.finagle.http.{Request, Response} import wvlet.airframe.Design import wvlet.airframe.http.finagle.{FinagleClient, FinagleSyncClient} import wvlet.airspec.AirSpec class PathOnlyMatcherTest extends AirSpec { protected override def design: Design = { val config = HttpRecorderConfig(requestMatcher = HttpRequestMatcher.PathOnlyMatcher) Design.newDesign .bind[HttpRecorderServer].toInstance(HttpRecorder.createInMemoryServer(config)) .onStart { recorder => // Record responses { val req = Request("/hello") req.headerMap.put("Accept-Encoding", "gzip") val resp = Response() resp.contentString = "hello" recorder.recordIfNotExists(req, resp) } { val r = Request("/hello-hello") r.headerMap.put("Accept-Encoding", "gzip") val resp = Response() resp.contentString = "hello-hello" recorder.recordIfNotExists(r, resp) } } .bind[FinagleSyncClient].toProvider { recorder: HttpRecorderServer => FinagleClient.newSyncClient(recorder.localAddress) } } def `support simple path matcher`(client: FinagleSyncClient): Unit = { client.get[String]("/hello") shouldBe "hello" client.get[String]("/hello-hello") shouldBe "hello-hello" } }
Example 7
Source File: FinagleRetryFilter.scala From airframe with Apache License 2.0 | 5 votes |
package wvlet.airframe.http.finagle import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.finagle.util.DefaultTimer import com.twitter.finagle.{Service, SimpleFilter, http} import com.twitter.util._ import wvlet.airframe.control.ResultClass import wvlet.airframe.control.Retry.{MaxRetryException, RetryContext} import wvlet.airframe.http.{HttpClientException, HttpClientMaxRetryException} import wvlet.log.LogSupport class FinagleRetryFilter(retry: RetryContext, timer: Timer = DefaultTimer) extends SimpleFilter[http.Request, http.Response] with LogSupport { import com.twitter.conversions.DurationOps._ private[this] def schedule(d: Duration)(f: => Future[Response]) = { if (d > 0.seconds) { val promise = new Promise[Response] timer.schedule(Time.now + d) { promise.become(f) } promise } else { f } } private def dispatch( retryContext: RetryContext, request: Request, service: Service[Request, Response] ): Future[Response] = { val rep = service(request) rep.transform { x => val classifier = x match { case Throw(e) => retryContext.errorClassifier(e) case Return(r) => retryContext.resultClassifier(r) } classifier match { case ResultClass.Succeeded => rep case ResultClass.Failed(isRetryable, cause, extraWait) => { if (!retryContext.canContinue) { // Reached the max retry rep.flatMap { r => Future.exception(HttpClientMaxRetryException(FinagleHttpResponseWrapper(r), retryContext, cause)) } } else if (!isRetryable) { // Non-retryable failure Future.exception(cause) } else { Future .value { // Update the retry count retryContext.withExtraWait(extraWait).nextRetry(cause) }.flatMap { nextRetryContext => // Wait until the next retry schedule(nextRetryContext.nextWaitMillis.millis) { // Run the same request again dispatch(nextRetryContext, request, service) } } } } } } } override def apply(request: Request, service: Service[Request, Response]): Future[Response] = { val retryContext = retry.init(Option(request)) dispatch(retryContext, request, service) } }
Example 8
Source File: FinagleBackend.scala From airframe with Apache License 2.0 | 5 votes |
package wvlet.airframe.http.finagle import java.util.concurrent.atomic.AtomicReference import com.twitter.finagle.Service import com.twitter.finagle.context.Contexts import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.util.{Future, Promise, Return, Throw} import wvlet.airframe.http.{HttpBackend, HttpRequestAdapter, HttpStatus} import wvlet.log.LogSupport import scala.concurrent.ExecutionContext import scala.util.{Failure, Success} import scala.{concurrent => sc} object FinagleBackend extends HttpBackend[Request, Response, Future] { override protected implicit val httpRequestAdapter: HttpRequestAdapter[Request] = FinagleHttpRequestAdapter override def wrapException(e: Throwable): Future[Response] = { Future.exception(e) } override def newResponse(status: HttpStatus, content: String): Response = { val r = Response(Status.fromCode(status.code)) r.contentString = content r } def wrapFilter(filter: com.twitter.finagle.Filter[Request, Response, Request, Response]): FinagleFilter = { new FinagleFilter with LogSupport { override def apply(request: Request, context: Context): Future[Response] = { filter(request, Service.mk { req: Request => context(req) }) } } } override def toFuture[A](a: A): Future[A] = Future.value(a) override def toScalaFuture[A](a: Future[A]): sc.Future[A] = { val promise: sc.Promise[A] = sc.Promise() a.respond { case Return(value) => promise.success(value) case Throw(exception) => promise.failure(exception) } promise.future } override def toFuture[A](a: sc.Future[A], e: ExecutionContext): Future[A] = { val promise: Promise[A] = Promise() a.onComplete { case Success(value) => promise.setValue(value) case Failure(exception) => promise.setException(exception) }(e) promise } override def isFutureType(cl: Class[_]): Boolean = { classOf[Future[_]].isAssignableFrom(cl) } override def isRawResponseType(cl: Class[_]): Boolean = { classOf[Response].isAssignableFrom(cl) } override def mapF[A, B](f: Future[A], body: A => B): Future[B] = { f.map(body) } private val contextParamHolderKey = new Contexts.local.Key[AtomicReference[collection.mutable.Map[String, Any]]] override def withThreadLocalStore(body: => Future[Response]): Future[Response] = { val newParamHolder = collection.mutable.Map.empty[String, Any] Contexts.local .let(contextParamHolderKey, new AtomicReference[collection.mutable.Map[String, Any]](newParamHolder)) { body } } override def setThreadLocal[A](key: String, value: A): Unit = { Contexts.local.get(contextParamHolderKey).foreach { ref => ref.get().put(key, value) } } override def getThreadLocal[A](key: String): Option[A] = { Contexts.local.get(contextParamHolderKey).flatMap { ref => ref.get.get(key).asInstanceOf[Option[A]] } } }
Example 9
Source File: FinagleFilter.scala From airframe with Apache License 2.0 | 5 votes |
package wvlet.airframe.http.finagle import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Service, SimpleFilter} import com.twitter.util.Future import wvlet.airframe.Session import wvlet.airframe.codec.MessageCodecFactory import wvlet.airframe.http.{HttpBackend, HttpFilter} import wvlet.airframe.http.router.HttpRequestDispatcher abstract class FinagleFilter extends HttpFilter[Request, Response, Future] { override def backend: HttpBackend[Request, Response, Future] = FinagleBackend } class FinagleRouter(session: Session, private[finagle] val config: FinagleServerConfig) extends SimpleFilter[Request, Response] { private val dispatcher = HttpRequestDispatcher.newDispatcher( session, config.router, config.controllerProvider, FinagleBackend, config.responseHandler, MessageCodecFactory.defaultFactory.orElse(MessageCodecFactory.newFactory(config.customCodec)) ) override def apply(request: Request, service: Service[Request, Response]): Future[Response] = { dispatcher.apply(request, FinagleBackend.newContext { request: Request => service(request) }) } }
Example 10
Source File: FinagleServerFactoryTest.scala From airframe with Apache License 2.0 | 5 votes |
package wvlet.airframe.http.finagle import com.twitter.finagle.Service import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.finagle.tracing.ConsoleTracer import com.twitter.util.Future import wvlet.airframe.control.Control._ import wvlet.airframe.http.Router import wvlet.airspec.AirSpec class FinagleServerFactoryTest extends AirSpec { def `start multiple FinagleServers`: Unit = { val router1 = Router.add[MyApi] val router2 = Router.add[MyApi] val serverConfig1 = Finagle.server .withName("server1") .withRouter(router1) val serverConfig2 = Finagle.server .withName("server2") .withRouter(router2) finagleDefaultDesign.build[FinagleServerFactory] { factory => val server1 = factory.newFinagleServer(serverConfig1) val server2 = factory.newFinagleServer(serverConfig2) withResources( Finagle.newSyncClient(s"localhost:${server1.port}"), Finagle.newSyncClient(s"localhost:${server2.port}") ) { (client1, client2) => client1.send(Request("/v1/info")).contentString shouldBe "hello MyApi" client2.send(Request("/v1/info")).contentString shouldBe "hello MyApi" } } } def `allow customize services`: Unit = { val d = Finagle.server.withFallbackService { new Service[Request, Response] { override def apply(request: Request): Future[Response] = { val r = Response(Status.Ok) r.contentString = "hello custom server" Future.value(r) } } }.design d.build[FinagleServer] { server => withResource(Finagle.newSyncClient(s"localhost:${server.port}")) { client => client.send(Request("/v1")).contentString shouldBe "hello custom server" } } } def `allow customize Finagle Http Server`: Unit = { Finagle.server .withTracer(ConsoleTracer) .withFallbackService( new Service[Request, Response] { override def apply(request: Request): Future[Response] = { val r = Response(Status.Ok) r.contentString = "hello custom server with tracer" Future.value(r) } } ) .start { server => withResource(Finagle.newSyncClient(server.localAddress)) { client => client.send(Request("/v1")).contentString shouldBe "hello custom server with tracer" } } } }
Example 11
Source File: LeafFilterTest.scala From airframe with Apache License 2.0 | 5 votes |
package wvlet.airframe.http.finagle import com.twitter.finagle.http.{Request, Response} import com.twitter.util.Future import wvlet.airframe.Design import wvlet.airframe.http.{HttpFilter, Router} import wvlet.airspec.AirSpec object LeafFilterTest { class MyFilter extends FinagleFilter { override def apply(request: Request, context: Context): Future[Response] = { val r = Response() r.contentString = "leaf filter" toFuture(r) } } } class LeafFilterTest extends AirSpec { import LeafFilterTest._ override protected def design: Design = { newFinagleServerDesign(name = "leaf-filter-test", router = Router.add[MyFilter]) .add(finagleSyncClientDesign) } def `support leaf filters`(client: FinagleSyncClient): Unit = { client.get[String]("/") shouldBe "leaf filter" } }
Example 12
Source File: StaticContentTest.scala From airframe with Apache License 2.0 | 5 votes |
package wvlet.airframe.http.finagle import com.twitter.finagle.http.Response import wvlet.airframe.Design import wvlet.airframe.control.Control import wvlet.airframe.http._ import wvlet.airspec.AirSpec import wvlet.log.io.{IOUtil, Resource} object StaticContentTest { trait StaticContentServer { @Endpoint(path = "/html class StaticContentTest extends AirSpec { override protected def design: Design = { val r = Router.add[StaticContentTest.StaticContentServer] Finagle.server .withName("static-content-test").withRouter(r).design .add(Finagle.client.syncClientDesign) } def `serve static contents from resources in classpath`(client: FinagleSyncClient): Unit = { val res = client.get[Response]("/html/index.html") val html = res.contentString debug(html) html.contains("Hello Airframe HTTP!") shouldBe true res.contentType shouldBe Some("text/html") } def `forbid accessing parent resources`(client: FinagleSyncClient): Unit = { val ex = intercept[HttpClientException] { client.get[String]("/html/../hidden/secret.txt") } ex.status shouldBe HttpStatus.Forbidden_403 val ex2 = intercept[HttpClientException] { client.get[String]("/html/dummy/../../hidden/secret.txt") } ex2.status shouldBe HttpStatus.Forbidden_403 } def `support safe relative paths`(client: FinagleSyncClient): Unit = { // OK val html = client.get[String]("/html/asset/../index.html") html.contains("Hello Airframe HTTP!") shouldBe true } def `set content-type`(client: FinagleSyncClient): Unit = { def check(path: String, expectedContentType: String): Unit = { val r = client.get[Response](path) r.contentType shouldBe Some(expectedContentType) } check("/html/index.html", "text/html") check("/html/asset/style.css", "text/css") check("/html/data/sample.json", "application/json") check("/html/asset/test.js", "application/javascript") check("/html/asset/airframe_icon_small.png", "image/png") // TODO add more coverage } def `read binary file`(client: FinagleSyncClient): Unit = { val resp = client.get[Response]("/html/asset/airframe_icon_small.png") val img = resp.contentBytes val imgUrl = Resource.find("/wvlet/airframe/http/finagle/static/asset/airframe_icon_small.png").get Control.withResource(imgUrl.openStream()) { in => IOUtil.readFully(in) { bytes => img shouldBe bytes } } } def `read from an alternative static content path`(client: FinagleSyncClient): Unit = { val html = client.get[String]("/html2/index2.html") html.contains("static2") shouldBe true } def `read from a directory`(client: FinagleSyncClient): Unit = { val html = client.get[String]("/html3/index.html") html.contains("Hello Airframe HTTP!") shouldBe true val html2 = client.get[String]("/html4/index.html") html2.contains("Hello Airframe HTTP!") shouldBe true } }
Example 13
Source File: ThreadLocalStorageTest.scala From airframe with Apache License 2.0 | 5 votes |
package wvlet.airframe.http.finagle import com.twitter.finagle.http.{Request, Response} import com.twitter.util.Future import wvlet.airframe.Design import wvlet.airframe.http.{Endpoint, HttpContext, Router} import wvlet.airspec.AirSpec class ThreadLocalStorageTest extends AirSpec { class MyApp { @Endpoint(path = "/get") def get(context: FinagleContext): Unit = { context.setThreadLocal("mydata", "hello tls") } @Endpoint(path = "/read") def read(context: FinagleContext): String = { context.getThreadLocal[String]("client_id").getOrElse("unknown") } } class TLSReaderFilter extends FinagleFilter { override def apply(request: Request, context: HttpContext[Request, Response, Future]): Future[Response] = { context.setThreadLocal[String]("client_id", "xxxyyy") context(request).map { x => // Read TLS set by the child MyApp service val mydata = context.getThreadLocal("mydata") if (request.path == "/get") { val r = Response() r.contentString = mydata.getOrElse("N/A") r } else { x } } } } override protected def design: Design = { val router = Router.add[TLSReaderFilter].andThen[MyApp] newFinagleServerDesign(name = "tls-test", router = router) .bind[FinagleSyncClient].toProvider { server: FinagleServer => Finagle.client.noRetry.newSyncClient(server.localAddress) } } test("tls test") { client: FinagleSyncClient => test("read thread-local data set at the leaf filter") { val resp = client.get[String]("/get") resp shouldBe "hello tls" } test("read thread-local data set by the parent filter") { val resp = client.get[String]("/read") resp shouldBe "xxxyyy" } } }
Example 14
Source File: CorsFilterTest.scala From airframe with Apache License 2.0 | 5 votes |
package wvlet.airframe.http.finagle import com.twitter.finagle.{Service, SimpleFilter} import com.twitter.finagle.http.{Request, Response} import com.twitter.util.Future import wvlet.airframe.Design import wvlet.airframe.http.Router import wvlet.airframe.http.finagle.CorsFilterTest.{CheckFilter, LogFilter, SimpleFilter} import wvlet.airframe.http.finagle.filter.CorsFilter import wvlet.airspec.AirSpec import wvlet.log.LogSupport object CorsFilterTest { // Test SimpleFilter of Finagle object CheckFilter extends SimpleFilter[Request, Response] with LogSupport { override def apply(request: Request, service: Service[Request, Response]): Future[Response] = { info(s"checking request: ${request}") service(request) } } object LogFilter extends FinagleFilter with LogSupport { override def apply( request: Request, context: LogFilter.Context ): Future[Response] = { info(s"logging request: ${request}") context(request) } } object SimpleFilter extends FinagleFilter with LogSupport { override def apply( request: Request, context: SimpleFilter.Context ): Future[Response] = { toFuture { info(s"handling request: ${request}") val r = Response() r.contentString = request.headerMap.mkString(", ") r } } } } class CorsFilterTest extends AirSpec { override protected def design: Design = { val r = Router .add(LogFilter) .andThen(FinagleBackend.wrapFilter(CheckFilter)) .andThen(CorsFilter.unsafePermissiveFilter) .andThen(SimpleFilter) debug(r) newFinagleServerDesign(router = r) .add(finagleSyncClientDesign) } def `support CORS filter`(client: FinagleSyncClient): Unit = { val resp = client.get[String]("/") debug(resp) } }
Example 15
Source File: FinatraHttpServer.scala From the-finagle-docs with MIT License | 5 votes |
package net.gutefrage.basic import javax.inject.{Inject, Singleton} import com.google.inject.{Module, Provides} import com.twitter.finagle.Dtab import com.twitter.finagle.http.{Request, Response} import com.twitter.finatra.http.{Controller, HttpServer} import com.twitter.finatra.http.filters.{CommonFilters, LoggingMDCFilter, TraceIdMDCFilter} import com.twitter.finatra.http.routing.HttpRouter import com.twitter.finatra.response.Mustache import com.twitter.inject.TwitterModule import com.twitter.inject.annotations.Flag import net.gutefrage.Dtabs import net.gutefrage.temperature.thrift.TemperatureService object FinatraHttpServer extends HttpServer { premain { Dtabs.init() } override def modules: Seq[Module] = Seq(TemperatureServiceModule) override def defaultFinatraHttpPort = ":9000" override protected def configureHttp(router: HttpRouter): Unit = router .filter[LoggingMDCFilter[Request, Response]] .filter[TraceIdMDCFilter[Request, Response]] .filter[CommonFilters] .add[WeatherController] } class WeatherController @Inject()( temperatureService: TemperatureService.FutureIface, @Flag("local.doc.root") localDocRoot: String, @Flag("doc.root") docRoot: String ) extends Controller { private val docConfig = DocConfig(localDocRoot, docRoot) get("/") { request: Request => temperatureService.mean().map { meanTemperature => DashboardData(meanTemperature, Some("local"), docConfig) } } // Change dtab according to the environment get("/:env") { request: Request => val environment = request.params("env") Dtab.unwind { Dtab.local = Dtab.read(s"/env => /s#/$environment") temperatureService.mean().map { meanTemperature => DashboardData(meanTemperature, Some(environment), docConfig) } } } // Asset route (for styles.css) get("/assets/:*") { request: Request => response.ok.file("/assets/" + request.params("*")) } } @Mustache("dashboard") case class DashboardData( meanTemperature: Double, environment: Option[String], docConfig: DocConfig ) case class DocConfig(localDocRoot: String, docRoot: String)
Example 16
Source File: TodoListApp.scala From freestyle with Apache License 2.0 | 5 votes |
package examples.todolist import cats._ import cats.effect.IO import cats.implicits._ import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, ListeningServer, Service} import com.twitter.server.TwitterServer import com.twitter.util.{Await, Future} import doobie.util.transactor.Transactor import examples.todolist.http.Api import examples.todolist.persistence.Persistence import examples.todolist.services.Services import freestyle.tagless.config.ConfigM import freestyle.tagless.config.implicits._ import freestyle.tagless.effects.error.ErrorM import freestyle.tagless.effects.error.implicits._ import freestyle.tagless.logging.LoggingM import freestyle.tagless.loggingJVM.log4s.implicits._ import freestyle.tagless.module import io.circe.generic.auto._ import io.finch.circe._ @module trait App[F[_]] { val persistence: Persistence[F] val services: Services[F] } object TodoListApp extends TwitterServer { import examples.todolist.runtime.implicits._ def bootstrap[F[_]: Monad]( implicit app: App[F], handler: F ~> Future, T: Transactor[F], api: Api[F]): F[ListeningServer] = { val service: Service[Request, Response] = api.endpoints.toService val log: LoggingM[F] = app.services.log val cfg: ConfigM[F] = app.services.config for { _ <- log.info("Trying to load application.conf") config <- cfg.load host = config.string("http.host").getOrElse("localhost") port = config.int("http.port").getOrElse("8080") _ <- log.debug(s"Host: $host") _ <- log.debug(s"Port $port") } yield Await.ready( Http.server.withAdmissionControl .concurrencyLimit(maxConcurrentRequests = 10, maxWaiters = 10) .serve(s"$host:$port", service) ) } def main() = bootstrap[IO].unsafeRunAsync { case Left(error) => println(s"Error executing server. ${error.getMessage}") case Right(server) => server.close() } }
Example 17
Source File: CustomTelemetryService.scala From finagle-prometheus with MIT License | 5 votes |
package com.samstarling.prometheusfinagle.examples import java.text.SimpleDateFormat import java.util.Calendar import com.samstarling.prometheusfinagle.metrics.Telemetry import com.twitter.finagle.Service import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.util.Future class CustomTelemetryService(telemetry: Telemetry) extends Service[Request, Response] { private val dayOfWeekFormat = new SimpleDateFormat("E") private val counter = telemetry.counter("requests_by_day_of_week", "Help text", Seq("day_of_week")) override def apply(request: Request): Future[Response] = { dayOfWeek counter.labels(dayOfWeek).inc() val rep = Response(request.version, Status.Ok) rep.setContentString("Your request was logged!") Future(rep) } private def dayOfWeek: String = { dayOfWeekFormat.format(Calendar.getInstance.getTime) } }
Example 18
Source File: EmojiService.scala From finagle-prometheus with MIT License | 5 votes |
package com.samstarling.prometheusfinagle.examples import com.twitter.finagle.{Http, Service} import com.twitter.finagle.http.{Method, Request, Response, Status} import com.twitter.finagle.loadbalancer.LoadBalancerFactory import com.twitter.finagle.stats.{DefaultStatsReceiver, StatsReceiver} import com.twitter.util.Future class EmojiService(statsReceiver: StatsReceiver) extends Service[Request, Response] { private val client = Http.client .withTls("api.github.com") .withStatsReceiver(statsReceiver) .withHttpStats .configured(LoadBalancerFactory.HostStats(statsReceiver.scope("host"))) .newService("api.github.com:443", "GitHub") private val emojiRequest = Request(Method.Get, "/emojis") emojiRequest.headerMap.add("User-Agent", "My-Finagle-Example") override def apply(request: Request): Future[Response] = { client.apply(emojiRequest).map { resp => val r = Response(request.version, Status.Ok) r.setContentString(resp.getContentString()) r } } }
Example 19
Source File: MetricsService.scala From finagle-prometheus with MIT License | 5 votes |
package com.samstarling.prometheusfinagle.metrics import java.io.StringWriter import com.twitter.finagle.Service import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.util.Future import io.prometheus.client.CollectorRegistry import io.prometheus.client.exporter.common.TextFormat class MetricsService(registry: CollectorRegistry) extends Service[Request, Response] { override def apply(request: Request): Future[Response] = { val writer = new StringWriter TextFormat.write004(writer, registry.metricFamilySamples()) val response = Response(request.version, Status.Ok) response.setContentString(writer.toString) Future(response) } }
Example 20
Source File: HttpMonitoringFilter.scala From finagle-prometheus with MIT License | 5 votes |
package com.samstarling.prometheusfinagle.filter import com.samstarling.prometheusfinagle.metrics.Telemetry import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Service, SimpleFilter} import com.twitter.util.Future class HttpMonitoringFilter(telemetry: Telemetry, labeller: ServiceLabeller[Request, Response] = new HttpServiceLabeller) extends SimpleFilter[Request, Response] { private val counter = telemetry.counter( name = "incoming_http_requests_total", help = "The number of incoming HTTP requests", labelNames = labeller.keys ) override def apply(request: Request, service: Service[Request, Response]): Future[Response] = { service(request) onSuccess { response => counter.labels(labeller.labelsFor(request, response): _*).inc() } } }
Example 21
Source File: HttpLatencyMonitoringFilter.scala From finagle-prometheus with MIT License | 5 votes |
package com.samstarling.prometheusfinagle.filter import com.samstarling.prometheusfinagle.metrics.Telemetry import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Service, SimpleFilter} import com.twitter.util.{Future, Stopwatch} class HttpLatencyMonitoringFilter(telemetry: Telemetry, buckets: Seq[Double], labeller: ServiceLabeller[Request, Response] = new HttpServiceLabeller) extends SimpleFilter[Request, Response] { private val histogram = telemetry.histogram( name = "incoming_http_request_latency_seconds", help = "A histogram of the response latency for HTTP requests", labelNames = labeller.keys, buckets = buckets ) override def apply(request: Request, service: Service[Request, Response]): Future[Response] = { val stopwatch = Stopwatch.start() service(request) onSuccess { response => histogram .labels(labeller.labelsFor(request, response): _*) .observe(stopwatch().inMilliseconds / 1000.0) } } }
Example 22
Source File: HttpLatencyMonitoringFilterSpec.scala From finagle-prometheus with MIT License | 5 votes |
package com.samstarling.prometheusfinagle.filter import com.samstarling.prometheusfinagle.UnitTest import com.samstarling.prometheusfinagle.helper.{CollectorHelper, CollectorRegistryHelper} import com.samstarling.prometheusfinagle.metrics.Telemetry import com.twitter.finagle.Service import com.twitter.finagle.http.{Method, Request, Response, Status} import com.twitter.finagle.util.DefaultTimer import com.twitter.util.{Await, Duration, Future, Timer} import io.prometheus.client.CollectorRegistry import org.specs2.specification.Scope class HttpLatencyMonitoringFilterSpec extends UnitTest { class SlowService extends Service[Request, Response] { implicit val timer = DefaultTimer.twitter override def apply(request: Request): Future[Response] = { Future .value(Response(request.version, Status.Ok)) .delayed(Duration.fromMilliseconds(1500)) } } trait Context extends Scope { val registry = new CollectorRegistry(true) val registryHelper = CollectorRegistryHelper(registry) val telemetry = new Telemetry(registry, "test") val buckets = Seq(1.0, 2.0) val labeller = new TestLabeller val filter = new HttpLatencyMonitoringFilter(telemetry, buckets, labeller) val service = mock[Service[Request, Response]] val slowService = new SlowService val request = Request(Method.Get, "/foo/bar") val serviceResponse = Response(Status.Created) val histogram = telemetry.histogram(name = "incoming_http_request_latency_seconds") service.apply(request) returns Future.value(serviceResponse) } "HttpLatencyMonitoringFilter" >> { "passes requests on to the next service" in new Context { Await.result(filter.apply(request, service)) there was one(service).apply(request) } "returns the Response from the next service" in new Context { val actualResponse = Await.result(filter.apply(request, service)) actualResponse ==== serviceResponse } "counts the request" in new Context { Await.result(filter.apply(request, slowService)) registryHelper.samples .get("test_incoming_http_request_latency_seconds_count") .map(_.map(_.value).sum) must beSome(1.0).eventually } "increments the counter with the labels from the labeller" in new Context { Await.result(filter.apply(request, service)) registryHelper.samples .get("test_incoming_http_request_latency_seconds_count") .map(_.head.dimensions.get("foo").get) must beSome("bar").eventually } "categorises requests into the correct bucket" in new Context { Await.result(filter.apply(request, slowService)) // Our request takes ~1500ms, so it should NOT fall into the "less than or equal to 1 second" bucket (le=0.5) registryHelper.samples .get("test_incoming_http_request_latency_seconds_bucket") .flatMap(_.find(_.dimensions.get("le").contains("1.0"))) .map(_.value) must beSome(0.0).eventually // However, it should fall into the "less than or equal to 2 seconds" bucket (le=0.5) registryHelper.samples .get("test_incoming_http_request_latency_seconds_bucket") .flatMap(_.find(_.dimensions.get("le").contains("2.0"))) .map(_.value) must beSome(1.0).eventually // It should also fall into the "+Inf" bucket registryHelper.samples .get("test_incoming_http_request_latency_seconds_bucket") .flatMap(_.find(_.dimensions.get("le").contains("+Inf"))) .map(_.value) must beSome(1.0).eventually } } }
Example 23
Source File: HttpServiceLabellerSpec.scala From finagle-prometheus with MIT License | 5 votes |
package com.samstarling.prometheusfinagle.filter import com.samstarling.prometheusfinagle.UnitTest import com.twitter.finagle.http.{Method, Request, Response, Status} import org.specs2.specification.Scope class HttpServiceLabellerSpec extends UnitTest { trait Context extends Scope { val request = Request(Method.Get, "/foo/bar") val response = Response(Status.Ok) val labeller = new HttpServiceLabeller() val labels = labeller.labelsFor(request, response) } "keys" >> { "returns the keys in the correct order" in new Context { labeller.keys ==== Seq("status", "statusClass", "method") } } "labelsFor" >> { "returns the status code of the response" in new Context { labels(0) ==== "200" } "returns the status class of the request" in new Context { labels(1) ==== "2xx" } "returns the method of the request" in new Context { labels(2) ==== "GET" } } }
Example 24
Source File: HttpMonitoringFilterSpec.scala From finagle-prometheus with MIT License | 5 votes |
package com.samstarling.prometheusfinagle.filter import com.samstarling.prometheusfinagle.UnitTest import com.samstarling.prometheusfinagle.helper.CollectorHelper import com.samstarling.prometheusfinagle.metrics.Telemetry import com.twitter.finagle.Service import com.twitter.finagle.http.{Method, Request, Response, Status} import com.twitter.util.{Await, Future} import io.prometheus.client.CollectorRegistry import org.specs2.specification.Scope import scala.collection.JavaConverters._ class HttpMonitoringFilterSpec extends UnitTest { trait Context extends Scope { val registry = new CollectorRegistry(true) val telemetry = new Telemetry(registry, "test") val labeller = new TestLabeller val filter = new HttpMonitoringFilter(telemetry, labeller) val service = mock[Service[Request, Response]] val request = Request(Method.Get, "/foo/bar") val serviceResponse = Response(Status.Created) val counter = telemetry.counter(name = "incoming_http_requests_total") service.apply(request) returns Future.value(serviceResponse) } "HttpMonitoringFilter" >> { "passes requests on to the next service" in new Context { Await.result(filter.apply(request, service)) there was one(service).apply(request) } "returns the Response from the next service" in new Context { val actualResponse = Await.result(filter.apply(request, service)) actualResponse ==== serviceResponse } "increments the incoming_http_requests_total counter" in new Context { Await.result(filter.apply(request, service)) Await.result(filter.apply(request, service)) CollectorHelper.firstSampleFor(counter).map { sample => sample.value ==== 2.0 } } "adds the correct help label" in new Context { Await.result(filter.apply(request, service)) CollectorHelper.firstMetricFor(counter).map { metric => metric.help ==== "The number of incoming HTTP requests" } } "increments the counter with the labels from the labeller" in new Context { Await.result(filter.apply(request, service)) CollectorHelper.firstSampleFor(counter).map { sample => sample.labelNames.asScala(0) ==== "foo" sample.labelValues.asScala(0) ==== "bar" } } } }
Example 25
Source File: ContractProxyExample.scala From fintrospect with Apache License 2.0 | 5 votes |
package examples.clients import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.filter.Cors import com.twitter.finagle.http.filter.Cors.HttpFilter import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await import io.fintrospect.configuration.{Credentials, Host, Port} import io.fintrospect.filters.RequestFilters.{AddHost, BasicAuthorization} import io.fintrospect.parameters.Query import io.fintrospect.{Contract, ContractEndpoint, ContractProxyModule, RouteSpec} object ContractProxyExample extends App { val proxyModule = ContractProxyModule("brewdog", BrewdogApiHttp(), BrewdogApiContract) Await.ready( Http.serve(":9000", new HttpFilter(Cors.UnsafePermissivePolicy).andThen(proxyModule.toService)) ) } object BrewdogApiHttp { private val apiAuthority = Host("punkapi.com").toAuthority(Port(443)) def apply(): Service[Request, Response] = { AddHost(apiAuthority) .andThen(BasicAuthorization(Credentials("22244d6b88574064bbbfe284f1631eaf", ""))) .andThen(Http.client.withTlsWithoutValidation.newService(apiAuthority.toString)) } } object BrewdogApiContract extends Contract { object LookupBeers extends ContractEndpoint { val brewedBefore = Query.optional.string("brewed_before", "e.g. 01-2010 (format is mm-yyyy)") val alcoholContent = Query.optional.int("abv_gt", "Minimum alcohol %") override val route = RouteSpec("lookup beers") .taking(brewedBefore) .taking(alcoholContent) .at(Get) / "api" / "v1" / "beers" } object RandomBeer extends ContractEndpoint { override val route = RouteSpec("get a random beer recipe") .at(Get) / "api" / "v1" / "beers" / "random" } }
Example 26
Source File: ClientSideAndSharedRouteSpecExample.scala From fintrospect with Apache License 2.0 | 5 votes |
package examples.clients import java.time.LocalDate import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await import io.fintrospect.RouteSpec import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.parameters._ import io.fintrospect.testing.TestHttpServer import io.fintrospect.util.HttpRequestResponseUtil.{headersFrom, statusAndContentFrom} object ClientSideAndSharedRouteSpecExample extends App { val theDate = Path.localDate("date") val theWeather = Query.optional.string("weather") val theUser = Header.required.string("user") val gender = FormField.optional.string("gender") val body = Body.form(gender) val sharedRouteSpec = RouteSpec() .taking(theUser) .taking(theWeather) .body(body) .at(Get) / "firstSection" / theDate val fakeServerRoute = sharedRouteSpec bindTo (dateFromPath => Service.mk[Request, Response] { request: Request => { println("URL was " + request.uri) println("Headers were " + headersFrom(request)) println("Form sent was " + (body <-- request)) println("Date send was " + dateFromPath.toString) Ok(dateFromPath.toString) } }) Await.result(new TestHttpServer(10000, fakeServerRoute).start()) val client = sharedRouteSpec bindToClient Http.newService("localhost:10000") val theCall = client(theWeather --> Option("sunny"), body --> Form(gender --> "male"), theDate --> LocalDate.of(2015, 1, 1), theUser --> System.getenv("USER")) val response = Await.result(theCall) println("Response headers: " + headersFrom(response)) println("Response: " + statusAndContentFrom(response)) }
Example 27
Source File: BookAdd.scala From fintrospect with Apache License 2.0 | 5 votes |
package examples.extended import com.twitter.finagle.Service import com.twitter.finagle.http.{Method, Request, Response, Status} import io.fintrospect.formats.Argo.ResponseBuilder._ import io.fintrospect.parameters.{Body, Path} import io.fintrospect.{ResponseSpec, RouteSpec} class BookAdd(books: Books) { private val exampleBook = Book("the title", "the author", 666) private val bookExistsResponse = Conflict("Book with that ISBN exists") private val jsonBody = Body.json("book content", exampleBook.toJson) private def addBook(isbn: String) = Service.mk { request: Request => books.lookup(isbn) match { case Some(_) => bookExistsResponse case None => { val book = Book.unapply(jsonBody <-- request).get books.add(isbn, book) Created(book.toJson) } } } val route = RouteSpec("add book by isbn number", "This book must not already exist") .body(jsonBody) .returning(ResponseSpec.json(Status.Created -> "we added your book", exampleBook.toJson)) .returning(bookExistsResponse) .at(Method.Post) / "book" / Path.string("isbn", "the isbn of the book") bindTo addBook }
Example 28
Source File: BookLookup.scala From fintrospect with Apache License 2.0 | 5 votes |
package examples.extended import com.twitter.finagle.Service import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.{Request, Response, Status} import io.fintrospect.ContentTypes.APPLICATION_JSON import io.fintrospect.RouteSpec import io.fintrospect.formats.Argo.ResponseBuilder._ import io.fintrospect.parameters.Path class BookLookup(books: Books) { private def lookupByIsbn(isbn: String) = Service.mk { request: Request => books.lookup(isbn) match { case Some(book) => Ok(book.toJson) case _ => NotFound("No book found with isbn") } } val route = RouteSpec("lookup book by isbn number") .producing(APPLICATION_JSON) .returning(NotFound("no book was found with this ISBN")) .returning(Status.Ok -> "we found your book", Book("a book", "authorName", 99).toJson) .at(Get) / "book" / Path.string("isbn", "the isbn of the book") bindTo lookupByIsbn }
Example 29
Source File: AddMessage.scala From fintrospect with Apache License 2.0 | 5 votes |
package examples.circe import com.twitter.finagle.Service import com.twitter.finagle.http.Method.Post import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.util.Future import io.circe.generic.auto._ import io.fintrospect.RouteSpec import io.fintrospect.formats.Circe import io.fintrospect.formats.Circe.Auto._ import io.fintrospect.formats.Circe.responseSpec import io.fintrospect.parameters.{Body, Path} class AddMessage(emails: Emails) { private val exampleEmail = Email(EmailAddress("[email protected]"), EmailAddress("[email protected]"), "when are you going to be home for dinner", 250) private val email = Body.of(Circe.bodySpec[Email](), "email", exampleEmail) private def addEmail(address: EmailAddress): Service[Request, Response] = InOut(Service.mk { newEmail: Email => { // validate that the receiver is as passed as the one in the URL if (address == newEmail.to) emails.add(newEmail) Future(emails.forUser(newEmail.to)) } }) val route = RouteSpec("add an email and return the new inbox contents for the receiver") .body(email) .returning(responseSpec(Status.Ok -> "new list of emails for the 'to' user", Seq(exampleEmail))) .at(Post) / "email" / Path.of(EmailAddress.spec, "email") bindTo addEmail }
Example 30
Source File: FakeRemoteLibrary.scala From fintrospect with Apache License 2.0 | 5 votes |
package presentation._6 import com.twitter.finagle.http.filter.Cors import com.twitter.finagle.http.filter.Cors.HttpFilter import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import io.fintrospect.RouteModule import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.renderers.simplejson.SimpleJson import presentation.Books class FakeRemoteLibrary(books: Books) { def search(titlePart: String) = Service.mk[Request, Response] { request => { val results = books.titles().filter(_.toLowerCase.contains(titlePart.toLowerCase)) Ok(results.mkString(",")) } } val service = RouteModule(Root, SimpleJson()) .withRoute(RemoteBooks.route bindTo search) .toService val searchService = new HttpFilter(Cors.UnsafePermissivePolicy).andThen(service) Http.serve(":10000", searchService) }
Example 31
Source File: SearchApp.scala From fintrospect with Apache License 2.0 | 5 votes |
package presentation._6 import com.twitter.finagle.http.Method.{Get, Post} import com.twitter.finagle.http.filter.Cors import com.twitter.finagle.http.filter.Cors.HttpFilter import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.finagle.{Http, Service} import io.fintrospect.formats.Argo.JsonFormat.array import io.fintrospect.formats.Argo.ResponseBuilder._ import io.fintrospect.parameters.{Body, BodySpec, Query} import io.fintrospect.renderers.swagger2dot0.{ApiInfo, Swagger2dot0Json} import io.fintrospect.{ResponseSpec, RouteModule, RouteSpec} import presentation.Book class SearchRoute(books: RemoteBooks) { private val titlePartParam = Query.required.string("titlePart") def search() = Service.mk[Request, Response] { request => { val titlePart = titlePartParam <-- request books.search(titlePart) .map(results => results.split(",").map(Book(_)).toSeq) .map(books => Ok(array(books.map(_.toJson)))) } } val route = RouteSpec("search books") .taking(titlePartParam) .returning(ResponseSpec.json(Status.Ok -> "search results", array(Book("1984").toJson))) .at(Get) / "search" bindTo search } class BookAvailable(books: RemoteBooks) { private val bodySpec = BodySpec.json().map(Book.fromJson, (b: Book) => b.toJson) private val body = Body.of(bodySpec, "a book", Book("1984")) def availability() = Service.mk[Request, Response] { request => { val book = body <-- request books.search(book.title) .map(results => { if (results.length > 0) Ok("cool") else NotFound("!") }) } } val route = RouteSpec("find if the book is owned") .body(body) .returning(Status.Ok -> "book is available") .returning(Status.NotFound -> "book not found") .at(Post) / "availability" bindTo availability } class SearchApp { private val apiInfo = ApiInfo("search some books", "1.0", "an api for searching our book collection") val service = RouteModule(Root, Swagger2dot0Json(apiInfo)) .withRoute(new SearchRoute(new RemoteBooks).route) .withRoute(new BookAvailable(new RemoteBooks).route) .toService val searchService = new HttpFilter(Cors.UnsafePermissivePolicy).andThen(service) Http.serve(":9000", searchService) }
Example 32
Source File: FakeRemoteLibrary.scala From fintrospect with Apache License 2.0 | 5 votes |
package presentation._5 import com.twitter.finagle.http.filter.Cors import com.twitter.finagle.http.filter.Cors.HttpFilter import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import io.fintrospect.RouteModule import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.renderers.simplejson.SimpleJson import presentation.Books class FakeRemoteLibrary(books: Books) { def search(titlePart: String) = Service.mk[Request, Response] { request => Ok(books.titles().filter(_.toLowerCase.contains(titlePart.toLowerCase)).mkString(",")) } val service = RouteModule(Root, SimpleJson()) .withRoute(RemoteBooks.route bindTo search) .toService val searchService = new HttpFilter(Cors.UnsafePermissivePolicy).andThen(service) Http.serve(":10000", searchService) }
Example 33
Source File: SearchApp.scala From fintrospect with Apache License 2.0 | 5 votes |
package presentation._5 import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.filter.Cors import com.twitter.finagle.http.filter.Cors.HttpFilter import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.finagle.{Http, Service} import io.fintrospect.formats.Argo.JsonFormat.array import io.fintrospect.formats.Argo.ResponseBuilder._ import io.fintrospect.parameters.Query import io.fintrospect.renderers.swagger2dot0.{ApiInfo, Swagger2dot0Json} import io.fintrospect.{ResponseSpec, RouteModule, RouteSpec} import presentation.Book class SearchRoute(books: RemoteBooks) { private val titlePartParam = Query.required.string("titlePart") def search() = Service.mk[Request, Response] { request => { val titlePart = titlePartParam <-- request books.search(titlePart) .map(results => results.split(",").map(Book(_)).toSeq) .map(books => Ok(array(books.map(_.toJson)))) } } val route = RouteSpec("search books") .taking(titlePartParam) .returning(ResponseSpec.json(Status.Ok -> "search results", array(Book("1984").toJson))) .at(Get) / "search" bindTo search } class SearchApp { private val apiInfo = ApiInfo("search some books", "1.0", "an api for searching our book collection") val service = RouteModule(Root, Swagger2dot0Json(apiInfo)) .withRoute(new SearchRoute(new RemoteBooks).route) .toService val searchService = new HttpFilter(Cors.UnsafePermissivePolicy).andThen(service) Http.serve(":9000", searchService) }
Example 34
Source File: FakeRemoteLibrary.scala From fintrospect with Apache License 2.0 | 5 votes |
package presentation._4 import com.twitter.finagle.http.filter.Cors import com.twitter.finagle.http.filter.Cors.HttpFilter import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import io.fintrospect.RouteModule import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.renderers.simplejson.SimpleJson import presentation.Books class FakeRemoteLibrary(books: Books) { def search(titlePart: String) = Service.mk[Request, Response] { _ => Ok(books.titles().filter(_.toLowerCase.contains(titlePart.toLowerCase)).mkString(",")) } val service = RouteModule(Root, SimpleJson()) .withRoute(RemoteBooks.route bindTo search) .toService val searchService = new HttpFilter(Cors.UnsafePermissivePolicy).andThen(service) Http.serve(":10000", searchService) }
Example 35
Source File: SearchApp.scala From fintrospect with Apache License 2.0 | 5 votes |
package presentation._4 import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.filter.Cors import com.twitter.finagle.http.filter.Cors.HttpFilter import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.parameters.Query import io.fintrospect.renderers.swagger2dot0.{ApiInfo, Swagger2dot0Json} import io.fintrospect.{RouteModule, RouteSpec} class SearchRoute(books: RemoteBooks) { private val titlePartParam = Query.required.string("titlePart") def search() = Service.mk[Request, Response] { request => { val titlePart = titlePartParam <-- request books.search(titlePart) .map(results => Ok(results)) } } val route = RouteSpec("search books") .taking(titlePartParam) .at(Get) / "search" bindTo search } class SearchApp { private val apiInfo = ApiInfo("search some books", "1.0", "an api for searching our book collection") val service = RouteModule(Root, Swagger2dot0Json(apiInfo)) .withRoute(new SearchRoute(new RemoteBooks).route) .toService val searchService = new HttpFilter(Cors.UnsafePermissivePolicy).andThen(service) Http.serve(":9000", searchService) }
Example 36
Source File: SearchApp.scala From fintrospect with Apache License 2.0 | 5 votes |
package presentation._3 import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.filter.Cors import com.twitter.finagle.http.filter.Cors.HttpFilter import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.parameters.Query import io.fintrospect.renderers.swagger2dot0.{ApiInfo, Swagger2dot0Json} import io.fintrospect.{RouteModule, RouteSpec} import presentation.Books class SearchRoute(books: Books) { private val titlePartParam = Query.required.string("titlePart") def search() = Service.mk[Request, Response] { request => { val titlePart = titlePartParam <-- request val results = books.titles().filter(_.toLowerCase.contains(titlePart.toLowerCase)) Ok(results.toString()) } } val route = RouteSpec("search books") .taking(titlePartParam) .at(Get) / "search" bindTo search } class SearchApp(books: Books) { private val apiInfo = ApiInfo("search some books", "1.0", "an api for searching our book collection") val service = RouteModule(Root, Swagger2dot0Json(apiInfo)) .withRoute(new SearchRoute(books).route) .toService val searchService = new HttpFilter(Cors.UnsafePermissivePolicy).andThen(service) Http.serve(":9000", searchService) } object Environment extends App { new SearchApp(new Books) Thread.currentThread().join() }
Example 37
Source File: SearchApp.scala From fintrospect with Apache License 2.0 | 5 votes |
package presentation._2 import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.filter.Cors import com.twitter.finagle.http.filter.Cors.HttpFilter import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.renderers.swagger2dot0.{ApiInfo, Swagger2dot0Json} import io.fintrospect.{RouteModule, RouteSpec} import presentation.Books class SearchApp(books: Books) { def search() = Service.mk[Request, Response] { _ => Ok(books.titles().toString()) } private val apiInfo = ApiInfo("search some books", "1.0", "an api for searching our book collection") val service = RouteModule(Root, Swagger2dot0Json(apiInfo)) .withRoute(RouteSpec("search books").at(Get) / "search" bindTo search) .toService val searchService = new HttpFilter(Cors.UnsafePermissivePolicy).andThen(service) Http.serve(":9000", searchService) } object Environment extends App { new SearchApp(new Books) Thread.currentThread().join() }
Example 38
Source File: MultiPart_Web_Form_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.forms // fintrospect-core object MultiPart_Web_Form_Example extends App { import com.twitter.finagle.http.Method.Post import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import com.twitter.util.Future import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.parameters.{Body, Form, FormField, MultiPartFile} import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} val usernameField = FormField.required.string("user") val fileField = FormField.required.file("data") val form: Body[Form] = Body.multiPartWebForm(usernameField -> "everyone has a name!", fileField -> "file is required!") val svc: Service[Request, Response] = Service.mk[Request, Response] { req => { val postedForm: Form = form <-- req if (postedForm.isValid) successMessage(postedForm) else failureMessage(postedForm) } } def failureMessage(postedForm: Form): Future[Response] = { val errorString = postedForm.errors.map(e => e.param.name + ": " + e.reason).mkString("\n") BadRequest("errors were: " + errorString) } def successMessage(postedForm: Form): Future[Response] = { val name: String = usernameField <-- postedForm val data: MultiPartFile = fileField <-- postedForm Ok(s"$name posted ${data.filename} which is ${data.length}" + " bytes") } val route: ServerRoute[Request, Response] = RouteSpec() .body(form) .at(Post) bindTo svc val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) }
Example 39
Source File: Web_Form_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.forms // fintrospect-core object Web_Form_Example extends App { import com.twitter.finagle.http.Method.Post import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import com.twitter.util.Future import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.parameters.{Body, Form, FormField} import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} val nameField = FormField.required.string("name") val ageField = FormField.optional.int("age") val form: Body[Form] = Body.webForm(nameField -> "everyone has a name!", ageField -> "age is an int!") val svc: Service[Request, Response] = Service.mk[Request, Response] { req => { val postedForm: Form = form <-- req if (postedForm.isValid) successMessage(postedForm) else failureMessage(postedForm) } } def failureMessage(postedForm: Form): Future[Response] = { val errorString = postedForm.errors.map(e => e.param.name + ": " + e.reason).mkString("\n") BadRequest("errors were: " + errorString) } def successMessage(postedForm: Form): Future[Response] = { val name: String = nameField <-- postedForm val age: Option[Int] = ageField <-- postedForm Ok(s"$name is ${age.map(_.toString).getOrElse("too old to admit it")}") } val route: ServerRoute[Request, Response] = RouteSpec() .body(form) .at(Post) bindTo svc val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v -H"Content-Type: application/x-www-form-urlencoded" -XPOST http://localhost:9999/ --data '&age=asd' //curl -v -H"Content-Type: application/x-www-form-urlencoded" -XPOST http://localhost:9999/ --data 'name=david&age=12'
Example 40
Source File: Simple_Form_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.forms // fintrospect-core object Simple_Form_Example extends App { import com.twitter.finagle.http.Method.Post import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.parameters.{Body, Form, FormField} import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} val nameField = FormField.required.string("name") val ageField = FormField.optional.int("age") val form: Body[Form] = Body.form(nameField, ageField) val svc: Service[Request, Response] = Service.mk[Request, Response] { req => { val formInstance: Form = form <-- req val name: String = nameField <-- formInstance val age: Option[Int] = ageField <-- formInstance Ok(s"$name is ${age.map(_.toString).getOrElse("too old to admit it")}") } } val route: ServerRoute[Request, Response] = RouteSpec() .body(form) .at(Post) bindTo svc val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v -H"Content-Type: application/x-www-form-urlencoded" -XPOST http://localhost:9999/ --data '&age=asd' //curl -v -H"Content-Type: application/x-www-form-urlencoded" -XPOST http://localhost:9999/ --data 'name=david&age=12'
Example 41
Source File: MultiPart_Form_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.forms // fintrospect-core object MultiPart_Form_Example extends App { import com.twitter.finagle.http.Method.Post import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.parameters.{Body, Form, FormField, MultiPartFile} import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} val usernameField = FormField.required.string("user") val fileField = FormField.required.file("data") val form: Body[Form] = Body.multiPartForm(usernameField, fileField) val svc: Service[Request, Response] = Service.mk[Request, Response] { req => { val postedForm: Form = form <-- req val name: String = usernameField <-- postedForm val data: MultiPartFile = fileField <-- postedForm Ok(s"$name posted ${data.filename} which is ${data.length}" + " bytes") } } val route: ServerRoute[Request, Response] = RouteSpec() .body(form) .at(Post) bindTo svc val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) }
Example 42
Source File: Handlebars_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.templating // fintrospect-core // fintrospect-handlebars case class HandlebarsView(name: String, age: Int) extends io.fintrospect.templating.View object Handlebars_Example extends App { import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import io.fintrospect.formats.Html import io.fintrospect.parameters.Path import io.fintrospect.templating.{HandlebarsTemplates, RenderView, View} import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} def showAgeIn30(name: String, age: Int): Service[Request, Response] = { val svc = Service.mk[Request, View] { req => MustacheView(name, age + 30) } new RenderView(Html.ResponseBuilder, HandlebarsTemplates.CachingClasspath(".")).andThen(svc) } val route: ServerRoute[Request, Response] = RouteSpec() .at(Get) / Path.string("name") / Path.int("age") bindTo showAgeIn30 val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v http://localhost:9999/david/100
Example 43
Source File: Semi_Auto_Marshalling_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.json_libraries case class Person(name: String, age: Option[Int]) // fintrospect-core // fintrospect-circe object Semi_Auto_Marshalling_Example extends App { import com.twitter.finagle.http.Method.Post import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import io.circe.generic.auto._ import io.fintrospect.formats.Circe import io.fintrospect.formats.Circe.JsonFormat._ import io.fintrospect.formats.Circe.ResponseBuilder._ import io.fintrospect.parameters.Body import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} val personBody = Body.of(Circe.bodySpec[Person]()) val insultMe: Service[Request, Response] = Service.mk[Request, Response] { req => val person: Person = personBody <-- req val smellyPerson: Person = person.copy(name = person.name + " Smells") Ok(encode(smellyPerson)) } val route: ServerRoute[Request, Response] = RouteSpec() .body(personBody) .at(Post) bindTo insultMe val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v -XPOST http://localhost:9999/ --data '{"name":"David", "age": 50}'
Example 44
Source File: Patching_Endpoint_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.json_libraries case class Employee(name: String, age: Option[Int]) // fintrospect-core // fintrospect-circe object Patching_Endpoint_Example extends App { import com.twitter.finagle.http.Method.Post import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import com.twitter.util.Future import io.circe.generic.auto._ import io.fintrospect.formats.Circe import io.fintrospect.formats.Circe.JsonFormat._ import io.fintrospect.formats.Circe.ResponseBuilder._ import io.fintrospect.parameters.Path import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} import scala.collection.mutable val employees = mutable.Map[Int, Employee](1 -> Employee("David", None)) val patchBody = Circe.patchBody[Employee]() def updateAge(id: Int): Service[Request, Response] = Service.mk[Request, Response] { req => val patcher = patchBody <-- req Future(employees.get(id) match { case Some(employee) => employees(id) = patcher(employee) Ok(encode(employees.get(id))) case _ => NotFound(s"with id $id") }) } val route: ServerRoute[Request, Response] = RouteSpec() .body(patchBody) .at(Post) / Path.int("id") bindTo updateAge val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v -XPOST http://localhost:9999/1 --data '{"age": 50}'
Example 45
Source File: Full_Auto_Service_Wrappers_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.json_libraries case class Profile(name: String, age: Option[Int]) // fintrospect-core // fintrospect-circe object Full_Auto_Marshalling_Example extends App { import com.twitter.finagle.http.Method.Post import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import com.twitter.util.Future import io.circe.generic.auto._ import io.fintrospect.formats.Circe import io.fintrospect.formats.Circe.Auto._ import io.fintrospect.parameters.Body import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} val insultMe: Service[Profile, Profile] = Service.mk[Profile, Profile] { inProfile => Future(inProfile.copy(name = inProfile.name + " Smells")) } val route: ServerRoute[Request, Response] = RouteSpec() .body(Body.of(Circe.bodySpec[Profile]())) .at(Post) bindTo InOut(insultMe) val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v -XPOST http://localhost:9999/ --data '{"name":"David", "age": 50}'
Example 46
Source File: Composite_Request_Parameters_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.core // fintrospect-core object Composite_Request_Parameters_Example extends App { import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.parameters.{Binding, Composite, Header, Query} import io.fintrospect.util.Extraction import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} case class FooBar(foo: String, bar: Int) object FooBar extends Composite[FooBar] { private val fooQ = add(Header.required.string("foo")) private val barQ = add(Query.required.int("bar")) override def -->(foobar: FooBar): Iterable[Binding] = (fooQ --> foobar.foo) ++ (barQ --> foobar.bar) override def <--?(req: Request): Extraction[FooBar] = { for { foo <- fooQ <--? req bar <- barQ <--? req } yield FooBar(foo, bar) } } val route: ServerRoute[Request, Response] = RouteSpec() .taking(FooBar).at(Get) bindTo Service.mk { req: Request => Ok("you sent: " + (FooBar <-- req)) } val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v -H"foo: foo" http://localhost:9999?bar=123
Example 47
Source File: Serving_Multiple_Content_Types_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.core // fintrospect-core object Serving_Multiple_Content_Types_Example extends App { import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import io.fintrospect.ContentTypes.{APPLICATION_JSON, APPLICATION_XML} import io.fintrospect.parameters.Path import io.fintrospect.util.StrictContentTypeNegotiation import io.fintrospect.{RouteModule, RouteSpec} def serveJson(name: String) = Service.mk[Request, Response] { req => import io.fintrospect.formats.Argo.JsonFormat._ import io.fintrospect.formats.Argo.ResponseBuilder._ Ok(obj("field" -> string(name))) } def serveXml(name: String) = Service.mk[Request, Response] { import io.fintrospect.formats.Xml.ResponseBuilder._ req => Ok(<root> <field> {name} </field> </root>) } val route = RouteSpec() .at(Get) / Path.string("name") bindTo StrictContentTypeNegotiation(APPLICATION_XML -> serveXml, APPLICATION_JSON -> serveJson) ready(Http.serve(":9999", RouteModule(Root).withRoute(route).toService)) } //curl -v -H"Accept: application/json" http://localhost:9999/David //curl -v -H"Accept: application/xml" http://localhost:9999/David
Example 48
Source File: Simple_XML_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.core // fintrospect-core object Simple_XML_Example extends App { import com.twitter.finagle.http.Method.Post import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import io.fintrospect.formats.Xml.ResponseBuilder._ import io.fintrospect.parameters.Body import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} import scala.xml.Elem val document: Body[Elem] = Body.xml() val analyse: Service[Request, Response] = Service.mk[Request, Response] { req => { val postedDoc: Elem = document <-- req Ok( <document> <number-of-root-elements> {postedDoc.length} </number-of-root-elements> </document> ) } } val route: ServerRoute[Request, Response] = RouteSpec().body(document).at(Post) bindTo analyse val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v -XPOST http://localhost:9999/ --data '<person name="david" age="100"/>'
Example 49
Source File: Swagger_Auto_Docs_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.core // fintrospect-core object Swagger_Auto_Docs_Example extends App { import argo.jdom.JsonNode import com.twitter.finagle.http.Method.Post import com.twitter.finagle.http.filter.Cors import com.twitter.finagle.http.filter.Cors.HttpFilter import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import com.twitter.util.Future import io.fintrospect.ContentTypes.APPLICATION_JSON import io.fintrospect.formats.Argo.JsonFormat._ import io.fintrospect.formats.Argo.ResponseBuilder._ import io.fintrospect.parameters.{Body, Header, Path, Query} import io.fintrospect.renderers.ModuleRenderer import io.fintrospect.renderers.swagger2dot0.{ApiInfo, Swagger2dot0Json} import io.fintrospect.{ApiKey, Module, RouteModule, RouteSpec, ServerRoute} def buildResponse(id: Int, sent: JsonNode) = obj("id" -> number(id), "sent" -> sent) val exampleBody: JsonNode = array(obj("lastName" -> string("Jane")), obj("name" -> string("Jim"))) val exampleResponse: JsonNode = buildResponse(222, exampleBody) val sentDocument: Body[JsonNode] = Body.json("family description", exampleBody) def svc(id: Int): Service[Request, Response] = Service.mk[Request, Response] { req => Ok(buildResponse(id, sentDocument <-- req)) } val securityFilter: Service[String, Boolean] = Service.mk[String, Boolean] { r => Future(r == "secret") } val route: ServerRoute[Request, Response] = RouteSpec("a short summary", "a longer description") .taking(Query.required.string("firstName", "this is your firstname")) .taking(Header.optional.localDate("birthdate", "format yyyy-mm-dd")) .producing(APPLICATION_JSON) .consuming(APPLICATION_JSON) .returning(Status.Ok -> "Valid request accepted", exampleResponse) .body(sentDocument) .at(Post) / Path.int("id", "custom identifier for this request") bindTo svc val docsRenderer: ModuleRenderer = Swagger2dot0Json( ApiInfo("My App", "1.0", "This is an extended description of the API's functions") ) val module: Module = RouteModule(Root, docsRenderer) .withDescriptionPath(moduleRoot => moduleRoot / "swagger.json") .securedBy(ApiKey(Query.required.string("token"), securityFilter)) .withRoute(route) ready(Http.serve(":9999", new HttpFilter(Cors.UnsafePermissivePolicy).andThen(module.toService))) } // curl -v http://localhost:9999/swagger.json
Example 50
Source File: Custom_Response_Format_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.core // fintrospect-core object Custom_Response_Format_Example extends App { import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.io.Bufs import com.twitter.util.Await.ready import io.fintrospect.formats.{AbstractResponseBuilder, ResponseBuilder} import io.fintrospect.{ContentType, Module, RouteModule, RouteSpec, ServerRoute} object Csv { object ResponseBuilder extends AbstractResponseBuilder[List[String]] { override def HttpResponse(): ResponseBuilder[List[String]] = new ResponseBuilder( (i: List[String]) => Bufs.utf8Buf(i.mkString(",")), error => List("ERROR:" + error), throwable => List("ERROR:" + throwable.getMessage), ContentType("application/csv") ) } } import Csv.ResponseBuilder._ val service: Service[Request, Response] = Service.mk { _: Request => Ok(List("this", "is", "comma", "separated", "hello", "world")) } val route: ServerRoute[Request, Response] = RouteSpec().at(Get) bindTo service val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v http://localhost:9999
Example 51
Source File: Simple_HTML_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.core // fintrospect-core object Simple_HTML_Example extends App { import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import io.fintrospect.formats.Html.ResponseBuilder._ import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} val serve: Service[Request, Response] = Service.mk[Request, Response] { req => { Ok( <html> <head> <title>The Title</title> </head> <body>Some content goes here</body> </html>.toString() ) } } val route: ServerRoute[Request, Response] = RouteSpec().at(Get) bindTo serve val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v http://localhost:9999/'
Example 52
Source File: Accepting_Multiple_Body_Types_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.core // fintrospect-core object Accepting_Multiple_Body_Types_Example extends App { import argo.jdom.JsonNode import com.twitter.finagle.http.Method.Post import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import io.fintrospect.parameters.Body import io.fintrospect.util.MultiBodyType import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} import scala.xml.Elem val json: Body[JsonNode] = Body.json() val echoJson: Service[Request, Response] = Service.mk[Request, Response] { req => import io.fintrospect.formats.Argo.ResponseBuilder._ Ok(json <-- req) } val xml: Body[Elem] = Body.xml() val echoXml: Service[Request, Response] = Service.mk[Request, Response] { req => import io.fintrospect.formats.Xml.ResponseBuilder._ Ok(xml <-- req) } val route: ServerRoute[Request, Response] = RouteSpec("echo posted content in either JSON or XML") .at(Post) bindTo MultiBodyType(json -> echoJson, xml -> echoXml) val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v -XPOST -H"Content-Type: application/json" http://localhost:9999/ --data '{"name":"David"}' //curl -v -XPOST -H"Content-Type: application/xml" http://localhost:9999/ --data '<name>David</name>'
Example 53
Source File: Module_Filters_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.core // fintrospect-core object Module_Filters_Example extends App { import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Filter, Http, Service} import com.twitter.util.Await.ready import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.renderers.ModuleRenderer import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} val headers: Service[Request, Response] = Service.mk[Request, Response] { req => Ok(req.uri) } val route: ServerRoute[Request, Response] = RouteSpec().at(Get) bindTo headers val timingFilter = Filter.mk[Request, Response, Request, Response] { (req, next) => val start = System.currentTimeMillis() next(req).map { resp => { val time = System.currentTimeMillis() - start resp.headerMap("performance") = s"${resp.contentString} took $time ms" resp } } } val module: Module = RouteModule(Root, ModuleRenderer.Default, timingFilter).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v http://localhost:9999
Example 54
Source File: Extracting_Upstream_Responses.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.core // fintrospect-core object Extracting_Upstream_Responses extends App { import argo.jdom.JsonNode import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.result import io.fintrospect.configuration.{Authority, Host, Port} import io.fintrospect.filters.RequestFilters.AddHost import io.fintrospect.filters.ResponseFilters import io.fintrospect.parameters.{Body, BodySpec, Path} import io.fintrospect.util.{Extracted, Extraction, ExtractionFailed} import io.fintrospect.{RouteClient, RouteSpec} case class Pokemon(id: Int, name: String, weight: Int) object Pokemon { def from(j: JsonNode) = Pokemon(j.getNumberValue("id").toInt, j.getStringValue("name"), j.getNumberValue("weight").toInt) } val authority: Authority = Host("pokeapi.co").toAuthority(Port._80) val http: Service[Request, Response] = AddHost(authority).andThen(Http.newService(authority.toString)) val id = Path.int("pokemonId") val spec: BodySpec[Pokemon] = BodySpec.json().map(Pokemon.from) val nameAndWeight: Body[Pokemon] = Body.of(spec) val client: RouteClient[Extraction[Option[Pokemon]]] = RouteSpec().at(Get) / "api" / "v2" / "pokemon" / id / "" bindToClient ResponseFilters.ExtractBody(nameAndWeight).andThen(http) def reportOnPokemon(pid: Int) = println( result(client(id --> pid)) match { case Extracted(Some(pokemon)) => s"i found a pokemon: $pokemon" case Extracted(None) => s"there is no pokemon with id $pid" case ExtractionFailed(errors) => s"problem extracting response $errors" } ) reportOnPokemon(1) reportOnPokemon(11) reportOnPokemon(9999) }
Example 55
Source File: Simple_JSON_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.core // fintrospect-core object Simple_JSON_Example extends App { import java.time.ZonedDateTime import argo.jdom.JsonNode import com.twitter.finagle.http.Method.Post import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import io.fintrospect.formats.Argo.JsonFormat._ import io.fintrospect.formats.Argo.ResponseBuilder._ import io.fintrospect.parameters.Body import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} val json: Body[JsonNode] = Body.json() val echo: Service[Request, Response] = Service.mk[Request, Response] { req => val requestJson: JsonNode = json <-- req val responseJson: JsonNode = obj( "posted" -> requestJson, "time" -> string(ZonedDateTime.now().toString) ) Ok(responseJson) } val route: ServerRoute[Request, Response] = RouteSpec().body(json).at(Post) bindTo echo val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl -v -XPOST http://localhost:9999/ --data '{"name":"David"}'
Example 56
Source File: Combining_Modules_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.core // fintrospect-core object Combining_Modules_Example extends App { import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} val identify: Service[Request, Response] = Service.mk { req: Request => Ok(req.uri) } val route: ServerRoute[Request, Response] = RouteSpec().at(Get) bindTo identify val childModule: Module = RouteModule(Root / "child").withRoute(route) val rootModule: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", childModule.andThen(rootModule).toService)) } //curl -v http://localhost:9999/child //curl -v http://localhost:9999
Example 57
Source File: Streaming_Response_Example.scala From fintrospect with Apache License 2.0 | 5 votes |
package cookbook.core // fintrospect-core object Streaming_Response_Example extends App { import argo.jdom.JsonNode import com.twitter.concurrent.AsyncStream import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Http, Service} import com.twitter.util.Await.ready import com.twitter.util.Duration.fromSeconds import com.twitter.util.Future.sleep import com.twitter.util.JavaTimer import io.fintrospect.formats.Argo.JsonFormat._ import io.fintrospect.formats.Argo.ResponseBuilder._ import io.fintrospect.{Module, RouteModule, RouteSpec, ServerRoute} val timer = new JavaTimer() def ints(i: Int): AsyncStream[Int] = i +:: AsyncStream.fromFuture(sleep(fromSeconds(1))(timer)).flatMap(_ => ints(i + 1)) def jsonStream: AsyncStream[JsonNode] = ints(0).map(i => obj("number" -> number(i))) val count: Service[Request, Response] = Service.mk[Request, Response] { req => Ok(jsonStream) } val route: ServerRoute[Request, Response] = RouteSpec().at(Get) bindTo count val module: Module = RouteModule(Root).withRoute(route) ready(Http.serve(":9999", module.toService)) } //curl --raw http://localhost:9999/
Example 58
Source File: Auto.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.formats import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.finagle.{Filter, Service} import io.fintrospect.parameters.{Body, Mandatory} import io.fintrospect.util.{Extracted, ExtractionFailed} class Auto[R](responseBuilder: AbstractResponseBuilder[R]) { type SvcBody[IN] = Body[IN] with Mandatory[Request, IN] import responseBuilder._ def OptionalOut[IN, OUT](svc: Service[IN, Option[OUT]], successStatus: Status = Status.Ok) (implicit transform: OUT => R): Service[IN, Response] = Filter.mk[IN, Response, IN, Option[OUT]] { (req, svc) => svc(req) .map( _.map(transform) .map(l => HttpResponse(successStatus).withContent(l)) .getOrElse(HttpResponse(Status.NotFound).withErrorMessage("No object available to unmarshal"))) .map(_.build()) }.andThen(svc) }
Example 59
Source File: ContractProxyModule.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect import com.twitter.finagle.Service import com.twitter.finagle.http.path.{Path, Root} import com.twitter.finagle.http.{Request, Response} import io.fintrospect.renderers.swagger2dot0.{ApiInfo, Swagger2dot0Json} import scala.reflect.runtime.universe.TypeTag import scala.reflect.runtime.{currentMirror, universe} object ContractProxyModule { def apply[T <: Contract](name: String, service: Service[Request, Response], contract: T, rootPath: Path = Root, description: String = null)(implicit tag: TypeTag[T]): RouteModule[Request, Response] = { val descriptionOption = Option(description).getOrElse(s"Proxy services for $name API") val routes = universe.typeOf[T].members .filter(_.isModule) .map(_.asModule) .map(currentMirror.reflectModule(_).instance) .filter(_.isInstanceOf[ContractEndpoint]) .map(_.asInstanceOf[ContractEndpoint].route) routes.foldLeft(RouteModule(rootPath, Swagger2dot0Json(ApiInfo(name, name, descriptionOption)))) { (spec, route) => spec.withRoute(route.bindToProxy(service)) } } }
Example 60
Source File: StaticModule.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect import com.google.common.io.Resources.toByteArray import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.Status.Ok import com.twitter.finagle.http.path.{->, Path, Root} import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{Filter, Service} import com.twitter.io.Buf.ByteArray.Owned import io.fintrospect.ContentType.lookup import io.fintrospect.Module.ServiceBinding import io.fintrospect.formats.ResponseBuilder.HttpResponse object StaticModule { def apply(basePath: Path, resourceLoader: ResourceLoader = ResourceLoader.Classpath(), moduleFilter: Filter[Request, Response, Request, Response] = Filter.identity) = { new StaticModule(basePath, resourceLoader, moduleFilter) } } class StaticModule private(basePath: Path, resourceLoader: ResourceLoader, moduleFilter: Filter[Request, Response, Request, Response]) extends Module { override protected[fintrospect] def serviceBinding: ServiceBinding = { case Get -> path if exists(path) => moduleFilter.andThen(Service.mk[Request, Response] { _ => HttpResponse(lookup(convertPath(path))).withCode(Ok).withContent(Owned(toByteArray(resourceLoader.load(convertPath(path))))) }) } private def exists(path: Path) = if (path.startsWith(basePath)) resourceLoader.load(convertPath(path)) != null else false private def convertPath(path: Path) = { val newPath = if (basePath == Root) path.toString else path.toString.replace(basePath.toString, "") val resolved = if (newPath == "") "/index.html" else newPath resolved.replaceFirst("/", "") } }
Example 61
Source File: ModuleSpec.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect import com.twitter.finagle.Filter import com.twitter.finagle.http.path.Path import com.twitter.finagle.http.{Request, Response} import io.fintrospect.renderers.ModuleRenderer @deprecated("Renamed: use RouteModule instead", "13.16.0") object ModuleSpec { @deprecated("Renamed: use RouteModule instead", "13.16.0") def apply(basePath: Path): RouteModule[Request, Response] = RouteModule(basePath) @deprecated("Renamed: use RouteModule instead", "13.16.0") def apply(basePath: Path, moduleRenderer: ModuleRenderer): RouteModule[Request, Response] = RouteModule(basePath, moduleRenderer) @deprecated("Renamed: use RouteModule instead", "13.16.0") def apply[RQ, RS](basePath: Path, moduleRenderer: ModuleRenderer, moduleFilter: Filter[Request, Response, RQ, RS]): RouteModule[RQ, RS] = RouteModule(basePath, moduleRenderer, moduleFilter) }
Example 62
Source File: SiteMapModuleRenderer.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.renderers import java.net.URL import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.path.Path import com.twitter.finagle.http.{Request, Response, Status} import io.fintrospect.formats.Xml.ResponseBuilder._ import io.fintrospect.util.ExtractionError import io.fintrospect.{Security, ServerRoute} class SiteMapModuleRenderer(baseUrl: URL) extends ModuleRenderer { override def badRequest(badParameters: Seq[ExtractionError]): Response = BadRequest(badParameters.toString()) override def notFound(request: Request): Response = HttpResponse(Status.NotFound).build() override def description(basePath: Path, security: Security, routes: Seq[ServerRoute[_, _]]): Response = { def buildUrl(route: ServerRoute[_, _]) = <url> <loc> {baseUrl + route.describeFor(basePath)} </loc> </url> Ok(<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> {routes.filter(_.method == Get).map(buildUrl)} </urlset>) } }
Example 63
Source File: SimpleJson.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.renderers.simplejson import com.twitter.finagle.http.path.Path import com.twitter.finagle.http.{Request, Response} import io.fintrospect.formats.Argo import io.fintrospect.formats.Argo.JsonFormat.{Field, obj} import io.fintrospect.formats.Argo.ResponseBuilder._ import io.fintrospect.renderers.{JsonErrorResponseRenderer, ModuleRenderer} import io.fintrospect.util.ExtractionError import io.fintrospect.{Security, ServerRoute} class SimpleJson extends ModuleRenderer { override def badRequest(badParameters: Seq[ExtractionError]): Response = JsonErrorResponseRenderer.badRequest(badParameters) override def notFound(request: Request): Response = JsonErrorResponseRenderer.notFound() private def render(basePath: Path, route: ServerRoute[_, _]): Field = route.method.toString() + ":" + route.describeFor(basePath) -> Argo.JsonFormat.string(route.routeSpec.summary) override def description(basePath: Path, security: Security, routes: Seq[ServerRoute[_, _]]): Response = Ok(obj("resources" -> obj(routes.map(r => render(basePath, r))))) } object SimpleJson { def apply() = new SimpleJson() }
Example 64
Source File: JsonErrorResponseRenderer.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.renderers import com.twitter.finagle.http.Response import io.fintrospect.formats.Argo.JsonFormat.{array, boolean, obj, string} import io.fintrospect.formats.Argo.ResponseBuilder._ import io.fintrospect.util.ExtractionError object JsonErrorResponseRenderer { def badRequest(badParameters: Seq[ExtractionError]): Response = { val messages = badParameters.map(p => obj( "name" -> string(p.param.name), "type" -> string(p.param.where), "datatype" -> string(p.param.paramType.name), "required" -> boolean(p.param.required), "reason" -> string(p.reason) )) BadRequest(obj("message" -> string("Missing/invalid parameters"), "params" -> array(messages))) } def notFound(): Response = { NotFound(obj("message" -> string("No route found on this path. Have you used the correct HTTP verb?"))) } }
Example 65
Source File: Swagger1dot1Json.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.renderers.swagger1dot1 import argo.jdom.JsonNode import com.twitter.finagle.http.path.Path import com.twitter.finagle.http.{Request, Response} import io.fintrospect.formats.Argo.JsonFormat._ import io.fintrospect.formats.Argo.ResponseBuilder._ import io.fintrospect.parameters.HasParameters import io.fintrospect.renderers.{JsonErrorResponseRenderer, ModuleRenderer} import io.fintrospect.util.ExtractionError import io.fintrospect.{Security, ServerRoute} class Swagger1dot1Json extends ModuleRenderer { private def render(parameters: HasParameters): Iterable[JsonNode] = parameters.map( parameter => obj( "name" -> string(parameter.name), "description" -> Option(parameter.description).map(string).getOrElse(nullNode()), "paramType" -> string(parameter.where), "required" -> boolean(parameter.required), "dataType" -> string(parameter.paramType.name) ) ) private def render(route: ServerRoute[_, _]): Field = route.method.toString().toLowerCase -> { val allParams = route.pathParams.flatten ++ route.routeSpec.requestParams.flatMap(_.iterator).flatten ++ route.routeSpec.body.map(_.iterator).getOrElse(Nil) obj( "Method" -> string(route.method.toString()), "nickname" -> string(route.routeSpec.summary), "notes" -> route.routeSpec.description.map(string).getOrElse(nullNode()), "produces" -> array(route.routeSpec.produces.map(m => string(m.value))), "consumes" -> array(route.routeSpec.consumes.map(m => string(m.value))), "parameters" -> array(allParams.flatMap(render)), "errorResponses" -> array(route.routeSpec.responses.values.filter(_.status.code > 399) .map(resp => obj("code" -> number(resp.status.code), "reason" -> string(resp.description)))) ) } override def description(basePath: Path, security: Security, routes: Seq[ServerRoute[_, _]]): Response = { Ok(obj("swaggerVersion" -> string("1.1"), "resourcePath" -> string("/"), "apis" -> array(routes .groupBy(_.describeFor(basePath)) .map { case (path, routesForPath) => obj("path" -> string(path), "operations" -> array(routesForPath.map(render(_)._2))) } .toSeq: _*))) } override def badRequest(badParameters: Seq[ExtractionError]): Response = JsonErrorResponseRenderer.badRequest(badParameters) override def notFound(request: Request): Response = JsonErrorResponseRenderer.notFound() } object Swagger1dot1Json { def apply() = new Swagger1dot1Json() }
Example 66
Source File: MultiBodyType.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.util import com.twitter.finagle.Service import com.twitter.finagle.http.{Request, Response} import com.twitter.util.Future import io.fintrospect.ContentType import io.fintrospect.formats.Argo.ResponseBuilder._ import io.fintrospect.parameters.Body import io.fintrospect.renderers.ModuleRenderer import io.fintrospect.renderers.simplejson.SimpleJson object MultiBodyType { type SupportedContentType = (Body[_], Service[Request, Response]) def apply(services: SupportedContentType*)(implicit moduleRenderer: ModuleRenderer = SimpleJson()): Service[Request, Response] = { val supportedContentTypes = Map(services.map(bs => ContentType(bs._1.contentType.value.toLowerCase) -> bs): _*) def validateAndRespond(request: Request, body: SupportedContentType) = body._1.extract(request) match { case ExtractionFailed(invalid) => Future(moduleRenderer.badRequest(invalid)) case _ => body._2(request) } def handle(request: Request, contentType: ContentType): Future[Response] = supportedContentTypes.get(contentType) .map(pair => validateAndRespond(request, pair)) .getOrElse(UnsupportedMediaType(contentType.value)) Service.mk { request: Request => (ContentType.header <-- request) .map(value => ContentType(value.toLowerCase())) .map(contentType => handle(request, contentType)) .getOrElse(UnsupportedMediaType("missing Content-Type header")) } } }
Example 67
Source File: HeapDump.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.util import java.io.File import java.lang.management.ManagementFactory.getPlatformMXBeans import java.time.Clock import java.time.ZonedDateTime.now import java.time.format.DateTimeFormatter.ISO_DATE_TIME import com.sun.management.HotSpotDiagnosticMXBean import com.twitter.finagle.Service import com.twitter.finagle.http.{Request, Response} import com.twitter.io.Readers import com.twitter.util.Future import io.fintrospect.ContentType import io.fintrospect.formats.ResponseBuilder.HttpResponse class HeapDump(processIdentifier: String = "", clock: Clock = Clock.systemUTC()) extends Service[Request, Response] { override def apply(request: Request): Future[Response] = { val dumpFileName = s"heapdump-$processIdentifier-${now(clock).format(ISO_DATE_TIME)}" val dumpFile = File.createTempFile(dumpFileName, ".hprof") dumpFile.delete() getPlatformMXBeans(classOf[HotSpotDiagnosticMXBean]).get(0).dumpHeap(dumpFile.getAbsolutePath, true) val response = HttpResponse(ContentType("application/x-heap-dump")) .withHeaders("Content-disposition" -> ("inline; filename=\"" + dumpFileName + ".hprof\"")) .withContent(Readers.newFileReader(dumpFile, 1024)).build() Future(response).ensure(dumpFile.delete()) } }
Example 68
Source File: RequestFilters.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.filters import java.nio.charset.StandardCharsets.ISO_8859_1 import java.util.Base64 import com.twitter.finagle.Filter import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.util.Future import io.fintrospect.ContentType.fromAcceptHeaders import io.fintrospect.configuration.{Authority, Credentials} import io.fintrospect.formats.Argo.ResponseBuilder._ import io.fintrospect.renderers.ModuleRenderer import io.fintrospect.renderers.simplejson.SimpleJson import io.fintrospect.util.{Extracted, Extraction, ExtractionFailed, Extractor} import io.fintrospect.{ContentType, ContentTypes} import io.netty.handler.codec.http.HttpHeaderNames def ExtractBody[I](extractor: Extractor[Request, I]) (implicit moduleRenderer: ModuleRenderer = SimpleJson()): Filter[Request, Response, I, Response] = Filter.mk[Request, Response, I, Response] { (req, svc) => { extractor <--? req match { case Extracted(x) => svc(x) case ExtractionFailed(invalid) => Future(moduleRenderer.badRequest(invalid)) } } } } object A extends App { println(HttpHeaderNames.USER_AGENT.toString) }
Example 69
Source File: SecurityTest.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect import com.twitter.finagle.Service import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.util.Await.result import com.twitter.util.Future import io.fintrospect.formats.PlainText.ResponseBuilder._ import io.fintrospect.parameters.Query import io.fintrospect.util.HttpRequestResponseUtil.statusAndContentFrom import org.scalatest.{FunSpec, Matchers} class SecurityTest extends FunSpec with Matchers { describe("ApiKey") { val paramName = "name" val param = Query.required.int(paramName) val next = Service.mk[Request, Response](r => Ok("hello")) it("valid API key is granted access and result carried through") { val (status, content) = result(ApiKey(param, Service.const(Future(true))).filter(Request(paramName -> "1"), next) .map(statusAndContentFrom)) status should be(Status.Ok) content should be("hello") } it("missing API key is unauthorized") { val (status, content) = result(ApiKey(param, Service.const(Future(true))).filter(Request(), next) .map(statusAndContentFrom)) status should be(Status.Unauthorized) content should be("") } it("bad API key is unauthorized") { val (status, content) = result(ApiKey(param, Service.const(Future(true))).filter(Request(paramName -> "notAnInt"), next) .map(statusAndContentFrom)) status should be(Status.Unauthorized) content should be("") } it("unknown API key is unauthorized") { val (status, content) = result(ApiKey(param, Service.const(Future(false))).filter(Request(paramName -> "1"), next) .map(statusAndContentFrom)) status should be(Status.Unauthorized) content should be("") } it("failed API key lookup is rethrown") { val e = new RuntimeException("boom") val caught = intercept[RuntimeException](result(ApiKey(param, Service.const(Future.exception(e))).filter(Request(paramName -> "1"), next))) caught should be(e) } } }
Example 70
Source File: ModuleTest.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect import com.twitter.finagle.Service import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.path.Path import com.twitter.finagle.http.{Method, Request, Response, Status} import com.twitter.util.Await.result import io.fintrospect.util.Echo import io.fintrospect.util.HttpRequestResponseUtil.statusAndContentFrom import org.scalatest.{FunSpec, Matchers} class ModuleTest extends FunSpec with Matchers { describe("Module") { it("when it matches it responds as expected") { val response = statusAndContentFrom(result(routingWhichMatches((Get, Path("/someUrl")))(Request("/someUrl?field=hello")))) response._1 shouldBe Status.Ok response._2 should include("/someUrl?field=hello") } it("no match responds with default 404") { val response = result(routingWhichMatches((Get, Path("/someUrl")))(Request("/notMyService"))) response.status shouldBe Status.NotFound } } private def routingWhichMatches(methodAndPath: (Method, Path)): Service[Request, Response] = { Module.toService(new PartialFunction[(Method, Path), Service[Request, Response]] { override def isDefinedAt(x: (Method, Path)): Boolean = x === methodAndPath override def apply(v1: (Method, Path)): Service[Request, Response] = Echo() }) } }
Example 71
Source File: SiteMapModuleRendererTest.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.renderers import java.net.URL import com.twitter.finagle.Service import com.twitter.finagle.http.Method._ import com.twitter.finagle.http.Status.{BadRequest, NotFound, Ok} import com.twitter.finagle.http.path.Root import com.twitter.finagle.http.{Method, Request, Response} import com.twitter.util.Future import io.fintrospect.util.HttpRequestResponseUtil.statusAndContentFrom import io.fintrospect.{NoSecurity, RouteSpec, ServerRoute} import org.scalatest.{FunSpec, Matchers} class SiteMapModuleRendererTest extends FunSpec with Matchers { it("renders 400") { new SiteMapModuleRenderer(new URL("http://fintrospect.io")).badRequest(Nil).status shouldBe BadRequest } it("renders 404") { new SiteMapModuleRenderer(new URL("http://fintrospect.io")).notFound(Request()).status shouldBe NotFound } it("should describe only GET endpoints of module as a sitemap") { val rsp = new SiteMapModuleRenderer(new URL("http://fintrospect.io")).description(Root / "bob", NoSecurity, Seq( endpointFor(Get), endpointFor(Post), endpointFor(Delete), endpointFor(Put), endpointFor(Options), endpointFor(Connect), endpointFor(Head), endpointFor(Trace) )) val (status, content) = statusAndContentFrom(rsp) status shouldBe Ok content shouldBe <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url> <loc> http://fintrospect.io/bob/GET </loc> </url> </urlset>.toString() } private def endpointFor(method: Method): ServerRoute[Request, Response] = { RouteSpec().at(method) / method.toString() bindTo Service.mk[Request, Response]((r) => Future(Response())) } }
Example 72
Source File: StrictContentTypeNegotiationTest.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.util import com.twitter.finagle.Service import com.twitter.finagle.http.Status.{NotAcceptable, Ok} import com.twitter.finagle.http.{Request, Response} import com.twitter.util.Await.result import com.twitter.util.Future import io.fintrospect.ContentType import io.fintrospect.ContentTypes.{APPLICATION_ATOM_XML, APPLICATION_JSON, TEXT_HTML} import io.fintrospect.formats.ResponseBuilder import org.scalatest.{FunSpec, Matchers} class StrictContentTypeNegotiationTest extends FunSpec with Matchers { describe("StrictContentTypeNegotiation") { it("on no match, return 406") { val r = result(StrictContentTypeNegotiation(serviceForType(APPLICATION_ATOM_XML))(requestWithAcceptHeaders(APPLICATION_JSON.value))) r.status shouldBe NotAcceptable } it("when there are no accept header set, just chooses the first type") { val r = result(StrictContentTypeNegotiation(serviceForType(APPLICATION_ATOM_XML), serviceForType(APPLICATION_JSON))(requestWithAcceptHeaders())) r.status shouldBe Ok r.headerMap("Content-Type") should startWith(APPLICATION_ATOM_XML.value) } it("when there is a wildcard set, just chooses the first type") { val r = result(StrictContentTypeNegotiation(serviceForType(APPLICATION_ATOM_XML), serviceForType(APPLICATION_JSON))(requestWithAcceptHeaders("**;q=0.5"))) r.status shouldBe Ok r.headerMap("Content-Type") should startWith(TEXT_HTML.value) } } private def serviceForType(contentType: ContentType): (ContentType, Service[Request, Response]) = contentType -> Service.mk[Request, Response] { r => Future(ResponseBuilder.HttpResponse(contentType).build()) } private def requestWithAcceptHeaders(headers: String*): Request = { val request = Request() headers.foreach(value => request.headerMap.add("Accept", value)) request } }
Example 73
Source File: MultiBodyTypeTest.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.util import com.twitter.finagle.Service import com.twitter.finagle.http.Status.Ok import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.util.Await.result import com.twitter.util.Future import io.fintrospect.ContentType import io.fintrospect.ContentTypes.APPLICATION_JSON import io.fintrospect.parameters.Body import org.scalatest.{FunSpec, Matchers} class MultiBodyTypeTest extends FunSpec with Matchers { val xmlBody = Body.xml() val xmlAccepting = MultiBodyType(xmlBody -> Service.mk { req: Request => Future(Response(Ok)) }) describe("MultiBodyType") { it("on no match, reject with 415") { val r = result(xmlAccepting(requestFromContentType(APPLICATION_JSON))) r.status shouldBe Status.UnsupportedMediaType } it("when there are no content-type header set, reject with 415") { val r = result(xmlAccepting(requestFromContentType())) r.status shouldBe Status.UnsupportedMediaType } it("when there is an exact (case insensitive) match on a content type, use that service") { val r = Request() r.headerMap("Content-Type") = "application/xml" r.contentString = "<xml/>" val resp = result(xmlAccepting(r)) resp.status shouldBe Ok } } def requestFromContentType(headers: ContentType*): Request = { val request = Request() headers.foreach(value => request.headerMap.add("Content-Type", value.value)) request } }
Example 74
Source File: OverridableHttpServiceTest.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.testing import com.twitter.finagle.Service import com.twitter.finagle.http.Status.{Accepted, Conflict} import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.util.{Await, Future} import org.scalatest.{FunSpec, Matchers} class OverridableHttpServiceTest extends FunSpec with Matchers { val originalStatus = Conflict val overridableHttpService = new OverridableHttpService[Request](Service.mk { r: Request => Future(Response(originalStatus)) }) it("will serve routes that are passed to it") { statusShouldBe(originalStatus) } it("can override status") { overridableHttpService.respondWith(Accepted) statusShouldBe(Accepted) } private def statusShouldBe(expected: Status): Unit = { Await.result(overridableHttpService.service(Request())).status shouldBe expected } }
Example 75
Source File: TestHttpServerTest.scala From fintrospect with Apache License 2.0 | 5 votes |
package io.fintrospect.testing import com.twitter.finagle.http.Method.Get import com.twitter.finagle.http.Status.{Accepted, Conflict} import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.finagle.{Http, Service} import com.twitter.util.{Await, Future} import io.fintrospect.RouteSpec import org.scalatest.{BeforeAndAfterEach, FunSpec, Matchers} class TestHttpServerTest extends FunSpec with Matchers with BeforeAndAfterEach { val originalStatus = Conflict private val server = new TestHttpServer(9888, RouteSpec().at(Get) bindTo Service.mk { r: Request => Future(Response(originalStatus)) }) override def beforeEach() = { Await.result(server.start()) } override def afterEach() = { Await.result(server.stop()) } it("will serve routes that are passed to it") { statusShouldBe(originalStatus) } it("can override status") { server.respondWith(Accepted) statusShouldBe(Accepted) } private def statusShouldBe(expected: Status): Unit = { Await.result(Http.newService("localhost:9888", "")(Request())).status shouldBe expected } }
Example 76
Source File: App.scala From finagle-metrics with MIT License | 5 votes |
import com.codahale.metrics.ConsoleReporter import com.twitter.finagle.{ Http, Service } import com.twitter.finagle.metrics.MetricsStatsReceiver import com.twitter.finagle.http.{ Request, Response, Status } import com.twitter.io.Charsets import com.twitter.server.TwitterServer import com.twitter.util.{ Await, Future } import java.util.concurrent.TimeUnit object App extends TwitterServer { val service = new Service[Request, Response] { def apply(request: Request) = { val response = Response(request.version, Status.Ok) response.contentString = "hello" Future.value(response) } } val reporter = ConsoleReporter .forRegistry(MetricsStatsReceiver.metrics) .convertRatesTo(TimeUnit.SECONDS) .convertDurationsTo(TimeUnit.MILLISECONDS) .build def main() = { val server = Http.serve(":8080", service) reporter.start(5, TimeUnit.SECONDS) onExit { server.close() } Await.ready(server) } }
Example 77
Source File: ProcessReportHandler.scala From finagle-microservice-sample with Apache License 2.0 | 5 votes |
import com.twitter.finagle.Service import com.twitter.finagle.http.Response import com.twitter.util.Future import org.jboss.netty.handler.codec.http.HttpResponseStatus import reports.ReportProcessor class ProcessReportHandler(reportProcessor: ReportProcessor) extends Service[AuthorizedRequest, Response] { val processReportUrl = "/report/([0-9]+)/process".r override def apply(req: AuthorizedRequest): Future[Response] = req.request.path match { case processReportUrl(processId) => reportProcessor.processReport(processId.toInt) map { _ => val response = Response(req.request.getProtocolVersion(), HttpResponseStatus.OK) response.setContentTypeJson() response.setContentString( s""" { "processId": $processId, "processed": true } """) response } rescue { case _ => Future.value(Response(req.request.getProtocolVersion(), HttpResponseStatus.INTERNAL_SERVER_ERROR)) } case _ => Future.value(Response(req.request.getProtocolVersion(), HttpResponseStatus.NOT_FOUND)) } }
Example 78
Source File: AuthenticationFilter.scala From finagle-microservice-sample with Apache License 2.0 | 5 votes |
import com.twitter.finagle.{Service, Filter} import com.twitter.finagle.http.{Response, Request} import com.twitter.util.Future import data.UserData import org.jboss.netty.handler.codec.http.HttpHeaders.Names import org.jboss.netty.handler.codec.http.HttpResponseStatus class AuthenticationFilter(loginService: LoginService) extends Filter[Request, Response, AuthorizedRequest, Response] { override def apply(request: Request, continue: Service[AuthorizedRequest, Response]): Future[Response] = { if(request.headers().contains(Names.AUTHORIZATION)) { //for simplicity, we assume the Authorization request header is in the format "username:password" request.headers().get(Names.AUTHORIZATION).split(":") match { case Array(username, password) => if(loginService.login(username, password)) { val authorizedRequest = AuthorizedRequest(request, UserData(username, List("guest"))) continue(authorizedRequest) //continue to the next service/filter } else unauthorized(request) case _ => unauthorized(request) } } else unauthorized(request) } def unauthorized(request: Request): Future[Response] = Future.value(Response(request.getProtocolVersion(), HttpResponseStatus.UNAUTHORIZED)) }
Example 79
Source File: InstanceMetadata.scala From graphcool-framework with Apache License 2.0 | 5 votes |
package cool.graph.metrics import com.twitter.finagle import com.twitter.finagle.http.{Method, Request, Response} import cool.graph.metrics.Utils._ import scala.concurrent.Future import com.twitter.conversions.time._ import com.twitter.finagle.service.Backoff object InstanceMetadata { import scala.concurrent.ExecutionContext.Implicits.global val service = finagle.Http.client.withRetryBackoff(Backoff.const(5.seconds)).withRequestTimeout(15.seconds).newService("169.254.169.254:80") private def fetch(path: String): Future[String] = { val request = Request(Method.Get, path) val requestFuture = service(request).asScala requestFuture.onFailure({ case e => throw MetricsError(s"Error while fetching request ${request.uri}: $e") }) requestFuture.map { (response: Response) => response.status match { case x if x.code >= 200 && x.code < 300 => val ip = response.contentString println(s"[Metrics] Request ${request.uri} result: $ip") ip case _ => throw MetricsError(s"Unable to retrieve EC2 metadata (${request.uri}) - ${response.status} | ${response.contentString}") } } } }
Example 80
Source File: HelloWorld.scala From finch-101 with Apache License 2.0 | 5 votes |
package i.f.workshop.finagle import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.{ListeningServer, Http, Service} import com.twitter.io.Buf import com.twitter.util.{Await, Future} object HelloWorld extends App { val service: Service[Request, Response] = new Service[Request, Response] { def apply(req: Request): Future[Response] = { val rep: Response = Response() rep.content = Buf.Utf8("Hello, World!") Future.value(rep) } } val server: ListeningServer = Http.server.serve(":8081", service) Await.ready(server) }
Example 81
Source File: StackParams.scala From finch-101 with Apache License 2.0 | 5 votes |
package i.f.workshop.finagle import com.twitter.finagle.param import com.twitter.finagle.http.{Response, Request} import com.twitter.finagle.service.TimeoutFilter import com.twitter.finagle.transport.Transport import com.twitter.finagle.{Http, Service} import com.twitter.util._ import com.twitter.conversions.time._ object StackParams extends App { implicit val timer: Timer = new JavaTimer() val service: Service[Request, Response] = new Service[Request, Response] { def apply(req: Request): Future[Response] = Future.sleep(5.seconds).map(_ => Response()) } val monitor: Monitor = new Monitor { def handle(exc: Throwable): Boolean = { println(exc) false } } Await.ready(Http.server .configured(TimeoutFilter.Param(1.seconds)) .configured(Transport.Verbose(true)) .configured(param.Monitor(monitor)) .serve(":8081", service) ) }
Example 82
Source File: MesosMasterClient.scala From cosmos with Apache License 2.0 | 5 votes |
package com.mesosphere.cosmos import com.mesosphere.cosmos.http.RequestSession import io.lemonlabs.uri.Uri import io.lemonlabs.uri.dsl._ import com.twitter.finagle.Service import com.twitter.finagle.http.Request import com.twitter.finagle.http.Response import com.twitter.util.Future import io.lemonlabs.uri.QueryString import org.jboss.netty.handler.codec.http.HttpMethod class MesosMasterClient( mesosUri: Uri, client: Service[Request, Response] ) extends ServiceClient(mesosUri) { def tearDownFramework( frameworkId: String )( implicit session: RequestSession ): Future[thirdparty.mesos.master.model.MesosFrameworkTearDownResponse] = { val formData = QueryString.fromPairs("frameworkId" -> frameworkId).toString() val encodedString = formData.toString.substring(1) val uri = "master" / "teardown" client(postForm(uri, encodedString)) .map(validateResponseStatus(HttpMethod.POST, uri, _)) .map { _ => thirdparty.mesos.master.model.MesosFrameworkTearDownResponse() } } def getFrameworks( name: String )( implicit session: RequestSession ): Future[List[thirdparty.mesos.master.model.Framework]] = { val uri = "master" / "frameworks" val request = get(uri) client(request).flatMap( decodeTo[thirdparty.mesos.master.model.MasterState](HttpMethod.GET, uri, _) ).map { state => state.frameworks.filter(_.name == name) } } }
Example 83
Source File: ServiceUpdater.scala From cosmos with Apache License 2.0 | 5 votes |
package com.mesosphere.cosmos import _root_.io.circe.JsonObject import com.mesosphere.cosmos.circe.Decoders.parse import com.mesosphere.cosmos.http.RequestSession import com.mesosphere.cosmos.thirdparty.marathon.model.AppId import com.mesosphere.error.ResultOps import com.twitter.finagle.http.Response import com.twitter.finagle.http.Status import com.twitter.util.Future final class ServiceUpdater(adminRouter: AdminRouter) { def update( appId: AppId, renderedConfig: JsonObject )(implicit session: RequestSession): Future[String] = { adminRouter.update(appId, renderedConfig).map { response: Response => response.status match { case Status.Ok => parse(response.contentString).getOrThrow.hcursor.get[String]("deploymentId").right.get case _ => // TODO: Why do we do this? throw new Error(response.contentString) } } } } object ServiceUpdater { def apply(adminRouter: AdminRouter): ServiceUpdater = { new ServiceUpdater(adminRouter) } }
Example 84
Source File: ServiceDescribeSpec.scala From cosmos with Apache License 2.0 | 5 votes |
package com.mesosphere.cosmos.handler import com.mesosphere.cosmos.HttpErrorResponse import com.mesosphere.cosmos.IntegrationBeforeAndAfterAll import com.mesosphere.cosmos.ItObjects import com.mesosphere.cosmos.ItOps._ import com.mesosphere.cosmos.Requests import com.mesosphere.cosmos.RoundTrips import com.mesosphere.cosmos.error.MarathonAppNotFound import com.mesosphere.cosmos.http.CosmosRequests import com.mesosphere.cosmos.http.TestContext import com.mesosphere.cosmos.rpc.v1.model.ErrorResponse import com.mesosphere.cosmos.rpc.v1.model.ServiceDescribeRequest import com.mesosphere.cosmos.test.CosmosIntegrationTestClient.CosmosClient import com.mesosphere.cosmos.thirdparty.marathon.model.AppId import com.twitter.bijection.Conversion.asMethod import com.twitter.finagle.http.Response import com.twitter.finagle.http.Status import org.scalatest.FeatureSpec import org.scalatest.Matchers final class ServiceDescribeSpec extends FeatureSpec with Matchers with IntegrationBeforeAndAfterAll{ private[this] implicit val testContext = TestContext.fromSystemProperties() private[this] val name = "helloworld" private[this] val port = 9999 feature("The service/describe endpoint") { scenario("The user would like to know the upgrades available to a service") { RoundTrips.withInstallV1(name, Some("0.1.0".detailsVersion)).runWith { ir => Requests.describeService(ir.appId).upgradesTo.shouldBe( List("0.4.2").map(_.version)) } } scenario("The user would like to know the downgrades available to a service") { RoundTrips.withInstallV1(name, Some("0.4.2".detailsVersion)).runWith { ir => Requests.describeService(ir.appId).downgradesTo.shouldBe( List("0.4.2", "0.4.1", "0.4.0", "0.1.0").map(_.version)) } } scenario("The user would like to know the package definition used to run a service") { RoundTrips.withInstallV1(name, Some("0.1.0".detailsVersion)).runWith { ir => Requests.describeService(ir.appId).`package`.shouldBe( Requests.describePackage(ir.packageName, Some(ir.packageVersion)).`package`) } } scenario("The user should receive an error if the service is not present") { val appId = AppId("/does-not-exist-4204242") val error = intercept[HttpErrorResponse](Requests.describeService(appId)) error.status shouldBe Status.BadRequest error.errorResponse.shouldBe(MarathonAppNotFound(appId).as[ErrorResponse]) } scenario("The user would like to know the options used to run a service") { val options = s"""{ "port": $port, "name": "$name" }""".json.asObject RoundTrips.withInstallV1(name, Some("0.1.0".detailsVersion), options).runWith { ir => Requests.describeService(ir.appId).resolvedOptions.shouldBe(options) } } scenario("The user would like to know the options he provided to run a service") { val options = s"""{ "port": $port }""".json.asObject RoundTrips.withInstallV1(name, Some("0.1.0".detailsVersion), options).runWith { ir => Requests.describeService(ir.appId).userProvidedOptions.shouldBe(options) } } scenario("The user would like to describe a service via a custom manager") { val appId = AppId("cassandra") Requests.installV2("cassandra", appId = Some(appId), managerId = Some(ItObjects.customManagerAppName)) val serviceDescribeRequest = ServiceDescribeRequest(appId, Some(ItObjects.customManagerAppName), None, None) val serviceDescribeResponse = submitServiceDescribeRequest(serviceDescribeRequest) assertResult(Status.Ok)(serviceDescribeResponse.status) Requests.uninstall("cassandra", managerId = Some(ItObjects.customManagerAppName)) Requests.waitForMarathonAppToDisappear(appId) } } def submitServiceDescribeRequest( request: ServiceDescribeRequest )( implicit testContext: TestContext ): Response = { CosmosClient.submit(CosmosRequests.serviceDescribe(request)) } }
Example 85
Source File: CosmosResponse.scala From cosmos with Apache License 2.0 | 5 votes |
package com.mesosphere.cosmos.http import com.mesosphere.cosmos.HttpErrorResponse import com.mesosphere.cosmos.rpc import com.twitter.finagle.http.Response import com.twitter.finagle.http.Status import io.circe.Decoder import io.circe.jawn.decode import org.scalatest.Matchers sealed trait CosmosResponse[+A] { def get(): A } object CosmosResponse { def apply[Res: Decoder](response: Response): CosmosResponse[Res] = { if (response.status.code / 100 == 2) { decode[Res](response.contentString) match { case Left(_) => val status = response.status val content = response.contentString Matchers.fail(s"Could not decode as successful response ($status): '$content'") case Right(successfulResponse) => SuccessCosmosResponse(successfulResponse) } } else { decode[rpc.v1.model.ErrorResponse](response.contentString) match { case Left(_) => val status = response.status val content = response.contentString Matchers.fail(s"Could not decode as error response ($status): '$content'") case Right(errorResponse) => ErrorCosmosResponse(response.status, errorResponse) } } } } final case class SuccessCosmosResponse[A](body: A) extends CosmosResponse[A] { override def get(): A = body } final case class ErrorCosmosResponse( status: Status, error: rpc.v1.model.ErrorResponse ) extends CosmosResponse[Nothing] { override def get(): Nothing = throw HttpErrorResponse(status, error) }
Example 86
Source File: HttpDifferenceProxy.scala From diffy with GNU Affero General Public License v3.0 | 5 votes |
package ai.diffy.proxy import java.net.SocketAddress import ai.diffy.analysis.{DifferenceAnalyzer, InMemoryDifferenceCollector, JoinedDifferences} import ai.diffy.lifter.{HttpLifter, Message} import com.twitter.finagle.http.{Method, Request, Response} import com.twitter.finagle.{Filter, Http} import com.twitter.util.{Future, StorageUnit, Try} object HttpDifferenceProxy { def requestHostHeaderFilter(host: String) = Filter.mk[Request, Response, Request, Response] { (req, svc) => req.host(host) svc(req) } } trait HttpDifferenceProxy extends DifferenceProxy { import HttpDifferenceProxy._ val servicePort: SocketAddress val lifter = new HttpLifter(settings.excludeHttpHeadersComparison, settings.resourceMatcher) override type Req = Request override type Rep = Response override type Srv = HttpService override def serviceFactory(serverset: String, label: String) = HttpService(requestHostHeaderFilter(serverset) andThen Http.client .withMaxResponseSize(settings.maxResponseSize) .withMaxHeaderSize(settings.maxHeaderSize) .newService(serverset, label)) override lazy val server = Http.serve( servicePort, proxy ) override def liftRequest(req: Request): Future[Message] = lifter.liftRequest(req) override def liftResponse(resp: Try[Response]): Future[Message] = lifter.liftResponse(resp) } object SimpleHttpDifferenceProxy { case class SimpleHttpsDifferenceProxy ( settings: Settings, collector: InMemoryDifferenceCollector, joinedDifferences: JoinedDifferences, analyzer: DifferenceAnalyzer) extends HttpDifferenceProxy { import SimpleHttpDifferenceProxy._ override val servicePort = settings.servicePort override val proxy = Filter.identity andThenIf (!settings.allowHttpSideEffects, httpSideEffectsFilter) andThen super.proxy override def serviceFactory(serverset: String, label: String) = HttpService( Http.client .withTls(serverset) .newService(serverset+":"+settings.httpsPort, label) ) }
Example 87
Source File: ClientService.scala From diffy with GNU Affero General Public License v3.0 | 5 votes |
package ai.diffy.proxy import com.twitter.finagle.http.{Request, Response} import com.twitter.finagle.thrift.ThriftClientRequest import com.twitter.finagle.{Addr, Name, Service} import com.twitter.util.{Time, Var} trait ClientService[Req, Rep] { val client: Service[Req, Rep] } case class ThriftService( override val client: Service[ThriftClientRequest, Array[Byte]], path: Name) extends ClientService[ThriftClientRequest, Array[Byte]] { var members: Int = 0 var serversetValid = false var changedAt: Option[Time] = None var resetAt: Option[Time] = None var changeCount: Int = 0 val boundServerset: Option[Var[Addr]] = path match { case Name.Bound(addr) => serversetValid = true Some(addr) case _ => serversetValid = false None } boundServerset foreach { _.changes.respond { case Addr.Bound(addrs, _) => serversetValid = true sizeChange(addrs.size) case Addr.Failed(_) | Addr.Neg => serversetValid = false sizeChange(0) case Addr.Pending => () } } private[this] def sizeChange(size: Int) { changeCount += 1 if (changeCount > 1) { changedAt = Some(Time.now) if (members == 0) { resetAt = Some(Time.now) } } members = size } } case class HttpService( override val client: Service[Request, Response]) extends ClientService[Request, Response]
Example 88
Source File: HttpLifter.scala From diffy with GNU Affero General Public License v3.0 | 5 votes |
package ai.diffy.lifter import ai.diffy.util.ResourceMatcher import com.twitter.finagle.http.{Request, Response} import com.twitter.logging.Logger import com.twitter.util.{Future, Try} object HttpLifter { val ControllerEndpointHeaderName = "X-Action-Name" def contentTypeNotSupportedException(contentType: String) = new Exception(s"Content type: $contentType is not supported") def contentTypeNotSupportedExceptionFuture(contentType: String) = Future.exception(contentTypeNotSupportedException(contentType)) case class MalformedJsonContentException(cause: Throwable) extends Exception("Malformed Json content") { initCause(cause) } } class HttpLifter(excludeHttpHeadersComparison: Boolean, resourceMatcher: Option[ResourceMatcher] = None) { import HttpLifter._ private[this] val log = Logger(classOf[HttpLifter]) private[this] def headersMap(response: Response): Map[String, Any] = { if(!excludeHttpHeadersComparison) { val rawHeaders = response.headerMap.toSeq val headers = rawHeaders map { case (name, value) => (name.toLowerCase, value) } groupBy { _._1} map { case (name, pairs) => name -> (pairs map { _._2 } sorted) } Map( "headers" -> FieldMap(headers)) } else Map.empty } def liftRequest(req: Request): Future[Message] = { val headers = req.headerMap val canonicalResource = headers .get("Canonical-Resource") .orElse(resourceMatcher.flatMap(_.resourceName(req.path))) val params = req.getParams() val body = StringLifter.lift(req.getContentString()) Future.value( Message( canonicalResource, FieldMap( Map( "uri" -> req.uri, "method" -> req.method, "headers" -> headers, "params" -> params, "body" -> body ) ) ) ) } def liftResponse(resp: Try[Response]): Future[Message] = { log.debug(s"$resp") Future.const(resp) flatMap { r: Response => val controllerEndpoint = r.headerMap.get(ControllerEndpointHeaderName) val stringContentTry = Try { StringLifter.lift(r.getContentString()) } Future.const(stringContentTry map { stringContent => val responseMap = Map( r.statusCode.toString -> (Map( "content" -> stringContent, "chunked" -> r.isChunked ) ++ headersMap(r)) ) Message(controllerEndpoint, FieldMap(responseMap)) }) } } }
Example 89
Source File: DiffyProject.scala From diffy with GNU Affero General Public License v3.0 | 5 votes |
package ai.diffy.util import ai.diffy.compare.Difference import ai.diffy.lifter.JsonLifter import ai.diffy.proxy.Settings import com.twitter.finagle.Http import com.twitter.finagle.http.{Method, Request, Response} import com.twitter.util.Future object DiffyProject { private[this] sealed trait config { val client: Request => Future[Response] } private[this] object production extends config { override val client: Request => Future[Response] = Http.client .withTls("diffyproject.appspot.com") .newService("diffyproject.appspot.com:443") } private[this] object development extends config { override val client: Request => Future[Response] = Http.client .newService("localhost:7000") } private[this] val cfg: config = production def settings(settings: Settings): Unit ={ s = settings val m = Difference.mkMap(s) val ed = m("emailDelay") uid = m.updated("emailDelay",ed.toString).updated("artifact", "od.2019.8.27.001") log("start") } private[this] var s :Settings = _ private[this] var uid :Map[String, Any] = Map.empty def log(message: String): Unit = { val request = Request(Method.Post, "/stats") request.setContentTypeJson() request.setContentString(JsonLifter.encode(uid.updated("message", message))) cfg.client(request) } }
Example 90
Source File: FinchTemplateApi.scala From finch-template with BSD 3-Clause "New" or "Revised" License | 5 votes |
package com.redbubble.finchtemplate import com.redbubble.finchtemplate.api.v1 import com.redbubble.finchtemplate.api.v1.FinchTemplateErrorHandler.apiErrorHandler import com.redbubble.finchtemplate.api.v1.{FinchTemplateErrorHandler, ResponseEncoders} import com.redbubble.finchtemplate.util.config.Config._ import com.redbubble.finchtemplate.util.config.{Development, Environment, Test} import com.redbubble.finchtemplate.util.metrics.Metrics._ import com.redbubble.hawk.HawkAuthenticateRequestFilter import com.redbubble.util.http.filter.{ExceptionFilter, HttpBasicAuthFilter, RequestLoggingFilter, RoutingMetricsFilter} import com.twitter.finagle.Service import com.twitter.finagle.http.{Request, Response} import io.finch.Application object ApiAuthFilter extends HawkAuthenticateRequestFilter(apiAuthenticationCredentials, whitelistedAuthPaths, serverMetrics) object BasicAuthFilter extends HttpBasicAuthFilter(s"$systemName Security", basicAuthCredentials, basicAuthPaths, serverMetrics) object UnhandledExceptionsFilter extends ExceptionFilter(ResponseEncoders.throwableEncode, FinchTemplateErrorHandler, serverMetrics) object RouteMetricsFilter extends RoutingMetricsFilter(serverMetrics) object FinchTemplateApi extends ResponseEncoders { private val api = v1.api def apiService: Service[Request, Response] = filters andThen api.handle(apiErrorHandler).toServiceAs[Application.Json] private def filters = { val baseFilters = RequestLoggingFilter andThen UnhandledExceptionsFilter andThen RouteMetricsFilter Environment.env match { case Development => baseFilters case Test => baseFilters case _ => baseFilters andThen ApiAuthFilter andThen BasicAuthFilter } } }
Example 91
Source File: derivation.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.custom package derivation import com.twitter.finagle.http.Response import derevo.Derivation import ru.tinkoff.tschema.ResponseStatus object responseStatus extends Derivation[ResponseStatus] { def apply[T](status: Int): ResponseStatus[T] = ResponseStatus(status) } object jsonError extends Derivation[ErrorResponse] { def apply[T](status: Int)(implicit json: AsResponse.Json[T]): ErrorResponse[T] = new ErrorResponse[T](status) { def apply(a: T): Response = json(a).statusCode(status) } } object plainError extends Derivation[ErrorResponse] { def apply[T](status: Int)(implicit plain: AsResponse.Plain[T]): ErrorResponse[T] = new ErrorResponse[T](status) { def apply(a: T): Response = plain(a).statusCode(status) } }
Example 92
Source File: ExceptCompleting.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.custom import cats.syntax.applicative._ import cats.{Applicative, ApplicativeError, Monad} import com.twitter.finagle.http.{Response, Status} import ru.tinkoff.tschema.finagle.{Completing, LiftHttp} trait ExceptCompleting[F[_], R, E, A] extends Completing[F, ExceptResult[E, R], A] object ExceptCompleting extends ExceptCompleteInstances with ExceptPureCompletes { implicit def optionComplete[F[_], G[_], R, A](implicit F: Monad[F], success: Completing[F, R, A], lift: LiftHttp[F, G] ): ExceptCompleting[F, R, None.type, G[Option[A]]] = fa => F.flatMap(lift(fa))(_.fold(Response(Status.NotFound).pure[F])(success.complete)) implicit def pureEitherComplete[F[_], G[_], E, R, A](implicit F: Monad[F], success: Completing[F, R, A], err: AsResponse.Error[E], lift: LiftHttp[F, G] ): ExceptCompleting[F, R, E, G[Either[E, A]]] = fa => F.flatMap(lift(fa))(_.fold(err(_).pure[F], success.complete)) } trait ExceptCompleteInstances { implicit def applicativeErrorComplete[F[_], G[_], R, E, A](implicit G: ApplicativeError[G, E], F: Monad[F], success: Completing[F, R, A], error: AsResponse.Error[E], lift: LiftHttp[F, G] ): ExceptCompleting[F, R, E, G[A]] = fa => F.flatMap(lift(G.attempt(fa)))(_.fold(error(_).pure[F], success.complete)) } trait ExceptPureCompletes { implicit def pureOptionComplete[F[_], R, A](implicit F: Applicative[F], success: Completing[F, R, A], ): ExceptCompleting[F, R, None.type, Option[A]] = _.fold(Response(Status.NotFound).pure[F])(success.complete) implicit def pureEitherComplete[F[_], E, R, A](implicit F: Applicative[F], success: Completing[F, R, A], err: AsResponse.Error[E], ): ExceptCompleting[F, R, E, Either[E, A]] = _.fold(err(_).pure[F], success.complete) }
Example 93
Source File: EnvRouting.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.finagle.envRouting import cats.syntax.semigroup._ import com.twitter import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.finagle.{Service, http} import com.twitter.util.{Future, Promise} import monix.eval.Task import monix.execution.Scheduler import ru.tinkoff.tschema.finagle.Rejection.Recover import ru.tinkoff.tschema.finagle._ import ru.tinkoff.tschema.finagle.envRouting.EnvRouting.EnvHttp import ru.tinkoff.tschema.utils.SubString import tofu.env.Env final case class EnvRouting[+R]( request: http.Request, path: CharSequence, matched: Int, embedded: R ) object EnvRouting extends EnvInstanceDecl { type EnvHttp[R, +A] = Env[EnvRouting[R], A] implicit def taskRouted[R] : RoutedPlus[EnvHttp[R, *]] with ConvertService[EnvHttp[R, *]] with LiftHttp[EnvHttp[R, *], Env[R, *]] = envRoutedAny.asInstanceOf[EnvRoutedConvert[R]] implicit def envRunnable[R](implicit recover: Recover[EnvHttp[R, *]] = Recover.default[EnvHttp[R, *]] ): RunHttp[EnvHttp[R, *], Env[R, *]] = response => { val handled = response.onErrorRecoverWith { case Rejected(rej) => recover(rej) } Env(r => Task.deferAction(implicit sched => Task.delay(execResponse(r, handled, _)))) } private[this] def execResponse[R](r: R, envResponse: EnvHttp[R, Response], request: Request)(implicit sc: Scheduler ): Future[Response] = { val promise = Promise[Response] val routing = EnvRouting(request, SubString(request.path), 0, r) val cancelable = envResponse.run(routing).runAsync { case Right(res) => promise.setValue(res) case Left(ex) => val resp = Response(Status.InternalServerError) val message = Option(ex.getLocalizedMessage).getOrElse(ex.toString) resp.setContentString(message) promise.setValue(resp) } promise.setInterruptHandler { case _ => cancelable.cancel() } promise } } private[finagle] class EnvInstanceDecl { protected trait EnvRoutedConvert[R] extends RoutedPlus[EnvHttp[R, *]] with ConvertService[EnvHttp[R, *]] with LiftHttp[EnvHttp[R, *], Env[R, *]] { private type F[a] = EnvHttp[R, a] implicit private[this] val self: RoutedPlus[F] = this def matched: F[Int] = Env.fromFunc(_.matched) def withMatched[A](m: Int, fa: F[A]): F[A] = fa.local(_.copy(matched = m)) def path: F[CharSequence] = Env.fromFunc(_.path) def request: F[http.Request] = Env.fromFunc(_.request) def reject[A](rejection: Rejection): F[A] = Routed.unmatchedPath[F].flatMap(path => throwRej(rejection withPath path.toString)) def combineK[A](x: F[A], y: F[A]): F[A] = catchRej(x)(xrs => catchRej(y)(yrs => throwRej(xrs |+| yrs))) def convertService[A](svc: Service[http.Request, A]): F[A] = Env { r => Task.cancelable { cb => val fut = svc(r.request).respond { case twitter.util.Return(a) => cb.onSuccess(a) case twitter.util.Throw(ex) => cb.onError(ex) } Task(fut.raise(new InterruptedException)) } } def apply[A](fa: Env[R, A]): EnvHttp[R, A] = fa.localP(_.embedded) @inline private[this] def catchRej[A](z: F[A])(f: Rejection => F[A]): F[A] = z.onErrorRecoverWith { case Rejected(xrs) => f(xrs) } @inline private[this] def throwRej[A](map: Rejection): F[A] = Env.raiseError(envRouting.Rejected(map)) } protected object envRoutedAny extends EnvRoutedConvert[Any] }
Example 94
Source File: TaskRouting.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.finagle.envRouting import cats.syntax.semigroup._ import com.twitter import com.twitter.finagle.http.{Request, Response, Status} import com.twitter.finagle.{Service, http} import com.twitter.util.{Future, Promise} import monix.eval.Task import monix.execution.Scheduler import ru.tinkoff.tschema.finagle.Rejection.Recover import ru.tinkoff.tschema.finagle._ import ru.tinkoff.tschema.finagle.envRouting.TaskRouting.TaskHttp import ru.tinkoff.tschema.utils.SubString import tofu.env.Env final case class TaskRouting( request: http.Request, path: CharSequence, matched: Int ) object TaskRouting extends TaskInstanceDecl { type TaskHttp[+A] = Env[TaskRouting, A] implicit val taskRouted: RoutedPlus[TaskHttp] with ConvertService[TaskHttp] with LiftHttp[TaskHttp, Task] = new TaskRoutedConvert implicit def envRunnable(implicit recover: Recover[TaskHttp] = Recover.default[TaskHttp] ): RunHttp[TaskHttp, Task] = response => Task.deferAction(implicit sched => Task.delay(execResponse(response, _))) private[this] def execResponse( envResponse: TaskHttp[Response], request: Request )(implicit sc: Scheduler, recover: Recover[TaskHttp]): Future[Response] = { val promise = Promise[Response] val routing = TaskRouting(request, SubString(request.path), 0) val cancelable = envResponse.onErrorRecoverWith { case Rejected(rej) => recover(rej) }.run(routing).runAsync { case Right(res) => promise.setValue(res) case Left(ex) => val resp = Response(Status.InternalServerError) resp.setContentString(ex.getMessage) promise.setValue(resp) } promise.setInterruptHandler { case _ => cancelable.cancel() } promise } } private[finagle] class TaskInstanceDecl { protected class TaskRoutedConvert extends RoutedPlus[TaskHttp] with ConvertService[TaskHttp] with LiftHttp[TaskHttp, Task] { private type F[a] = TaskHttp[a] implicit private[this] val self: RoutedPlus[F] = this def matched: F[Int] = Env.fromFunc(_.matched) def withMatched[A](m: Int, fa: F[A]): F[A] = fa.local(_.copy(matched = m)) def path: F[CharSequence] = Env.fromFunc(_.path) def request: F[http.Request] = Env.fromFunc(_.request) def reject[A](rejection: Rejection): F[A] = Routed.unmatchedPath[F].flatMap(path => throwRej(rejection withPath path.toString)) def combineK[A](x: F[A], y: F[A]): F[A] = catchRej(x)(xrs => catchRej(y)(yrs => throwRej(xrs |+| yrs))) def convertService[A](svc: Service[http.Request, A]): F[A] = Env { r => Task.cancelable { cb => val fut = svc(r.request).respond { case twitter.util.Return(a) => cb.onSuccess(a) case twitter.util.Throw(ex) => cb.onError(ex) } Task(fut.raise(new InterruptedException)) } } def apply[A](fa: Task[A]): TaskHttp[A] = Env.fromTask(fa) @inline private[this] def catchRej[A](z: F[A])(f: Rejection => F[A]): F[A] = z.onErrorRecoverWith { case Rejected(xrs) => f(xrs) } @inline private[this] def throwRej[A](map: Rejection): F[A] = Env.raiseError(envRouting.Rejected(map)) } }
Example 95
Source File: package.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.finagle import com.twitter.finagle.http.{Response, Status} import com.twitter.util.{Future, Promise} import zio.{Exit, Fiber, Has, Runtime, ZIO} package object zioRouting { type NoError <: Nothing type None >: Any type ZRouting = ZioRouting[Any] type HasRouting = Has[ZRouting] type UIOHttp[+A] = ZIO[ZioRouting[None], Fail[NoError], A] type IOHttp[+E, +A] = ZIO[ZioRouting[None], Fail[E], A] type TaskHttp[+A] = ZIO[ZioRouting[None], Fail[Throwable], A] type URIOHttp[-R, +A] = ZIO[ZioRouting[R], Fail[NoError], A] type RIOHttp[-R, +A] = ZIO[ZioRouting[R], Fail[Throwable], A] type ZIOHttp[-R, +E, +A] = ZIO[ZioRouting[R], Fail[E], A] type UIOH[+A] = ZIO[HasRouting, Fail[NoError], A] type IOH[+E, +A] = ZIO[HasRouting, Fail[E], A] type TaskH[+A] = ZIO[HasRouting, Fail[Throwable], A] type URIOH[-R, +A] = ZIO[HasRouting with R, Fail[NoError], A] type RIOH[-R, +A] = ZIO[HasRouting with R, Fail[Throwable], A] type ZIOH[-R, +E, +A] = ZIO[HasRouting with R, Fail[E], A] private[zioRouting] def execWithRuntime[R, E <: Throwable](runtime: Runtime[R])( zio: ZIO[R, E, Response] ): Future[Response] = { val promise = Promise[Response] runtime.unsafeRunAsync(setInterruption(zio, promise, runtime)) { case Exit.Success(resp) => promise.setValue(resp) case Exit.Failure(cause) => val resp = Response(Status.InternalServerError) val error = cause.squash resp.setContentString(Option(error.getLocalizedMessage).getOrElse(error.toString)) promise.setValue(resp) } promise } private def setInterruption[R, E, A, X](zio: ZIO[R, E, A], promise: Promise[X], rt: Runtime[Any]): ZIO[R, E, A] = { def setInterrupt(fiber: Fiber[Any, Any]) = ZIO.effectTotal(promise.setInterruptHandler { case _ => rt.unsafeRunAsync(fiber.interrupt)(_ => ()) }) zio.fork.tap(setInterrupt) >>= (_.join) } private[zioRouting] def execResponse[R, R1, E <: Throwable]( runtime: zio.Runtime[R], zioResponse: ZIO[R1, E, Response], f: R => R1 ): Future[Response] = zioRouting.execWithRuntime(runtime)( zioResponse.provideSome[R](f) ) }
Example 96
Source File: Completing.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema package finagle import cats.syntax.flatMap._ import cats.{Applicative, Contravariant, Functor, Monad, MonoidK} import com.twitter.finagle.http.{Response, Status} import ru.tinkoff.tschema.Decompose import ru.tinkoff.tschema.Decompose.{Cons, Last, NotFound} import ru.tinkoff.tschema.finagle.util.message import shapeless.Lazy import cats.syntax.applicative._ import cats.syntax.apply._ import scala.annotation.implicitNotFound @implicitNotFound( "Could not complete ${A} knowing that result should be ${Out} using ${In} in ${F}. Make sure you have appropriate serializing instance and imported complete implementation from tethysIntances, circeInstances, etc." ) trait CompleteIn[F[_], -In, Out, A] { def completeIn(a: A, in: In): F[Response] def as[Out1]: CompleteIn[F, In, Out1, A] = this.asInstanceOf[CompleteIn[F, In, Out1, A]] } object CompleteIn trait Completing[F[_], R, A] extends CompleteIn[F, Any, R, A] { def complete(a: A): F[Response] def completeIn(a: A, in: Any): F[Response] = complete(a) override def as[R1]: Completing[F, R1, A] = this.asInstanceOf[Completing[F, R1, A]] } object Completing { implicit def contravariant[F[_], R]: Contravariant[Completing[F, R, *]] = new Contravariant[Completing[F, R, *]] { def contramap[A, B](fa: Completing[F, R, A])(f: B => A): Completing[F, R, B] = b => fa.complete(f(b)) } }
Example 97
Source File: MkService.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.finagle import cats.{FlatMap, Monad} import com.twitter.finagle.http.Response import ru.tinkoff.tschema.macros.MakerMacro import ru.tinkoff.tschema.typeDSL.DSLDef import shapeless.HList import cats.syntax.semigroupk._ object MkService { def apply[F[_]] = new MkApply[F] class MkApply[F[_]] { def apply[Def <: DSLDef, Impl](definition: => Def)(impl: Impl): F[Response] = macro MakerMacro.makeRouteHNil[F, macroInterface.type, Def, Impl, F[Response]] def of[Def <: DSLDef, Impl, In <: HList](definition: => Def)(impl: Impl)(input: In): F[Response] = macro MakerMacro.makeRoute[F, macroInterface.type, Def, Impl, F[Response], In] } object macroInterface { def makeResult[F[_], Out]: ResultPA1[F, Out] = new ResultPA1[F, Out] def concatResults[F[_]: RoutedPlus](x: F[Response], y: F[Response]): F[Response] = x <+> y def serve[F[_], T] = new ServePA[F, T] def route[Res](res: => Res) = new RoutePA[Res](res) class ResultPA1[F[_], Out] { def apply[In <: HList, Impl](in: In)(impl: Impl)(key: String, groups: String*): F[Response] = macro MakerMacro.makeResult[F, In, Out, Impl, F[Response]] } class RoutePA[Res](res: => Res) { def apply[F[_]: Routed: Monad, In, Out](in: In)(implicit complete: CompleteIn[F, In, Out, Res]): F[Response] = Routed.checkPathEnd(complete.completeIn(res, in)) } class ServePA[F[_], T] { def apply[In, Out](in: In)(implicit F: Monad[F], serve: Serve[T, F, In, Out]) = new ServePA2[F, T, In, Out](in)(serve) } class ServePA2[F[_]: FlatMap, T, In, Out](val in: In)(srv: Serve[T, F, In, Out]) { def apply(f: Out => F[Response]): F[Response] = srv.process(in, f) } } }
Example 98
Source File: message.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.finagle.util import cats.syntax.applicative._ import cats.syntax.flatMap._ import cats.syntax.functor._ import cats.syntax.option._ import cats.{Applicative, Functor, Monad} import com.twitter.finagle.http.{MediaType, Response, Status} import ru.tinkoff.tschema.finagle.{Completing, LiftHttp, ParseBody, Rejection, Routed} object message { def response(s: String, contentType: String, status: Status = Status.Ok): Response = { val resp = Response(status) resp.setContentType(contentType) resp.setContentString(s) resp } def stringResponse(s: String, status: Status = Status.Ok): Response = response(s, "text/plain", status) def jsonResponse(s: String, status: Status = Status.Ok): Response = response(s, MediaType.Json, status) def emptyComplete[F[_]: Applicative, A, B](status: Status = Status.Ok): Completing[F, A, B] = _ => Response(status).pure[F] def parseRequest[F[_]: Routed: Monad, A](f: String => Either[Throwable, A]): F[A] = Routed.request.flatMap(req => f(req.contentString).fold(fail => Routed.reject(Rejection.body(fail.getMessage)), res => res.pure[F]) ) def parseOptRequest[F[_]: Routed: Monad, A](f: String => Either[Throwable, A]): F[Option[A]] = Routed.request.flatMap { req => val cs = req.contentString if (cs.isEmpty) none.pure[F] else f(cs).fold(fail => Routed.reject(Rejection.body(fail.getMessage)), res => res.some.pure[F]) } def stringComplete[F[_]: Applicative, A](f: A => String, status: Status = Status.Ok): Completing[F, A, A] = a => stringResponse(f(a), status).pure[F] def fstringComplete[F[_], G[_]: Functor, A](f: A => String, status: Status = Status.Ok)(implicit lift: LiftHttp[F, G] ): Completing[F, A, G[A]] = fa => lift(fa.map(a => stringResponse(f(a), status))) def jsonComplete[F[_]: Applicative, A](f: A => String, status: Status = Status.Ok): Completing[F, A, A] = a => jsonResponse(f(a), status).pure[F] def fjsonComplete[F[_], G[_]: Functor, A](f: A => String, status: Status = Status.Ok)(implicit lift: LiftHttp[F, G] ): Completing[F, A, G[A]] = fa => lift(fa.map(a => jsonResponse(f(a), status))) def jsonBodyParse[F[_]: Routed: Monad, A](f: String => Either[Throwable, A]): ParseBody[F, A] = new ParseBody[F, A] { override def parse(): F[A] = parseRequest(f) override def parseOpt(): F[Option[A]] = parseOptRequest(f) } }
Example 99
Source File: ParamDirectives.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema package finagle import cats.Monad import cats.instances.list._ import cats.syntax.applicative._ import cats.syntax.flatMap._ import com.twitter.finagle.http.{Request, Response} import ru.tinkoff.tschema.param._ import shapeless._ import shapeless.labelled.{FieldType, field} trait ParamDirectives[S <: ParamSource] { def source: S def getByName[F[_]: Routed: Monad, A](name: String, fa: Option[CharSequence] => F[A]): F[A] def notFound(name: String): Rejection = Rejection.missingParam(name, source) def malformed(name: String, error: String): Rejection = Rejection.malformedParam(name, error, source) def singleRejection(name: String, error: SingleParamError): Rejection = error match { case MissingParamError => notFound(name) case ParseParamError(err) => malformed(name, err) } def errorReject[F[_], A](name: String, error: ParamError)(implicit routed: Routed[F]): F[A] = error match { case single: SingleParamError => routed.reject(singleRejection(name, single)) case MultiParamError(vals) => Routed.rejectMany(vals.map { case (field, err) => singleRejection(field, err) }.toSeq: _*) } def direct[F[_]: Routed: Monad, A, name, In <: HList]( name: String, result: Param.Result[A], in: In, k: (FieldType[name, A] :: In) => F[Response] ): F[Response] = result.fold(errorReject[F, Response](name, _), a => k(field[name](a) :: in)) def provideOrReject[F[_]: Routed: Monad, A](name: String, result: Param.Result[A]): F[A] = result.fold(errorReject[F, A](name, _), _.pure[F]) } abstract class ParamDirectivesSimple[S <: ParamSource](val source: S) extends ParamDirectives[S] { def getFromRequest(name: String)(req: Request): Option[CharSequence] def getByName[F[_]: Routed: Monad, A](name: String, f: Option[CharSequence] => F[A]): F[A] = Routed.request.flatMap(req => f(getFromRequest(name)(req))) } object ParamDirectives { def apply[S <: ParamSource](implicit dir: ParamDirectives[S]): ParamDirectives[S] = dir type TC[A <: ParamSource] = ParamDirectives[A] type TCS[A <: ParamSource] = ParamDirectivesSimple[A] import ParamSource._ implicit val queryParamDirective: TC[Query] = new TCS[Query](Query) { def getFromRequest(name: String)(req: Request): Option[String] = req.params.get(name) } implicit val cookieParamDirectives: TC[Cookie] = new TCS[Cookie](Cookie) { def getFromRequest(name: String)(req: Request): Option[String] = req.cookies.get(name).map(_.value) } implicit val pathParamDirectives: TC[ParamSource.Path] = new TC[ParamSource.Path] { def getByName[F[_]: Routed: Monad, A](name: String, fa: Option[CharSequence] => F[A]): F[A] = Routed.segment(fa) def source = ParamSource.Path } implicit val formDataParamDirectives: TC[Form] = new TCS[Form](Form) { def getFromRequest(name: String)(req: Request): Option[String] = req.params.get(name) } implicit val headerParamDirectives: TC[Header] = new TCS[Header](Header) { def getFromRequest(name: String)(req: Request): Option[String] = req.headerMap.get(name) } }
Example 100
Source File: Server.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.example import ExampleSwagger._ import cats.instances.list._ import cats.syntax.foldable._ import cats.syntax.semigroupk._ import com.twitter.finagle.{Http => FHttp} import com.twitter.finagle.http.Response import com.twitter.util.{Await, Duration} import ru.tinkoff.tschema.finagle.RunHttp import zio.blocking.Blocking import zio.console._ import zio.{blocking => _, _} object Server extends App { val modules: List[ExampleModule] = List( Greeting, TestModule, FiltersModule, FormFieldsModule, MultiParameters, ProxyModule, VersionModule, Authorize, ReceiveModule ) val svc: Http[Response] = modules.foldMapK(_.route) <+> ExampleSwagger.route val server = for { srv <- RunHttp.run[Example](svc) list <- ZIO.effect(FHttp.serve("0.0.0.0:9191", srv)) _ <- putStr(s"started at ${list.boundAddress}") _ <- ZIO.effect(Await.ready(list, Duration.Top)).fork res <- ZIO.never } yield res val layer: URLayer[Blocking with Console, FullEnv] = ZLayer.identity[Blocking with Console] ++ ExampleEnv.live def run(args: List[String]): URIO[Blocking with Console, Int] = layer.build.use(r => server.catchAll(ex => putStr(ex.getMessage)).provide(r)) as 0 }
Example 101
Source File: ExampleSwagger.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.example import java.util.Locale import com.twitter.finagle.http.Response import ru.tinkoff.tschema.example.Server.{getClass, modules} import ru.tinkoff.tschema.examples.SwaggerIndex import ru.tinkoff.tschema.finagle.{Rejection, Routed} import ru.tinkoff.tschema.finagle.util.message import ru.tinkoff.tschema.finagle.zioRouting.Fail.Rejected import ru.tinkoff.tschema.swagger.{OpenApiInfo, PathDescription} import zio.ZIO import zio.blocking.blocking import io.circe.syntax._ import cats.instances.list._ import cats.syntax.foldable._ import cats.syntax.semigroupk._ import io.circe.Printer object ExampleSwagger { private implicit val printer: Printer = Printer.spaces2.copy(dropNullValues = true) private val swaggerHttp: Http[Response] = { val response = message.stringResponse(SwaggerIndex.index.render) response.setContentType("text/html(UTF-8)") Routed.checkPath[Http, Response]("/swagger.php", ZIO.succeed(response)) } private def resource(name: String): Http[Response] = blocking(ZIO { val BufSize = 1024 val response = Response() val stream = getClass.getResourceAsStream(name) val arr = Array.ofDim[Byte](BufSize) def readAll(): Unit = stream.read(arr) match { case BufSize => response.write(arr) readAll() case size if size > 0 => response.write(arr.slice(0, size)) readAll() case _ => } readAll() response }).catchAll(_ => ZIO.fail(Rejected(Rejection.notFound))) private val swaggerResources: Http[Response] = Routed.path[Http].map(_.toString).flatMap { case s if s.startsWith("/webjars") => resource("/META-INF/resources" + s) case _ => Routed.reject[Http, Response](Rejection.notFound) } private val swaggerJson: Http[Response] = { val swagger = modules.foldMap(_.swag) val descriptions = PathDescription.utf8I18n("swagger", Locale.forLanguageTag("ru")) val json = swagger.describe(descriptions).make(OpenApiInfo()).asJson.pretty(printer) val response = message.jsonResponse(json) Routed.checkPath[Http, Response]("/swagger", ZIO.succeed(response)) } val route: Http[Response] = swaggerResources <+> swaggerHttp <+> swaggerJson }
Example 102
Source File: Authorize.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.example import cats.Applicative import com.twitter.finagle.http.Response import com.twitter.util.Base64StringEncoder import derevo.circe.{decoder, encoder} import derevo.derive import derevo.tethys.{tethysReader, tethysWriter} import ru.tinkoff.tschema.finagle.Authorization.{Basic, Bearer, Kind} import ru.tinkoff.tschema.finagle.{Authorization, Credentials, Rejection, Routed, SimpleAuth, BearerToken} import ru.tinkoff.tschema.swagger._ import ru.tinkoff.tschema.finagle._ import ru.tinkoff.tschema.syntax._ import shapeless.{HNil, Witness} import cats.syntax.applicative._ import ru.tinkoff.tschema.finagle.Credentials.secure_equals import ru.tinkoff.tschema.finagle.util.Unapply import scala.annotation.tailrec import ru.tinkoff.tschema.finagle.tethysInstances._ object Authorize extends ExampleModule { implicitly[Routed[Http]] override def route: Http[Response] = MkService[Http](api)(handler) override def swag: SwaggerBuilder = MkSwagger(api) final case class User(name: String, roles: List[String]) @derive(tethysWriter, tethysReader, Swagger) final case class Client(name: String, products: List[String]) val anonClient = Client("anon", List.empty) val users = Unapply( Map( "admin" -> ("adminadmin", List("admin")), "guest" -> ("guest", List()) ) ) val clients = Unapply( Map( "123456" -> Client("client", List("diamond card", "premium subscription")) ) ) val sessions = Map( "x123" -> List(1, 2, 3), "x12" -> List(1, 2), "y" -> List.empty ) implicit val userAuth: Authorization[Basic, Http, User] = SimpleAuth { case Credentials(id @ users(pass, roles), pwd) if secure_equals(pass, pwd) => User(id, roles) } implicit val clientAuth: Authorization[Bearer, Http, Client] = SimpleAuth { case BearerToken(clients(client)) => client } def api = tagPrefix("auth") |> (( operation("roles") |> basicAuth[User]("users", "user") |> get[List[String]] ) <> ( operation("client") |> bearerAuth[Option[Client]]("clients", "client") |> get[Client] ) <> ( operation("numbers") |> apiKeyAuth("sessionId", queryParam[Option[String]]("sessionId")) |> get[List[Int]] )) object handler { def roles(user: User): List[String] = user.roles def client(client: Option[Client]): Client = client.getOrElse(anonClient) def numbers(sessionId: Option[String]): List[Int] = sessionId.flatMap(sessions.get).getOrElse(List(-1)) } }
Example 103
Source File: VersionModule.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema package example import ru.tinkoff.tschema.finagle.Serve.Filter import ru.tinkoff.tschema.finagle.{Rejection, Routed, Serve} import ru.tinkoff.tschema.finagle.MkService import ru.tinkoff.tschema.param.ParamSource.Query import ru.tinkoff.tschema.swagger.{SwaggerMapper} import ru.tinkoff.tschema.swagger.MkSwagger import syntax._ import ru.tinkoff.tschema.typeDSL._ import shapeless.{HList, Witness} import cats.syntax.flatMap._ import cats.syntax.applicative._ import cats.syntax.semigroupk._ import cats.syntax.order._ import cats.instances.string._ import cats.instances.string._ import ru.tinkoff.tschema.finagle.tethysInstances._ import cats.SemigroupK import com.twitter.finagle.http.{Request, Response} import ru.tinkoff.tschema.param.Param import ru.tinkoff.tschema.common.Name import Routed.{uriParam, reject} object VersionModule extends ExampleModule { def api = tagPrefix("versioned") |> ( (version("v1") |> get[String]) <> (version("v2") |> get[Map[String, Int]]) <> (version("v2.1") |> get[Vector[String]]) ) object service { def v1 = "Ololo" def v2 = Map("Olol" -> 0) def `v2.1` = Vector("Olo", "lo") } val route = MkService[Http](api)(service) val swag = MkSwagger(api) } final class version[v] extends DSLAtom object version { def wrongVersion(shouldBe: String, passed: String) = Rejection.malformedParam("version", s"passed version $passed shouldBe: $shouldBe", Query) def apply[v <: Singleton](v: Witness.Aux[v]): version[v] :> Key[v] = new :> implicit def versionServe[v: Name, In <: HList]: Filter[version[v], Http, In] = Serve.checkCont[version[v], Http, In] { cnt => val shouldBe = Name[v].string Routed.checkPath[Http, Response](Name[v].string, cnt) <+> (uriParam[Http, String]("version").flatMap { s => reject[Http, Unit](wrongVersion(shouldBe, s)).whenA(s =!= shouldBe) } *> cnt) } implicit def versionSwagger[v: Name]: SwaggerMapper[version[v]] = SwaggerMapper[Prefix[v]].as[version[v]] }
Example 104
Source File: Server.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.example import Swagger._ import cats.effect.ExitCode import cats.effect.concurrent.Ref import cats.instances.list._ import cats.syntax.foldable._ import cats.syntax.semigroupk._ import com.twitter.finagle import finagle.{Http, http} import com.twitter.finagle.http.Response import com.twitter.util.{Await, Duration} import monix.eval.{Task, TaskApp} import ru.tinkoff.tschema.finagle.Runnable import tofu.Void object Server extends TaskApp { implicit val greeting: Greeting[Example] = Greeting[Example] val modules: List[ExampleModule] = List(GreetingModule[Example, Http](), TestModule, FiltersModule, FormFieldsModule, MultiParameters, ProxyModule, VersionModule, Authorize) val svc: Http[Response] = modules.foldMapK(_.route) <+> Swagger.route val server = for { srv <- Runnable.run[Example](svc) list <- Example.delay(finagle.Http.serve("0.0.0.0:9191", srv)) _ <- Example.delay(println(s"started at ${list.boundAddress}")) _ <- Example.delay(Await.ready(list, Duration.Top)).fork res <- Example.fromTask(Task.never[Void]) } yield res def run(args: List[String]): Task[ExitCode] = for { ref <- Ref[Task].of(0) _ <- server .onErrorHandle(ex => println(ex.getMessage)) .run(ExampleEnv("lol", ref)) } yield ExitCode.Success }
Example 105
Source File: Swagger.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.example import java.util.Locale import cats.Monad import com.twitter.finagle.http.Response import ru.tinkoff.tschema.example.Server.{getClass, modules} import ru.tinkoff.tschema.examples.SwaggerIndex import ru.tinkoff.tschema.finagle.{Rejection, Routed, RoutedPlus} import ru.tinkoff.tschema.finagle.util.message import ru.tinkoff.tschema.finagle.routing.Rejected import ru.tinkoff.tschema.swagger.{OpenApiInfo, PathDescription} import io.circe.syntax._ import cats.implicits._ import io.circe.Printer import monix.eval.Task import tofu.env.Env final case class Swagger[H[_]: RoutedPlus: Monad] { private implicit val printer: Printer = Printer.spaces2.copy(dropNullValues = true) private val swaggerHttp: H[Response] = { val response = message.stringResponse(SwaggerIndex.index.render) response.setContentType("text/html(UTF-8)") Routed.checkPath[H, Response]("/swagger.php", response.pure[H]) } private def resource(name: String): H[Response] = Env.fromTask( Task.delay { val BufSize = 1024 val response = Response() val stream = getClass.getResourceAsStream(name) val arr = Array.ofDim[Byte](BufSize) def readAll(): Unit = stream.read(arr) match { case BufSize => response.write(arr) readAll() case size if size > 0 => response.write(arr.slice(0, size)) readAll() case _ => } readAll() response }.executeOn(resources) .onErrorHandleWith(_ => Task.raiseError(Rejected(Rejection.notFound)))) private val swaggerResources: H[Response] = Routed.path[H].map(_.toString).flatMap { case s if s.startsWith("/webjars") => resource("/META-INF/resources" + s) case _ => Routed.reject[H, Response](Rejection.notFound) } private val swaggerJson: H[Response] = { val swagger = modules.foldMap(_.swag) val descriptions = PathDescription.utf8I18n("swagger", Locale.forLanguageTag("ru")) val json = swagger.describe(descriptions).make(OpenApiInfo()).asJson.pretty(printer) val response = message.jsonResponse(json) Routed.checkPath[H, Response]("/swagger", response.pure[H]) } val route: H[Response] = swaggerResources <+> swaggerHttp <+> swaggerJson }
Example 106
Source File: Authorize.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.example import cats.Applicative import com.twitter.finagle.http.Response import com.twitter.util.Base64StringEncoder import org.manatki.derevo.circeDerivation.{decoder, encoder} import org.manatki.derevo.derive import org.manatki.derevo.tethysInstances.{tethysReader, tethysWriter} import org.manatki.derevo.tschemaInstances._ import ru.tinkoff.tschema.finagle.Authorization.{Basic, Bearer, Kind} import ru.tinkoff.tschema.finagle.{Authorization, Credentials, MkService, Rejection, Routed, SimpleAuth, BearerToken} import ru.tinkoff.tschema.swagger.{SwaggerBuilder, _} import ru.tinkoff.tschema.syntax._ import shapeless.{HNil, Witness} import cats.syntax.applicative._ import ru.tinkoff.tschema.finagle.Credentials.secure_equals import ru.tinkoff.tschema.finagle.util.Unapply import scala.annotation.tailrec import ru.tinkoff.tschema.finagle.tethysInstances._ object Authorize extends ExampleModule { override def route: Http[Response] = MkService[Http](api)(handler) override def swag: SwaggerBuilder = MkSwagger(api) final case class User(name: String, roles: List[String]) @derive(tethysWriter, tethysReader, swagger) final case class Client(name: String, products: List[String]) val anonClient = Client("anon", List.empty) val users = Unapply( Map( "admin" -> ("adminadmin", List("admin")), "guest" -> ("guest", List()) )) val clients = Unapply( Map( "123456" -> Client("client", List("diamond card", "premium subscription")) )) val sessions = Map( "x123" -> List(1, 2, 3), "x12" -> List(1, 2), "y" -> List.empty ) implicit val userAuth: Authorization[Basic, Http, User] = SimpleAuth { case Credentials(id @ users(pass, roles), pwd) if secure_equals(pass, pwd) => User(id, roles) } implicit val clientAuth: Authorization[Bearer, Http, Client] = SimpleAuth { case BearerToken(clients(client)) => client } def api = tagPrefix('auth) |> (( operation('roles) |> basicAuth[User]("users", 'user) |> get[List[String]] ) <> ( operation('client) |> bearerAuth[Option[Client]]("clients", 'client) |> get[Client] ) <> ( operation('numbers) |> apiKeyAuth('sessionId, queryParam[Option[String]]('sessionId)) |> get[List[Int]] )) object handler { def roles(user: User): List[String] = user.roles def client(client: Option[Client]): Client = client.getOrElse(anonClient) def numbers(sessionId: Option[String]): List[Int] = sessionId.flatMap(sessions.get).getOrElse(List(-1)) } }
Example 107
Source File: VersionModule.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.example import ru.tinkoff.tschema.finagle.Serve.Filter import ru.tinkoff.tschema.finagle.{MkService, Rejection, Routed, Serve} import ru.tinkoff.tschema.param.ParamSource.Query import ru.tinkoff.tschema.swagger.{SwaggerMapper, _} import syntax._ import ru.tinkoff.tschema.typeDSL._ import shapeless.{HList, Witness} import cats.syntax.flatMap._ import cats.syntax.applicative._ import cats.syntax.semigroupk._ import cats.syntax.order._ import cats.instances.string._ import ru.tinkoff.tschema.common.Name import cats.instances.string._ import ru.tinkoff.tschema.finagle.tethysInstances._ import Routed.{reject, uriParam} import cats.SemigroupK import com.twitter.finagle.http.{Request, Response} import ru.tinkoff.tschema.param.Param object VersionModule extends ExampleModule { def api = tagPrefix('versioned) |> ( (version('v1) |> get[String]) <> (version('v2) |> get[Map[String, Int]]) <> (version("v2.1") |> get[Vector[String]]) ) object service { def v1 = "Ololo" def v2 = Map("Olol" -> 0) def `v2.1` = Vector("Olo", "lo") } val route = MkService[Http](api)(service) val swag = MkSwagger(api) } final class version[v] extends DSLAtom object version { def wrongVersion(shouldBe: String, passed: String) = Rejection.malformedParam("version", s"passed version $passed shouldBe: $shouldBe", Query) def apply[v](v: Witness.Aux[v]): version[v] :> Key[v] = new version[v] :> key(v) implicit def versionServe[v: Name, In <: HList]: Filter[version[v], Http, In] = Serve.checkCont[version[v], Http, In] { cnt => val shouldBe = Name[v].string Routed.checkPath[Http, Response](Name[v].string, cnt) <+> (uriParam[Http, String]("version").flatMap { s => reject[Http, Unit](wrongVersion(shouldBe, s)).whenA(s =!= shouldBe) } >> cnt) } implicit def versionSwagger[v: Name]: SwaggerMapper[version[v]] = SwaggerMapper[Prefix[v]].as[version[v]] }
Example 108
Source File: Server.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.example import cats.effect.ExitCode import cats.effect.concurrent.Ref import cats.instances.list._ import cats.syntax.foldable._ import cats.syntax.semigroupk._ import com.twitter.finagle import com.twitter.finagle.http.Response import com.twitter.util.{Await, Duration} import monix.eval.{Task, TaskApp} import ru.tinkoff.tschema.example.sample.SampleModule import ru.tinkoff.tschema.finagle.RunHttp import tofu.Void object Server extends TaskApp { def modules[H[_]]: List[ExampleModule[Http]] = List( new Greeting[Http, Example](), new SampleModule[Http, Example](), new FiltersModule(), new FormFieldsModule(), new MultiParameters(), new ProxyModule(), new VersionModule(), new Authorize ) val svc: Http[Response] = modules.foldMapK(_.route) <+> ExampleSwagger.route val server = for { srv <- RunHttp.run[Example](svc) list <- Example.delay(finagle.Http.serve("0.0.0.0:9191", srv)) _ <- Example.delay(println(s"started at ${list.boundAddress}")) _ <- Example.delay(Await.ready(list, Duration.Top)).fork res <- Example.fromTask(Task.never[Void]) } yield res def run(args: List[String]): Task[ExitCode] = for { ref <- Ref[Task].of(0) _ <- server .onErrorHandle(ex => println(ex.getMessage)) .run(ExampleEnv("lol", ref)) } yield ExitCode.Success }
Example 109
Source File: ExampleSwagger.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.example import java.util.Locale import com.twitter.finagle.http.Response import ru.tinkoff.tschema.example.Server.{getClass, modules} import ru.tinkoff.tschema.examples.SwaggerIndex import ru.tinkoff.tschema.finagle.{Rejection, Routed} import ru.tinkoff.tschema.finagle.util.message import ru.tinkoff.tschema.finagle.envRouting.Rejected import ru.tinkoff.tschema.swagger.{OpenApiInfo, PathDescription} import io.circe.syntax._ import cats.instances.list._ import cats.syntax.foldable._ import cats.syntax.semigroupk._ import io.circe.Printer import monix.eval.Task import tofu.env.Env object ExampleSwagger { private implicit val printer: Printer = Printer.spaces2.copy(dropNullValues = true) private val swaggerHttp: Http[Response] = { val response = message.stringResponse(SwaggerIndex.index.render) response.setContentType("text/html(UTF-8)") Routed.checkPath[Http, Response]("/swagger.php", Http.pure(response)) } private def resource(name: String): Http[Response] = Env.fromTask( Task.delay { val BufSize = 1024 val response = Response() val stream = getClass.getResourceAsStream(name) val arr = Array.ofDim[Byte](BufSize) def readAll(): Unit = stream.read(arr) match { case BufSize => response.write(arr) readAll() case size if size > 0 => response.write(arr.slice(0, size)) readAll() case _ => } readAll() response }.executeOn(resources) .onErrorHandleWith(_ => Task.raiseError(Rejected(Rejection.notFound)))) private val swaggerResources: Http[Response] = Routed.path[Http].map(_.toString).flatMap { case s if s.startsWith("/webjars") => resource("/META-INF/resources" + s) case _ => Routed.reject[Http, Response](Rejection.notFound) } private val swaggerJson: Http[Response] = { val swagger = modules.foldMap(_.swag) val descriptions = PathDescription.utf8I18n("swagger", Locale.forLanguageTag("ru")) val json = swagger.describe(descriptions).make(OpenApiInfo()).asJson.pretty(printer) val response = message.jsonResponse(json) Routed.checkPath[Http, Response]("/swagger", Env.pure(response)) } val route: Http[Response] = swaggerResources <+> swaggerHttp <+> swaggerJson }
Example 110
Source File: Authorize.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema.example import cats.Monad import com.twitter.finagle.http.Response import derevo.derive import derevo.tethys.{tethysReader, tethysWriter} import ru.tinkoff.tschema.custom.syntax._ import ru.tinkoff.tschema.finagle.Authorization.{Basic, Bearer} import ru.tinkoff.tschema.finagle.Credentials.secure_equals import ru.tinkoff.tschema.finagle.util.Unapply import ru.tinkoff.tschema.finagle._ import ru.tinkoff.tschema.swagger.SwaggerBuilder import ru.tinkoff.tschema.swagger._ import ru.tinkoff.tschema.syntax._ import ru.tinkoff.tschema.finagle.MkService object Authorize { final case class User(name: String, roles: List[String]) @derive(tethysWriter, tethysReader, Swagger) final case class Client(name: String, products: List[String]) val anonClient = Client("anon", List.empty) val users = Unapply( Map( "admin" -> ("adminadmin", List("admin")), "guest" -> ("guest", List()) ) ) val clients = Unapply( Map( "123456" -> Client("client", List("diamond card", "premium subscription")) ) ) val sessions = Map( "x123" -> List(1, 2, 3), "x12" -> List(1, 2), "y" -> List.empty ) def api = tagPrefix("auth") |> (( operation("roles") |> basicAuth[User]("users", "user") |> get |> json[List[String]] ) <> ( operation("client") |> bearerAuth[Option[Client]]("clients", "client") |> get |> json[Client] ) <> ( operation("numbers") |> apiKeyAuth("sessionId", queryParam[Option[String]]("sessionId")) |> get |> json[List[Int]] )) object handler { def roles(user: User): List[String] = user.roles def client(client: Option[Client]): Client = client.getOrElse(anonClient) def numbers(sessionId: Option[String]): List[Int] = sessionId.flatMap(sessions.get).getOrElse(List(-1)) } implicit def userAuth[H[_]: Monad: Routed]: Authorization[Basic, H, User] = SimpleAuth { case Credentials(id @ users(pass, roles), pwd) if secure_equals(pass, pwd) => User(id, roles) } implicit def clientAuth[H[_]: Monad: Routed]: Authorization[Bearer, H, Client] = SimpleAuth { case BearerToken(clients(client)) => client } } class Authorize[H[_]: Monad: RoutedPlus] extends ExampleModule[H] { import Authorize._ override def route: H[Response] = MkService[H](api)(handler) override def swag: SwaggerBuilder = MkSwagger(api) }
Example 111
Source File: VersionModule.scala From typed-schema with Apache License 2.0 | 5 votes |
package ru.tinkoff.tschema package example import cats.Monad import cats.instances.string._ import cats.syntax.applicative._ import cats.syntax.flatMap._ import cats.syntax.order._ import cats.syntax.semigroupk._ import com.twitter.finagle.http.Response import ru.tinkoff.tschema.finagle.Serve.Filter import ru.tinkoff.tschema.finagle.{Rejection, Routed, RoutedPlus, Serve} import ru.tinkoff.tschema.param.ParamSource.Query import ru.tinkoff.tschema.swagger.SwaggerMapper import ru.tinkoff.tschema.typeDSL._ import shapeless.{HList, Witness} import ru.tinkoff.tschema.common.Name import ru.tinkoff.tschema.custom.syntax._ import ru.tinkoff.tschema.finagle.MkService import ru.tinkoff.tschema.swagger.MkSwagger import syntax._ class VersionModule[H[_]: Monad: RoutedPlus] extends ExampleModule[H] { import VersionModule._ val route = MkService[H](api)(service) val swag = MkSwagger(api) } object VersionModule { def api = tagPrefix("versioned") |> ( (version("v1") |> get |> plain[String]) <> (version("v2") |> get |> json[Map[String, Int]]) <> (version("v2.1") |> get |> json[Vector[String]]) ) object service { def v1 = "Ololo" def v2 = Map("Olol" -> 0) def `v2.1` = Vector("Olo", "lo") } } final class version[v] extends DSLAtom object version { def wrongVersion(shouldBe: String, passed: String) = Rejection.malformedParam("version", s"passed version $passed shouldBe: $shouldBe", Query) def apply[v](v: Witness.Aux[v]): version[v] :> Key[v] = new :> implicit def versionServe[v: Name, In <: HList, H[_]: Monad: RoutedPlus]: Filter[version[v], H, In] = Serve.checkCont[version[v], H, In] { cnt => val shouldBe = Name[v].string import Routed._ Routed.checkPath[H, Response](Name[v].string, cnt) <+> (uriParam[H, String]("version").flatMap { s => reject[H, Unit](wrongVersion(shouldBe, s)).whenA(s =!= shouldBe) } >> cnt) } implicit def versionSwagger[v: Name]: SwaggerMapper[version[v]] = SwaggerMapper[Prefix[v]].as[version[v]] }
Example 112
Source File: package.scala From featherbed with Apache License 2.0 | 4 votes |
package featherbed import java.net.URL import com.twitter.finagle.{Filter, Http} import com.twitter.finagle.http.{Request, Response} import org.scalamock.matchers.Matcher import org.scalamock.scalatest.MockFactory package object fixture { private[fixture] class MockClient ( baseUrl: URL, filter: Filter[Request, Response, Request, Response] ) extends Client(baseUrl) { override def clientTransform(c: Http.Client) = c.filtered(filter) } trait ClientTest { self: MockFactory => class TransportRequestMatcher(f: Request => Unit) extends Matcher[Any] { override def canEqual(x: Any) = x match { case x: Request => true case _ => false } override def safeEquals(that: Any): Boolean = that match { case x: Request => f(x); true case _ => false } } def request(f: Request => Unit): TransportRequestMatcher = new TransportRequestMatcher(f) def mockClient(url: String, filter: Filter[Request, Response, Request, Response]): Client = new MockClient(new URL(url), filter) } }