Skip to content

Instantly share code, notes, and snippets.

@Krever
Last active March 25, 2017 08:21
Show Gist options
  • Save Krever/cf494eaf975f83ba4be236463606e189 to your computer and use it in GitHub Desktop.
Save Krever/cf494eaf975f83ba4be236463606e189 to your computer and use it in GitHub Desktop.
import BasicAuthAlgebra.Credentials
trait Algebra {
type Endpoint[Req, Resp]
type Request[T]
type RequestHeaders[T]
type Path[T]
type RequestBody[T]
type Method
type Response[T]
type ResponseBody[T]
type ResponseHeaders[T]
def endpoint: Endpoint[Unit, Unit]
def emptyRequest: Request[Unit]
def emptyReqHeaders: RequestHeaders[Unit]
def emptyRespHeaders: ResponseHeaders[Unit]
def root: Path[Unit]
def Get: Method
def jsonBody[T]: RequestBody[T]
def stringReqBody: RequestBody[String]
def stringRespBody: ResponseBody[String]
def emptyResponse: Response[Unit]
case class CountryPreference(charset: String, language: String)
implicit class EndpointOps[Req, Resp](endpoint: Endpoint[Req, Resp]) {
def withRequest[T](request: Request[T]): Endpoint[T, Resp] = ???
def withResponse[T](request: Response[T]): Endpoint[Req, T] = ???
def getRequest: Request[Req] = ???
def getResponse: Response[Resp] = ???
}
implicit class RequestOps[T](request: Request[T]) {
def withHeaders[U](headers: RequestHeaders[U])(implicit tupler: Tupler[T, U]): Request[tupler.Out] = ???
def withPath[U](path: Path[U])(implicit tupler: Tupler[T, U]): Request[tupler.Out] = ???
def withStringBody(implicit tupler: Tupler[T, String]): Request[tupler.Out] = withBody(stringReqBody)(tupler)
def withBody[U](body: RequestBody[U])(implicit tupler: Tupler[T, U]): Request[tupler.Out] = ???
def withMethod(body: Method): Request[T] = ???
}
implicit class ReqHeadersOps[T](headers: RequestHeaders[T]) {
def withHeader[U](headerName: String)(implicit tupler: Tupler[T, String]): RequestHeaders[tupler.Out] = ???
def as[U]: RequestHeaders[U] = ???
}
implicit class RespHeadersOps[T](headers: ResponseHeaders[T]) {
def withHeader[U](headerName: String)(implicit tupler: Tupler[T, String]): ResponseHeaders[tupler.Out] = ???
def as[U]: ResponseHeaders[U] = ???
}
implicit class PathOps[T](path: Path[T]) {
def /(segment: String)(implicit tupler: Tupler[T, String]): Path[tupler.Out] = ???
}
implicit class ResponseOps[T](response: Response[T]) {
def withHeaders[U](headers: ResponseHeaders[U])(implicit tupler: Tupler[T, U]): Response[tupler.Out] = ???
def withStringBody(implicit tupler: Tupler[T, String]): Response[tupler.Out] = withBody(stringRespBody)(tupler)
def withBody[U](body: ResponseBody[U])(implicit tupler: Tupler[T, U]): Response[tupler.Out] = ???
def or[U](response2: Response[U]): Response[Either[T, U]] = ???
def withStatusCode(code: Int): Response[T] = ???
}
}
trait Tupler[A, B] {
type Out
}
trait BasicAuthAlgebra extends Algebra {
import BasicAuthAlgebra._
type Protected[T] = Option[T]
//String in Right is basic auth realm
def toProtected[T](response: Response[Either[T, String]]): Response[Protected[T]]
implicit class BasicAuthEndpointOps[Req, Resp](endpoint: Endpoint[Req, Resp]) {
def withBasicAuth(implicit tupler: Tupler[Req, Credentials]): Endpoint[tupler.Out, Protected[Resp]] = {
val request = endpoint
.getRequest
.withHeaders(emptyReqHeaders.withHeader("Authorization").as[Credentials])
val response = endpoint.getResponse.or(
emptyResponse
.withHeaders(emptyRespHeaders.withHeader("WWW-Authenticate"))
.withStatusCode(401)
)
endpoint
.withRequest(request)
.withResponse(toProtected(response))
}
}
}
trait ValidatedRequestAlgebra extends Algebra {
type Validated[T] = Option[T]
def toValidated[T](response: Response[Either[T, Unit]]): Response[Validated[T]]
implicit class ValidatedResponseOps[T](response: Response[T]) {
def validated: Response[Validated[T]] = {
val r = response.or(emptyResponse.withStatusCode(400))
toValidated(r)
}
}
}
trait OptionalAlgebra extends Algebra {
type Optional[T] = Option[T]
def toOptional[T](response: Response[Either[T, Unit]]): Response[Optional[T]]
implicit class ValidatedResponseOps[T](response: Response[T]) {
def optional: Response[Optional[T]] = {
val r = response.or(emptyResponse.withStatusCode(404))
toOptional(r)
}
}
}
trait ExampleApi extends Algebra with ValidatedRequestAlgebra with BasicAuthAlgebra {
val parseFloat: Endpoint[(String, Credentials), Option[Option[String]]] = endpoint
.withRequest(
emptyRequest
.withMethod(Get)
.withStringBody
.withPath(root / "parseFloat"))
.withResponse(
emptyResponse
.withStringBody
.validated
)
.withBasicAuth
}
object BasicAuthAlgebra {
case class Credentials(username: String, password: String)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment