
io.fintrospect.RouteSpec.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fintrospect_2.10 Show documentation
Show all versions of fintrospect_2.10 Show documentation
Library that adds self-documentation to Finagle server endpoint services
package io.fintrospect
import com.twitter.finagle.http.{Method, Request, Response, Status}
import io.fintrospect.formats.json.{Argo, JsonFormat}
import io.fintrospect.parameters.{Body, Extractable, Extraction, HeaderParameter, NotProvided, Parameter, QueryParameter}
import io.fintrospect.util.HttpRequestResponseUtil.contentFrom
/**
* Encapsulates the specification of an HTTP endpoint, for use by either a Finagle server or client.
*/
case class RouteSpec private(summary: String,
description: Option[String],
produces: Set[ContentType],
consumes: Set[ContentType],
body: Option[Body[_]],
requestParams: Seq[Parameter with Extractable[Request, _]],
responses: Seq[ResponseSpec],
validation: RouteSpec => Extractable[Request, Nothing]) {
private[fintrospect] def <--?(request: Request) = validation(this).<--?(request)
/**
* Register content types which the route will consume. This is informational only and is NOT currently enforced.
*/
def consuming(contentTypes: ContentType*): RouteSpec = copy(consumes = produces ++ contentTypes)
/**
* Register content types which thus route will produce. This is informational only and NOT currently enforced.
*/
def producing(contentTypes: ContentType*): RouteSpec = copy(produces = produces ++ contentTypes)
/**
* Register a header parameter. Mandatory parameters are checked for each request, and a 400 returned if any are missing.
*/
def taking(rp: HeaderParameter[_] with Extractable[Request, _]): RouteSpec = copy(requestParams = rp +: requestParams)
/**
* Register a query parameter. Mandatory parameters are checked for each request, and a 400 returned if any are missing.
*/
def taking(rp: QueryParameter[_] with Extractable[Request, _]): RouteSpec = copy(requestParams = rp +: requestParams)
/**
* Register the expected content of the body.
*/
def body(bp: Body[_]): RouteSpec = copy(body = Option(bp), consumes = consumes + bp.contentType)
/**
* Register a possible response which could be produced by this route, with an example JSON body (used for schema generation).
*/
def returning(newResponse: ResponseSpec): RouteSpec = copy(responses = newResponse +: responses)
/**
* Register one or more possible responses which could be produced by this route.
*/
def returning(codes: (Status, String)*): RouteSpec = copy(responses = responses ++ codes.map(c => new ResponseSpec(c, null)))
/**
* Register an exact possible response which could be produced by this route. Will be used for schema generation if content is JSON.
*/
def returning(response: Response): RouteSpec = {
returning(new ResponseSpec(response.status -> response.status.reason, Option(contentFrom(response))))
}
/**
* Register a possible response which could be produced by this route, with an example JSON body (used for schema generation).
*/
def returning[T](code: (Status, String), example: T, jsonFormat: JsonFormat[T, _] = Argo.JsonFormat): RouteSpec = copy(responses = ResponseSpec.json(code, example, jsonFormat) +: responses)
/**
* Register a possible response which could be produced by this route, with an example body (used for schema generation).
*/
def returning(code: (Status, String), example: String): RouteSpec = copy(responses = new ResponseSpec(code, Option(example)) +: responses)
def at(method: Method) = IncompletePath(this, method)
}
object RouteSpec {
trait RequestValidation extends (RouteSpec => Extractable[Request, Nothing])
/**
* Defines the validation for the Route which could result in a BadRequest response from this route. By default, this
* is set to RequestValidation.all . It is overrideable in high performance scenarios, or where custom extraction logic
* is to be applied.
*/
object RequestValidation {
/**
* Validates the presence and format of all parameters (mandatory and optional), and the request body.
*/
val all = new RequestValidation {
def apply(spec: RouteSpec) = Extractable.mk {
(request: Request) => Extraction.combine(spec.requestParams.++(spec.body).map(_.extract(request)))
}
}
/**
* Validates the presence and format of all parameters (mandatory and optional) only.
*/
val noBody = new RequestValidation {
def apply(spec: RouteSpec) = Extractable.mk {
(request: Request) => Extraction.combine(spec.requestParams.map(_.extract(request)))
}
}
/**
* Validates the presence and format of body only.
*/
val noParameters = new RequestValidation {
def apply(spec: RouteSpec) = Extractable.mk {
(request: Request) => Extraction.combine(spec.body.map(_.extract(request)).toSeq)
}
}
/**
* Do not perform any validation of the request parameters or the body.
*/
val none = new RequestValidation {
def apply(spec: RouteSpec) = Extractable.mk { (request: Request) => NotProvided }
}
}
def apply(summary: String = "", description: String = null, validation: RequestValidation = RequestValidation.all): RouteSpec =
RouteSpec(summary, Option(description), Set.empty, Set.empty, None, Nil, Nil, validation)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy