akka.http.scaladsl.model.Uri.Query Scala Examples

The following examples show how to use akka.http.scaladsl.model.Uri.Query. 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: ClickhouseQueryBuilder.scala    From clickhouse-scala-client   with GNU Lesser General Public License v3.0 5 votes vote down vote up
package com.crobox.clickhouse.internal

import akka.http.scaladsl.model.Uri.Query
import akka.http.scaladsl.model.headers.{HttpEncodingRange, RawHeader}
import akka.http.scaladsl.model.{HttpMethods, HttpRequest, RequestEntity, Uri}
import com.crobox.clickhouse.internal.QuerySettings.ReadQueries
import com.crobox.clickhouse.internal.progress.ProgressHeadersAsEventsStage
import com.typesafe.config.Config
import com.typesafe.scalalogging.LazyLogging

import scala.collection.immutable

private[clickhouse] trait ClickhouseQueryBuilder extends LazyLogging {

  private val Headers = {
    import HttpEncodingRange.apply
    import akka.http.scaladsl.model.headers.HttpEncodings.{deflate, gzip}
    import akka.http.scaladsl.model.headers.`Accept-Encoding`
    immutable.Seq(`Accept-Encoding`(gzip, deflate))
  }
  private val MaxUriSize = 16 * 1024

  protected def toRequest(uri: Uri,
                          query: String,
                          queryIdentifier: Option[String],
                          settings: QuerySettings,
                          entity: Option[RequestEntity])(config: Config): HttpRequest = {
    val urlQuery = uri.withQuery(Query(Query("query" -> query) ++ settings.withFallback(config).asQueryParams: _*))
    entity match {
      case Some(e) =>
        logger.debug(s"Executing clickhouse query [$query] on host [${uri
          .toString()}] with entity payload of length ${e.contentLengthOption}")
        HttpRequest(
          method = HttpMethods.POST,
          uri = urlQuery,
          entity = e,
          headers = Headers ++ queryIdentifier.map(RawHeader(ProgressHeadersAsEventsStage.InternalQueryIdentifier, _))
        )
      case None
          if settings.idempotent.contains(true) && settings.readOnly == ReadQueries && urlQuery
            .toString()
            .getBytes
            .length < MaxUriSize => //max url size
        logger.debug(s"Executing clickhouse idempotent query [$query] on host [${uri.toString()}]")
        HttpRequest(
          method = HttpMethods.GET,
          uri = urlQuery.withQuery(
            urlQuery
              .query()
              .filterNot(
                _._1 == "readonly"
              ) //get requests are readonly by default, if we send the readonly flag clickhouse will fail the request
          ),
          headers = Headers ++ queryIdentifier.map(RawHeader(ProgressHeadersAsEventsStage.InternalQueryIdentifier, _))
        )
      case None =>
        logger.debug(s"Executing clickhouse query [$query] on host [${uri.toString()}]")
        HttpRequest(
          method = HttpMethods.POST,
          uri = uri.withQuery(settings.withFallback(config).asQueryParams),
          entity = query,
          headers = Headers ++ queryIdentifier.map(RawHeader(ProgressHeadersAsEventsStage.InternalQueryIdentifier, _))
        )
    }
  }

} 
Example 2
Source File: QuerySettings.scala    From clickhouse-scala-client   with GNU Lesser General Public License v3.0 5 votes vote down vote up
package com.crobox.clickhouse.internal
import akka.http.scaladsl.model.Uri.Query
import com.crobox.clickhouse.internal.QuerySettings._
import com.typesafe.config.Config

import scala.collection.JavaConverters._
import scala.util.Try

case class QuerySettings(readOnly: ReadOnlySetting = AllQueries,
                         authentication: Option[(String, String)] = None,
                         progressHeaders: Option[Boolean] = None,
                         queryId: Option[String] = None,
                         profile: Option[String] = None,
                         httpCompression: Option[Boolean] = None,
                         settings: Map[String, String] = Map.empty,
                         idempotent: Option[Boolean] = None) {

  def asQueryParams: Query =
    Query(
      settings ++ (Seq("readonly" -> readOnly.value.toString) ++
      queryId.map("query_id"      -> _) ++
      authentication.map(
        auth => "user" -> auth._1
      ) ++
      authentication.map(auth => "password" -> auth._2) ++
      profile.map("profile" -> _) ++
      progressHeaders.map(
        progress => "send_progress_in_http_headers" -> (if (progress) "1" else "0")
      ) ++
      httpCompression
        .map(compression => "enable_http_compression" -> (if (compression) "1" else "0"))).toMap
    )

  def withFallback(config: Config): QuerySettings = {
    val custom = config.getConfig(path("custom"))
    this.copy(
      authentication = authentication.orElse(Try {
        val authConfig = config.getConfig(path("authentication"))
        (authConfig.getString("user"), authConfig.getString("password"))
      }.toOption),
      profile = profile.orElse(Try { config.getString(path("profile")) }.toOption),
      httpCompression = httpCompression.orElse(Try { config.getBoolean(path("http-compression")) }.toOption),
      settings = custom.entrySet().asScala.map(u => (u.getKey, custom.getString(u.getKey))).toMap
      ++ settings
    )
  }

  private def path(setting: String) = s"settings.$setting"

}

object QuerySettings {
  sealed trait ReadOnlySetting {
    val value: Int
  }
  case object AllQueries extends ReadOnlySetting {
    override val value: Int = 0
  }
  case object ReadQueries extends ReadOnlySetting {
    override val value: Int = 1
  }
  case object ReadAndChangeQueries extends ReadOnlySetting {
    override val value: Int = 2
  }
} 
Example 3
Source File: Wsk.scala    From openwhisk   with Apache License 2.0 5 votes vote down vote up
package org.apache.openwhisk.standalone

import akka.Done
import akka.actor.ActorSystem
import akka.http.scaladsl.model.Uri.Query
import akka.http.scaladsl.model.headers.{Accept, Authorization, BasicHttpCredentials}
import akka.http.scaladsl.model.{HttpHeader, HttpMethods, MediaTypes, Uri}
import org.apache.openwhisk.core.database.PutException
import org.apache.openwhisk.http.PoolingRestClient
import spray.json._

import scala.concurrent.{ExecutionContext, Future}

class Wsk(host: String, port: Int, authKey: String)(implicit system: ActorSystem) extends DefaultJsonProtocol {
  import PoolingRestClient._
  private implicit val ec: ExecutionContext = system.dispatcher
  private val client = new PoolingRestClient("http", host, port, 10)
  private val baseHeaders: List[HttpHeader] = {
    val Array(username, password) = authKey.split(':')
    List(Authorization(BasicHttpCredentials(username, password)), Accept(MediaTypes.`application/json`))
  }

  def updatePgAction(name: String, content: String): Future[Done] = {
    val js = actionJson(name, content)
    val params = Map("overwrite" -> "true")
    val uri = Uri(s"/api/v1/namespaces/_/actions/$name").withQuery(Query(params))
    client.requestJson[JsObject](mkJsonRequest(HttpMethods.PUT, uri, js, baseHeaders)).map {
      case Right(_)     => Done
      case Left(status) => throw PutException(s"Error creating action $name " + status)
    }
  }

  private def actionJson(name: String, code: String) = {
    s"""{
      |    "namespace": "_",
      |    "name": "$name",
      |    "exec": {
      |        "kind": "nodejs:default",
      |        "code": ${quote(code)}
      |    },
      |    "annotations": [{
      |        "key": "provide-api-key",
      |        "value": true
      |    }, {
      |        "key": "web-export",
      |        "value": true
      |    }, {
      |        "key": "raw-http",
      |        "value": false
      |    }, {
      |        "key": "final",
      |        "value": true
      |    }],
      |    "parameters": [{
      |        "key": "__ignore_certs",
      |        "value": true
      |    }]
      |}""".stripMargin.parseJson.asJsObject
  }

  private def quote(code: String) = {
    JsString(code).compactPrint
  }
} 
Example 4
Source File: request.scala    From wix-http-testkit   with MIT License 5 votes vote down vote up
package com.wix.e2e.http.client.transformers.internals

import java.io.File

import akka.http.scaladsl.model.Uri.Query
import akka.http.scaladsl.model._
import akka.http.scaladsl.model.headers.{Cookie, RawHeader, `User-Agent`}
import akka.util.ByteString
import com.wix.e2e.http.api.Marshaller
import com.wix.e2e.http.client.transformers._
import com.wix.e2e.http.client.transformers.internals.RequestPartOps._
import com.wix.e2e.http.exceptions.UserAgentModificationNotSupportedException
import com.wix.e2e.http.{RequestTransformer, WixHttpTestkitResources}

import scala.xml.Node

trait HttpClientRequestUrlTransformers {
  def withParam(param: (String, String)): RequestTransformer = withParams(param)
  def withParams(params: (String, String)*): RequestTransformer = r =>
    r.copy(uri = r.uri
                  .withQuery( Query(currentParams(r) ++ params: _*)) )

  private def currentParams(r: HttpRequest): Seq[(String, String)] =
    r.uri.rawQueryString
     .map( Query(_).toSeq )
     .getOrElse( Seq.empty )
}

trait HttpClientRequestHeadersTransformers {
  def withHeader(header: (String, String)): RequestTransformer = withHeaders(header)
  def withHeaders(headers: (String, String)*): RequestTransformer =
    appendHeaders( headers.map {
      case (h, _) if h.toLowerCase == "user-agent" => throw new UserAgentModificationNotSupportedException
      case (h, v) => RawHeader(h, v)
    } )

  def withUserAgent(value: String): RequestTransformer = appendHeaders(Seq(`User-Agent`(value)))

  def withCookie(cookie: (String, String)): RequestTransformer = withCookies(cookie)
  def withCookies(cookies: (String, String)*): RequestTransformer = appendHeaders( cookies.map(p => Cookie(p._1, p._2)) )


  private def appendHeaders[H <: HttpHeader](headers: Iterable[H]): RequestTransformer = r =>
    r.withHeaders( r.headers ++ headers)
}

trait HttpClientRequestBodyTransformers extends HttpClientContentTypes {
  @deprecated("use `withTextPayload`", since = "Dec18, 2017")
  def withPayload(body: String, contentType: ContentType = TextPlain): RequestTransformer = withPayload(ByteString(body).toByteBuffer.array, contentType)
  def withTextPayload(body: String, contentType: ContentType = TextPlain): RequestTransformer = withPayload(ByteString(body).toByteBuffer.array, contentType)
  def withPayload(bytes: Array[Byte], contentType: ContentType): RequestTransformer = setBody(HttpEntity(contentType, bytes))
  def withPayload(xml: Node): RequestTransformer = setBody(HttpEntity(XmlContent, WixHttpTestkitResources.xmlPrinter.format(xml)))

  // todo: enable default marshaller when deprecated `withPayload` is removed
  def withPayload(entity: AnyRef)(implicit marshaller: Marshaller): RequestTransformer =
    withTextPayload(marshaller.marshall(entity), JsonContent)

  def withFormData(formParams: (String, String)*): RequestTransformer = setBody(FormData(formParams.toMap).toEntity)

  def withMultipartData(parts: (String, RequestPart)*): RequestTransformer =
    setBody( Multipart.FormData(parts.map {
      case (n, p) => Multipart.FormData.BodyPart(n, p.asBodyPartEntity, p.withAdditionalParams)
    }:_*)
      .toEntity)

  private def setBody(entity: RequestEntity): RequestTransformer = _.copy(entity = entity)
}

object RequestPartOps {

      implicit class `RequestPart --> HttpEntity`(private val r: RequestPart) extends AnyVal {
        def asBodyPartEntity: BodyPartEntity = r match {
          case PlainRequestPart(v, c) => HttpEntity(v).withContentType(c)
          case BinaryRequestPart(b, c, _) => HttpEntity(c, b)
          case FileRequestPart(f, c, _) => HttpEntity.fromPath(c, f.toPath)
          case FileNameRequestPart(p, c, fn) => FileRequestPart(new File(p), c, fn).asBodyPartEntity
        }
      }

      implicit class `RequestPart --> AdditionalParams`(private val r: RequestPart) extends AnyVal {
        def withAdditionalParams: Map[String, String] = r match {
          case _: PlainRequestPart => NoAdditionalParams
          case BinaryRequestPart(_, _, fn) => additionalParams(fn)
          case FileRequestPart(_, _, fn) => additionalParams(fn)
          case FileNameRequestPart(_, _, fn) => additionalParams(fn)
        }

        private def additionalParams(filenameOpt: Option[String]) =
          filenameOpt.map(fn => Map("filename" -> fn))
                     .getOrElse( NoAdditionalParams )

        private def NoAdditionalParams = Map.empty[String, String]
      }
}


trait HttpClientRequestTransformersOps  {
  implicit class TransformerConcatenation(first: RequestTransformer) {
    def and(second: RequestTransformer): RequestTransformer = first andThen second
  }
} 
Example 5
Source File: LmgtfyBot.scala    From telegram   with Apache License 2.0 5 votes vote down vote up
import akka.http.scaladsl.model.Uri
import akka.http.scaladsl.model.Uri.Query
import cats.instances.future._
import cats.syntax.functor._
import com.bot4s.telegram.Implicits._
import com.bot4s.telegram.api.declarative.{Commands, InlineQueries}
import com.bot4s.telegram.future.Polling
import com.bot4s.telegram.methods.ParseMode
import com.bot4s.telegram.models._

import scala.concurrent.Future


class LmgtfyBot(token: String) extends ExampleBot(token)
  with Polling
  with InlineQueries[Future]
  with Commands[Future] {

  def lmgtfyBtn(query: String): InlineKeyboardMarkup = InlineKeyboardMarkup.singleButton(
    InlineKeyboardButton.url("\uD83C\uDDECoogle it now!", lmgtfyUrl(query)))

  onCommand('start | 'help) { implicit msg =>
    reply(
      s"""Generates ${"Let me \uD83C\uDDECoogle that for you!".italic} links.
         |
         |/start | /help - list commands
         |
         |/lmgtfy args - generate link
         |
         |/lmgtfy2 | /btn args - clickable button
         |
         |@Bot args - Inline mode
      """.stripMargin,
      parseMode = ParseMode.Markdown).void
  }

  onCommand('lmgtfy) { implicit msg =>
    withArgs { args =>
      val query = args.mkString(" ")

      replyMd(
        query.altWithUrl(lmgtfyUrl(query)),
        disableWebPagePreview = true
      ).void
    }
  }

  def lmgtfyUrl(query: String): String =
    Uri("http://lmgtfy.com")
      .withQuery(Query("q" -> query))
      .toString()

  onCommand('btn | 'lmgtfy2) { implicit msg =>
    withArgs { args =>
      val query = args.mkString(" ")
      reply(query, replyMarkup = lmgtfyBtn(query)).void
    }
  }

  onInlineQuery { implicit iq =>
    val query = iq.query

    if (query.isEmpty)
      answerInlineQuery(Seq()).void
    else {

      val textMessage = InputTextMessageContent(
        query.altWithUrl(lmgtfyUrl(query)),
        disableWebPagePreview = true,
        parseMode = ParseMode.Markdown)

      val results = List(
        InlineQueryResultArticle(
          "btn:" + query,
          inputMessageContent = textMessage,
          title = iq.query,
          description = "Clickable button + link",
          replyMarkup = lmgtfyBtn(query)
        ),
        InlineQueryResultArticle(
          query,
          inputMessageContent = textMessage,
          description = "Clickable link",
          title = iq.query
        )
      )

      answerInlineQuery(results, cacheTime = 1).void
    }
  }
} 
Example 6
Source File: GitHubHosted2048Bot.scala    From telegram   with Apache License 2.0 5 votes vote down vote up
import akka.http.scaladsl.model.Uri
import akka.http.scaladsl.model.Uri.{Path, Query}
import akka.http.scaladsl.model.headers.{HttpOrigin, HttpOriginRange}

import ch.megard.akka.http.cors.scaladsl.model.{HttpHeaderRange, HttpOriginMatcher}

import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import cats.instances.future._
import cats.syntax.functor._
import ch.megard.akka.http.cors.scaladsl.CorsDirectives.cors
import ch.megard.akka.http.cors.scaladsl.settings.CorsSettings
import com.bot4s.telegram.api.declarative.{Callbacks, Commands}
import com.bot4s.telegram.api.{GameManager, Payload}
import com.bot4s.telegram.future.Polling
import com.bot4s.telegram.methods.SendGame

import scala.concurrent.Future


class GitHubHosted2048Bot(token: String, gameManagerHost: String)
  extends AkkaExampleBot(token)
    with Polling
    with Commands[Future]
    with Callbacks[Future]
    with GameManager {

  override val port: Int = 8080

  val Play2048 = "play_2048"
  val GitHubPages = Uri("https://mukel.github.io")

  onCommand(Play2048 or "2048" or "start") { implicit msg =>
    request(
      SendGame(msg.source, Play2048)
    ).void
  }

  onCallbackQuery { implicit cbq =>
    val acked = cbq.gameShortName.collect {
      case Play2048 =>
        val payload = Payload.forCallbackQuery(gameManagerHost)

        val url = GitHubPages
          .withPath(Path(s"/$Play2048/index.html"))
          .withQuery(Query("payload" -> payload.base64Encode))

        ackCallback(url = Some(url.toString()))
    }

    acked.getOrElse(ackCallback()).void
  }

  // Enable CORS for GitHub Pages.
  // Allows GitHub Pages to call cross-domain getScores and setScore.
  private val allowGitHub = CorsSettings.defaultSettings
    .withAllowedOrigins(HttpOriginMatcher(HttpOrigin(GitHubPages.toString())))

  override def routes: Route =
    super.routes ~
      cors(allowGitHub) {
        gameManagerRoute
      }
} 
Example 7
Source File: SelfHosted2048Bot.scala    From telegram   with Apache License 2.0 5 votes vote down vote up
import akka.http.scaladsl.model.Uri
import akka.http.scaladsl.model.Uri.{Path, Query}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import cats.instances.future._
import cats.syntax.functor._
import com.bot4s.telegram.api.declarative.{Callbacks, Commands}
import com.bot4s.telegram.api.{AkkaDefaults, GameManager, Payload}
import com.bot4s.telegram.future.Polling
import com.bot4s.telegram.methods.SendGame

import scala.concurrent.Future


class SelfHosted2048Bot(token: String, gameManagerHost: String)
  extends ExampleBot(token)
    with Polling
    with AkkaDefaults
    with Callbacks[Future]
    with GameManager
    with Commands[Future] {

  override val port: Int = 8080

  val Play2048 = "play_2048"

  onCommand(Play2048 or "2048" or "start") { implicit msg =>
    request(
      SendGame(msg.source, Play2048)
    ).void
  }

  onCallbackQuery { implicit cbq =>
    val acked = cbq.gameShortName.collect {
      case Play2048 =>
        val payload = Payload.forCallbackQuery(gameManagerHost)

        val url = Uri(gameManagerHost)
          .withPath(Path(s"/$Play2048/index.html"))
          .withQuery(Query("payload" -> payload.base64Encode))

        ackCallback(url = Some(url.toString()))
    }

    acked.getOrElse(ackCallback()).void
  }

  override def routes: Route =
    super.routes ~
      gameManagerRoute ~ {
      pathPrefix(Play2048) {
        getFromResourceDirectory(Play2048)
      }
    }
} 
Example 8
Source File: OAuth2Routes.scala    From scastie   with Apache License 2.0 5 votes vote down vote up
package com.olegych.scastie
package web
package routes

import oauth2._

import com.softwaremill.session.SessionDirectives._
import com.softwaremill.session.SessionOptions._
import com.softwaremill.session.CsrfDirectives._
import com.softwaremill.session.CsrfOptions._

import akka.http.scaladsl.model._
import akka.http.scaladsl.model.Uri.Query
import akka.http.scaladsl.model.StatusCodes.TemporaryRedirect
import akka.http.scaladsl.model.headers.Referer
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route

import scala.concurrent.ExecutionContext

class OAuth2Routes(github: Github, session: GithubUserSession)(
    implicit val executionContext: ExecutionContext
) {
  import session._

  val routes: Route =
    get(
      concat(
        path("login") {
          parameter("home".?)(
            home =>
              optionalHeaderValueByType[Referer](()) { referrer =>
                redirect(
                  Uri("https://github.com/login/oauth/authorize").withQuery(
                    Query(
                      "client_id" -> github.clientId,
                      "state" -> {
                        val homeUri = "/"
                        if (home.isDefined) homeUri
                        else referrer.map(_.value).getOrElse(homeUri)
                      }
                    )
                  ),
                  TemporaryRedirect
                )
            }
          )
        },
        path("logout") {
          headerValueByType[Referer](()) { referrer =>
            requiredSession(refreshable, usingCookies) { _ =>
              invalidateSession(refreshable, usingCookies) { ctx =>
                ctx.complete(
                  HttpResponse(
                    status = TemporaryRedirect,
                    headers = headers.Location(Uri(referrer.value)) :: Nil,
                    entity = HttpEntity.Empty
                  )
                )
              }
            }
          }
        },
        pathPrefix("callback") {
          pathEnd {
            parameters(("code", "state".?)) { (code, state) =>
              onSuccess(github.getUserWithOauth2(code)) { user =>
                setSession(refreshable, usingCookies, session.addUser(user)) {
                  setNewCsrfToken(checkHeader) { ctx =>
                    ctx.complete(
                      HttpResponse(
                        status = TemporaryRedirect,
                        headers = headers
                          .Location(Uri(state.getOrElse("/"))) :: Nil,
                        entity = HttpEntity.Empty
                      )
                    )
                  }
                }
              }
            }
          }
        }
      )
    )
} 
Example 9
Source File: QueryResultEncoder.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.kg.search

import akka.http.scaladsl.model.Uri
import akka.http.scaladsl.model.Uri.Query
import ch.epfl.bluebrain.nexus.commons.search.QueryResult.{ScoredQueryResult, UnscoredQueryResult}
import ch.epfl.bluebrain.nexus.commons.search.QueryResults.{ScoredQueryResults, UnscoredQueryResults}
import ch.epfl.bluebrain.nexus.commons.search.{FromPagination, QueryResult, QueryResults}
import ch.epfl.bluebrain.nexus.kg.config.Contexts.{resourceCtxUri, searchCtxUri}
import ch.epfl.bluebrain.nexus.kg.directives.QueryDirectives.{after, from, size}
import ch.epfl.bluebrain.nexus.kg.indexing.SparqlLink
import ch.epfl.bluebrain.nexus.rdf.implicits._
import ch.epfl.bluebrain.nexus.service.config.ServiceConfig.HttpConfig
import ch.epfl.bluebrain.nexus.service.config.Vocabulary.nxv
import io.circe.syntax._
import io.circe.{Encoder, Json}
trait LowPriorityQueryResultsEncoder {

  implicit def qrsEncoderLowPrio[A: Encoder]: Encoder[QueryResults[A]] =
    Encoder.instance(qrsEncoderJsonLinks[A](None).apply(_))

  implicit private val uriEncoder: Encoder[Uri] = Encoder.encodeString.contramap(_.toString)

  protected def qrsEncoderJsonLinks[A: Encoder](next: Option[Uri]): Encoder[QueryResults[A]] = {
    implicit def qrEncoderJson: Encoder[QueryResult[A]]     =
      Encoder.instance {
        case UnscoredQueryResult(v)      => v.asJson.removeKeys(nxv.original_source.prefix)
        case ScoredQueryResult(score, v) =>
          v.asJson.removeKeys(nxv.original_source.prefix) deepMerge
            Json.obj(nxv.score.prefix -> Json.fromFloatOrNull(score))
      }
    def json(total: Long, list: List[QueryResult[A]]): Json =
      Json
        .obj(nxv.total.prefix -> Json.fromLong(total), nxv.results.prefix -> Json.arr(list.map(qrEncoderJson(_)): _*))
        .addContext(searchCtxUri)
        .addContext(resourceCtxUri)

    Encoder.instance {
      case UnscoredQueryResults(total, list, _)         =>
        json(total, list) deepMerge Json.obj(nxv.next.prefix -> next.asJson)
      case ScoredQueryResults(total, maxScore, list, _) =>
        json(total, list) deepMerge
          Json.obj(nxv.maxScore.prefix -> maxScore.asJson, nxv.next.prefix -> next.asJson)
    }
  }
}

object QueryResultEncoder extends LowPriorityQueryResultsEncoder {

  implicit def qrsEncoderJson(implicit searchUri: Uri, http: HttpConfig): Encoder[QueryResults[Json]] =
    Encoder.instance { results =>
      val nextLink = results.token.flatMap(next(searchUri, _))
      qrsEncoderJsonLinks[Json](nextLink).apply(results)
    }

  implicit def qrsEncoderJson(implicit
      searchUri: Uri,
      pagination: FromPagination,
      http: HttpConfig
  ): Encoder[QueryResults[SparqlLink]] =
    Encoder.instance { results =>
      val nextLink = next(searchUri, results.total, pagination)
      qrsEncoderJsonLinks[SparqlLink](nextLink).apply(results)
    }

  private def next(current: Uri, total: Long, pagination: FromPagination)(implicit http: HttpConfig): Option[Uri] = {
    val nextFrom = pagination.from + pagination.size
    if (nextFrom < total.toInt) {
      val params = current.query().toMap + (from -> nextFrom.toString) + (size -> pagination.size.toString)
      Some(toPublic(current).withQuery(Query(params)))
    } else None
  }

  private def next(current: Uri, afterToken: String)(implicit http: HttpConfig): Option[Uri] =
    current.query().get(after) match {
      case Some(`afterToken`) => None
      case _                  =>
        val params = current.query().toMap + (after -> afterToken) - from
        Some(toPublic(current).withQuery(Query(params)))
    }

  private def toPublic(uri: Uri)(implicit http: HttpConfig): Uri =
    uri.copy(scheme = http.publicUri.scheme, authority = http.publicUri.authority)
} 
Example 10
Source File: QueryResultEncoderSpec.scala    From nexus   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.kg.search

import java.time.Instant
import java.util.regex.Pattern.quote

import akka.http.scaladsl.model.Uri
import akka.http.scaladsl.model.Uri.Query
import ch.epfl.bluebrain.nexus.commons.circe.syntax._
import ch.epfl.bluebrain.nexus.commons.search.QueryResult.{ScoredQueryResult, UnscoredQueryResult}
import ch.epfl.bluebrain.nexus.commons.search.QueryResults
import ch.epfl.bluebrain.nexus.commons.search.QueryResults.{ScoredQueryResults, UnscoredQueryResults}
import ch.epfl.bluebrain.nexus.commons.test.{Randomness, Resources}
import ch.epfl.bluebrain.nexus.kg.search.QueryResultEncoder._
import ch.epfl.bluebrain.nexus.rdf.Iri.AbsoluteIri
import ch.epfl.bluebrain.nexus.rdf.implicits._
import ch.epfl.bluebrain.nexus.service.config.ServiceConfig
import ch.epfl.bluebrain.nexus.service.config.ServiceConfig.HttpConfig
import io.circe.Json
import io.circe.syntax._
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpecLike

class QueryResultEncoderSpec extends AnyWordSpecLike with Matchers with Resources with Randomness {

  implicit val orderedKeys = ServiceConfig.orderedKeys
  val org                  = genString()
  val proj                 = genString()
  val schema               = genString()
  val now                  = Instant.now()
  implicit val http        = HttpConfig("", 0, "v1", "http://nexus.com")
  implicit val uri         = Uri(s"http://nexus.com/resources/$org/$proj/$schema?type=someType&from=10&size=10")
  val before               = now.minusSeconds(60)

  "QueryResultsEncoder" should {
    def json(id: AbsoluteIri, createdAt: Instant): Json =
      jsonContentOf(
        "/resources/es-metadata.json",
        Map(
          quote("{id}")      -> id.asString,
          quote("{org}")     -> org,
          quote("{proj}")    -> proj,
          quote("{schema}")  -> schema,
          quote("{instant}") -> createdAt.toString
        )
      ) deepMerge Json.obj("_original_source" -> Json.fromString(Json.obj("k" -> Json.fromInt(1)).noSpaces))

    "encode ScoredQueryResults" in {
      val results: QueryResults[Json] = ScoredQueryResults[Json](
        3,
        0.3f,
        List(
          ScoredQueryResult(0.3f, json(url"http://nexus.com/result1", before)),
          ScoredQueryResult(0.2f, json(url"http://nexus.com/result2", before)),
          ScoredQueryResult(0.1f, json(url"http://nexus.com/result3", now))
        ),
        sort(now)
      )

      results.asJson.sortKeys shouldEqual jsonContentOf(
        "/search/scored-query-results.json",
        Map(
          quote("{org}")                -> org,
          quote("{proj}")               -> proj,
          quote("{schema}")             -> schema,
          quote("{before}")             -> before.toString,
          quote("{lastElementCreated}") -> now.toString,
          quote("{after}")              -> after(now)
        )
      )
    }
    "encode UnscoredQueryResults" in {
      val results: QueryResults[Json] = UnscoredQueryResults[Json](
        3,
        List(
          UnscoredQueryResult(json(url"http://nexus.com/result1", before)),
          UnscoredQueryResult(json(url"http://nexus.com/result2", before)),
          UnscoredQueryResult(json(url"http://nexus.com/result3", now))
        ),
        sort(now)
      )

      results.asJson.sortKeys shouldEqual jsonContentOf(
        "/search/unscored-query-results.json",
        Map(
          quote("{org}")                -> org,
          quote("{proj}")               -> proj,
          quote("{schema}")             -> schema,
          quote("{before}")             -> before.toString,
          quote("{lastElementCreated}") -> now.toString,
          quote("{after}")              -> after(now)
        )
      )

    }
  }

  private def sort(instant: Instant): Option[String] = Some(Json.arr(Json.fromString(instant.toString)).noSpaces)
  private def after(instant: Instant): String        =
    Query("after" -> List(Json.fromString(instant.toString)).asJson.noSpaces).toString()

} 
Example 11
Source File: PublicApi.scala    From affinity   with Apache License 2.0 5 votes vote down vote up
import akka.http.scaladsl.model.HttpMethods._
import akka.http.scaladsl.model.HttpResponse
import akka.http.scaladsl.model.StatusCodes._
import akka.http.scaladsl.model.Uri.{Path, Query}
import io.amient.affinity.avro.record.AvroRecord
import io.amient.affinity.core.actor.GatewayHttp
import io.amient.affinity.core.http.Encoder
import io.amient.affinity.core.http.RequestMatchers.{HTTP, PATH}
import io.amient.affinity.core.state.KVStore

import scala.concurrent.Promise

case class ProtectedProfile(hello: String = "world") extends AvroRecord

trait PublicApi extends GatewayHttp {

  private val settings: KVStore[String, ConfigEntry] = global[String, ConfigEntry]("settings")

  abstract override def handle: Receive = super.handle orElse {

    case HTTP(GET, uri@PATH("profile", _), query, response) => AUTH_DSA(uri, query, response) { (sig: String) =>
      Encoder.json(OK, Map(
        "signature" -> sig,
        "profile" -> ProtectedProfile()
      ))
    }

    case HTTP(GET, uri@PATH("verify"), query, response) => AUTH_DSA(uri, query, response) { _ =>
      Encoder.json(OK, Some(ProtectedProfile()))
    }

  }

  
  object AUTH_DSA {

    def apply(path: Path, query: Query, response: Promise[HttpResponse])(code: (String) => HttpResponse): Unit = {
      try {
        query.get("signature") match {
          case None => throw new IllegalAccessError
          case Some(sig) =>
            sig.split(":") match {
              case Array(k, clientSignature) =>
                settings(k) match {
                  case None => throw new IllegalAccessError(s"Invalid api key $k")
                  case Some(configEntry) =>
                    if (configEntry.crypto.verify(clientSignature, path.toString)) {
                      val serverSignature = configEntry.crypto.sign(clientSignature)
                      response.success(code(serverSignature))
                    } else {
                      throw new IllegalAccessError(configEntry.crypto.sign(path.toString))
                    }
                }

              case _ => throw new IllegalAccessError
            }
        }
      } catch {
        case _: IllegalAccessError => response.success(Encoder.json(Unauthorized, "Unauthorized"))
        case e: Throwable => response.success(handleException(headers = List())(e))
      }
    }
  }

} 
Example 12
Source File: AkkaHttpClient.scala    From graphql-gateway   with Apache License 2.0 5 votes vote down vote up
package sangria.gateway.http.client

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.HttpHeader.ParsingResult
import akka.http.scaladsl.model._
import akka.http.scaladsl.model.Uri.Query
import akka.http.scaladsl.model.headers.Location
import akka.http.scaladsl.unmarshalling.Unmarshal
import akka.stream.Materializer
import akka.util.ByteString
import sangria.gateway.util.Logging

import scala.concurrent.{ExecutionContext, Future}

class AkkaHttpClient(implicit system: ActorSystem, mat: Materializer, ec: ExecutionContext) extends HttpClient with Logging {
  import AkkaHttpClient._
  import HttpClient._

  override def request(method: Method.Value, url: String, queryParams: Seq[(String, String)] = Seq.empty, headers: Seq[(String, String)] = Seq.empty, body: Option[(String, String)] = None) = {
    val m = mapMethod(method)
    val query = Query(queryParams: _*)
    val hs = headers.map(header)
    val uri = Uri(url).withQuery(query)
    val entity = body.fold(HttpEntity.Empty){case (tpe, content) ⇒ HttpEntity(contentType(tpe), ByteString(content))}
    val request = HttpRequest(m, uri, hs.toVector, entity)
    val client = Http().singleRequest(_: HttpRequest)
    val richClient = RichHttpClient.httpClientWithRedirect(client)

    logger.debug(s"Http request: ${m.value} $url")

    richClient(request).map(AkkaHttpResponse(m, url, _))
  }

  override def oauthClientCredentials(url: String, clientId: String, clientSecret: String, scopes: Seq[String]): Future[HttpResponse] =
    throw new IllegalStateException("Not yet implemented, please use play implementation.")

  private def contentType(str: String) = ContentType.parse(str).fold(
    errors ⇒ throw ClientError(s"Invalid content type '$str'", errors.map(_.detail)),
    identity)

  private def header(nameValue: (String, String)) = HttpHeader.parse(nameValue._1, nameValue._2) match {
    case ParsingResult.Ok(_, errors) if errors.nonEmpty ⇒ throw ClientError(s"Invalid header '${nameValue._1}'", errors.map(_.detail))
    case ParsingResult.Error(error) ⇒ throw ClientError(s"Invalid header '${nameValue._1}'", Seq(error.detail))
    case ParsingResult.Ok(h, _) ⇒ h
  }

  def mapMethod(method: Method.Value) = method match {
    case Method.Get ⇒ HttpMethods.GET
    case Method.Post ⇒ HttpMethods.POST
  }

  object RichHttpClient {
    import akka.http.scaladsl.model.HttpResponse
    type HttpClient = HttpRequest ⇒ Future[HttpResponse]

    def redirectOrResult(client: HttpClient)(response: HttpResponse): Future[HttpResponse] =
      response.status match {
        case StatusCodes.Found | StatusCodes.MovedPermanently | StatusCodes.SeeOther ⇒
          val newUri = response.header[Location].get.uri
          // Always make sure you consume the response entity streams (of type Source[ByteString,Unit]) by for example connecting it to a Sink (for example response.discardEntityBytes() if you don’t care about the response entity), since otherwise Akka HTTP (and the underlying Streams infrastructure) will understand the lack of entity consumption as a back-pressure signal and stop reading from the underlying TCP connection!
          response.discardEntityBytes()

          logger.debug(s"Http redirect: ${HttpMethods.GET.value} $newUri")

          client(HttpRequest(method = HttpMethods.GET, uri = newUri))

        case _ ⇒ Future.successful(response)
      }

    def httpClientWithRedirect(client: HttpClient): HttpClient = {
      lazy val redirectingClient: HttpClient =
        req ⇒ client(req).flatMap(redirectOrResult(redirectingClient)) // recurse to support multiple redirects

      redirectingClient
    }
  }

  case class ClientError(message: String, errors: Seq[String]) extends Exception(message + ":\n" + errors.map("  * "  + _).mkString("\n"))
}

object AkkaHttpClient {
  case class AkkaHttpResponse(method: HttpMethod, url: String, response: HttpResponse)(implicit mat: Materializer) extends HttpClient.HttpResponse {
    def asString = Unmarshal(response).to[String]
    def statusCode = response.status.intValue()
    def isSuccessful = response.status.isSuccess()
    def debugInfo = s"${method.value} $url"
  }
} 
Example 13
Source File: QueryResultEncoder.scala    From nexus-kg   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.kg.search

import akka.http.scaladsl.model.Uri
import akka.http.scaladsl.model.Uri.Query
import ch.epfl.bluebrain.nexus.commons.search.QueryResult.{ScoredQueryResult, UnscoredQueryResult}
import ch.epfl.bluebrain.nexus.commons.search.QueryResults.{ScoredQueryResults, UnscoredQueryResults}
import ch.epfl.bluebrain.nexus.commons.search.{FromPagination, QueryResult, QueryResults}
import ch.epfl.bluebrain.nexus.kg.config.AppConfig.HttpConfig
import ch.epfl.bluebrain.nexus.kg.config.Contexts.{resourceCtxUri, searchCtxUri}
import ch.epfl.bluebrain.nexus.kg.config.Vocabulary.nxv
import ch.epfl.bluebrain.nexus.kg.directives.QueryDirectives.{after, from, size}
import ch.epfl.bluebrain.nexus.kg.indexing.SparqlLink
import ch.epfl.bluebrain.nexus.rdf.implicits._
import io.circe.syntax._
import io.circe.{Encoder, Json}
trait LowPriorityQueryResultsEncoder {

  implicit def qrsEncoderLowPrio[A: Encoder]: Encoder[QueryResults[A]] =
    Encoder.instance(qrsEncoderJsonLinks[A](None).apply(_))

  private implicit val uriEncoder: Encoder[Uri] = Encoder.encodeString.contramap(_.toString)

  protected def qrsEncoderJsonLinks[A: Encoder](next: Option[Uri]): Encoder[QueryResults[A]] = {
    implicit def qrEncoderJson: Encoder[QueryResult[A]] = Encoder.instance {
      case UnscoredQueryResult(v) => v.asJson.removeKeys(nxv.original_source.prefix)
      case ScoredQueryResult(score, v) =>
        v.asJson.removeKeys(nxv.original_source.prefix) deepMerge
          Json.obj(nxv.score.prefix -> Json.fromFloatOrNull(score))
    }
    def json(total: Long, list: List[QueryResult[A]]): Json =
      Json
        .obj(nxv.total.prefix -> Json.fromLong(total), nxv.results.prefix -> Json.arr(list.map(qrEncoderJson(_)): _*))
        .addContext(searchCtxUri)
        .addContext(resourceCtxUri)

    Encoder.instance {
      case UnscoredQueryResults(total, list, _) =>
        json(total, list) deepMerge Json.obj(nxv.next.prefix -> next.asJson)
      case ScoredQueryResults(total, maxScore, list, _) =>
        json(total, list) deepMerge
          Json.obj(nxv.maxScore.prefix -> maxScore.asJson, nxv.next.prefix -> next.asJson)
    }
  }
}

object QueryResultEncoder extends LowPriorityQueryResultsEncoder {

  implicit def qrsEncoderJson(implicit searchUri: Uri, http: HttpConfig): Encoder[QueryResults[Json]] =
    Encoder.instance { results =>
      val nextLink = results.token.flatMap(next(searchUri, _))
      qrsEncoderJsonLinks[Json](nextLink).apply(results)
    }

  implicit def qrsEncoderJson(
      implicit searchUri: Uri,
      pagination: FromPagination,
      http: HttpConfig
  ): Encoder[QueryResults[SparqlLink]] =
    Encoder.instance { results =>
      val nextLink = next(searchUri, results.total, pagination)
      qrsEncoderJsonLinks[SparqlLink](nextLink).apply(results)
    }

  private def next(current: Uri, total: Long, pagination: FromPagination)(implicit http: HttpConfig): Option[Uri] = {
    val nextFrom = pagination.from + pagination.size
    if (nextFrom < total.toInt) {
      val params = current.query().toMap + (from -> nextFrom.toString) + (size -> pagination.size.toString)
      Some(toPublic(current).withQuery(Query(params)))
    } else None
  }

  private def next(current: Uri, afterToken: String)(implicit http: HttpConfig): Option[Uri] =
    current.query().get(after) match {
      case Some(`afterToken`) => None
      case _ =>
        val params = current.query().toMap + (after -> afterToken) - from
        Some(toPublic(current).withQuery(Query(params)))
    }

  private def toPublic(uri: Uri)(implicit http: HttpConfig): Uri =
    uri.copy(scheme = http.publicUri.scheme, authority = http.publicUri.authority)
} 
Example 14
Source File: QueryResultEncoderSpec.scala    From nexus-kg   with Apache License 2.0 5 votes vote down vote up
package ch.epfl.bluebrain.nexus.kg.search

import java.time.Instant
import java.util.regex.Pattern.quote

import akka.http.scaladsl.model.Uri
import akka.http.scaladsl.model.Uri.Query
import ch.epfl.bluebrain.nexus.commons.circe.syntax._
import ch.epfl.bluebrain.nexus.commons.search.QueryResult.{ScoredQueryResult, UnscoredQueryResult}
import ch.epfl.bluebrain.nexus.commons.search.QueryResults
import ch.epfl.bluebrain.nexus.commons.search.QueryResults.{ScoredQueryResults, UnscoredQueryResults}
import ch.epfl.bluebrain.nexus.commons.test.{Randomness, Resources}
import ch.epfl.bluebrain.nexus.kg.config.AppConfig
import ch.epfl.bluebrain.nexus.kg.config.AppConfig.HttpConfig
import ch.epfl.bluebrain.nexus.kg.search.QueryResultEncoder._
import ch.epfl.bluebrain.nexus.rdf.Iri.AbsoluteIri
import ch.epfl.bluebrain.nexus.rdf.implicits._
import io.circe.Json
import io.circe.syntax._
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpecLike

class QueryResultEncoderSpec extends AnyWordSpecLike with Matchers with Resources with Randomness {

  implicit val orderedKeys = AppConfig.orderedKeys
  val org                  = genString()
  val proj                 = genString()
  val schema               = genString()
  val now                  = Instant.now()
  implicit val http        = HttpConfig("", 0, "v1", "http://nexus.com")
  implicit val uri         = Uri(s"http://nexus.com/resources/$org/$proj/$schema?type=someType&from=10&size=10")
  val before               = now.minusSeconds(60)

  "QueryResultsEncoder" should {
    def json(id: AbsoluteIri, createdAt: Instant): Json =
      jsonContentOf(
        "/resources/es-metadata.json",
        Map(
          quote("{id}")      -> id.asString,
          quote("{org}")     -> org,
          quote("{proj}")    -> proj,
          quote("{schema}")  -> schema,
          quote("{instant}") -> createdAt.toString
        )
      ) deepMerge Json.obj("_original_source" -> Json.fromString(Json.obj("k" -> Json.fromInt(1)).noSpaces))

    "encode ScoredQueryResults" in {
      val results: QueryResults[Json] = ScoredQueryResults[Json](
        3,
        0.3f,
        List(
          ScoredQueryResult(0.3f, json(url"http://nexus.com/result1", before)),
          ScoredQueryResult(0.2f, json(url"http://nexus.com/result2", before)),
          ScoredQueryResult(0.1f, json(url"http://nexus.com/result3", now))
        ),
        sort(now)
      )

      results.asJson.sortKeys shouldEqual jsonContentOf(
        "/search/scored-query-results.json",
        Map(
          quote("{org}")                -> org,
          quote("{proj}")               -> proj,
          quote("{schema}")             -> schema,
          quote("{before}")             -> before.toString,
          quote("{lastElementCreated}") -> now.toString,
          quote("{after}")              -> after(now)
        )
      )
    }
    "encode UnscoredQueryResults" in {
      val results: QueryResults[Json] = UnscoredQueryResults[Json](
        3,
        List(
          UnscoredQueryResult(json(url"http://nexus.com/result1", before)),
          UnscoredQueryResult(json(url"http://nexus.com/result2", before)),
          UnscoredQueryResult(json(url"http://nexus.com/result3", now))
        ),
        sort(now)
      )

      results.asJson.sortKeys shouldEqual jsonContentOf(
        "/search/unscored-query-results.json",
        Map(
          quote("{org}")                -> org,
          quote("{proj}")               -> proj,
          quote("{schema}")             -> schema,
          quote("{before}")             -> before.toString,
          quote("{lastElementCreated}") -> now.toString,
          quote("{after}")              -> after(now)
        )
      )

    }
  }

  private def sort(instant: Instant): Option[String] = Some(Json.arr(Json.fromString(instant.toString)).noSpaces)
  private def after(instant: Instant): String =
    Query("after" -> List(Json.fromString(instant.toString)).asJson.noSpaces).toString()

} 
Example 15
Source File: ServeSpec.scala    From typed-schema   with Apache License 2.0 5 votes vote down vote up
package ru.tinkoff.tschema.akkaHttp

import akka.http.scaladsl.model.Multipart.FormData
import akka.http.scaladsl.model.Uri.Query
import akka.http.scaladsl.model.{HttpEntity, Uri}
import akka.http.scaladsl.server.MissingQueryParamRejection
import akka.http.scaladsl.testkit.ScalatestRouteTest
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
import ru.tinkoff.tschema.syntax

class ServeSpec extends AnyWordSpec with Matchers with ScalatestRouteTest {
  trait Small

  import ru.tinkoff.tschema.syntax._
  val dsl = syntax

  val intAnswer = 42

  object handler {
    val int = 42

    def repeat(body: String, n: Int) = body * n

    def multiply(x: Long, y: Double) = f"result is ${x * y}%.2f"

    def size(args: List[Int]) = args.size

    def min(args: List[Int]) = args.min
  }

  def api = (keyPrefix("int") :> get :> complete[Int]) ~
    (keyPrefix("repeat") :> reqBody[String] :> queryParam[Int]("n") :> post :> complete[String]) ~
    (keyPrefix("multiply") :> formField[Long]("x") :> formField[Double]("y") :> post :> complete[String]) ~
    (keyPrefix("size") :> queryParams[Option[Int]]("args") :> post :> complete[Int]) ~
    (keyPrefix("min") :> queryParams[Int]("args") :> post :> complete[Int])

  val route = MkRoute(api)(handler)

  "Simple service" should {
    "return a simple int" in {
      Get("/int") ~> route ~> check {
        responseAs[Int] shouldEqual intAnswer
      }
    }

    "multiply string by n times" in {
      Post(Uri("/repeat").withQuery(Query("n" -> "5")), "batman") ~> route ~> check {
        responseAs[String] shouldEqual ("batman" * 5)
      }
    }

    "multiply numbers from formdata" in {
      Post(Uri("/multiply"), FormData(Map("x" -> HttpEntity("3"), "y" -> HttpEntity("1.211")))) ~>
        route ~>
        check {
          responseAs[String] shouldEqual f"result is ${3.63}%.2f"
        }
    }

    "return size of empty args" in {
      Post(Uri("/size")) ~> route ~> check {
        responseAs[Int] shouldEqual 0
      }
    }

    "return size of non empty args" in {
      Post(Uri("/size").withQuery(Query(List("1", "2", "3").map("args" -> _): _*))) ~> route ~> check {
        responseAs[Int] shouldEqual 3
      }
    }

    "return min of non empty args" in {
      Post(Uri("/min").withQuery(Query(List("3", "1", "2").map("args" -> _): _*))) ~> route ~> check {
        responseAs[Int] shouldEqual 1
      }
    }

    "reject on min with empty args" in {
      Post(Uri("/min")) ~> route ~> check {
        rejection shouldEqual MissingQueryParamRejection("args")
      }
    }
  }
}