Last active
March 25, 2017 08:21
-
-
Save Krever/cf494eaf975f83ba4be236463606e189 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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