Suave Library ReferenceSynopsismodule Suave.WebPart type WebPart<'a> = 'a -> Async<'a option> val succeed : WebPart<'a> val fail<'a> : Async<'a option> val never : WebPart<'a> val bind : f:('a -> Async<'b option>) -> a: Async<'a option> -> Async<'b option> val compose : first:('a -> Async<'b option>) -> second:('b -> Async<'c option>) -> 'a -> Async<'c option> type AsyncOptionBuilder = new : unit -> AsyncOptionBuilder member Return : 'a -> Async<'a option> member Zero : unit -> Async<unit option> member ReturnFrom : Async<'a option> -> Async<'a option> member Delay : (unit -> Async<'a option>) -> Async<'a option> member Bind : Async<'a option> * ('a -> Async<'b option>) -> Async<'b option> val asyncOption : AsyncOptionBuilder val choose : options:WebPart<'a> list -> WebPart<'a> val inject : postOp:WebPart<'a> -> pairs:(WebPart<'a> * WebPart<'a>) list -> WebPart<'a> val warbler : f:('t -> 't -> 'u) -> 't -> 'u val cnst : x:'t -> 'u -> 't val cond : item:Choice<'T, _> -> f:('T -> 'U -> 'V) -> g:('U -> 'V) -> 'U -> 'V val tryThen : first:WebPart<'a> -> second:WebPart<'a> -> WebPart<'a> val concatenate : first:('a -> 'b option) -> second:('a -> 'b option) -> 'a -> 'b option module Response = val response : statusCode:HttpCode -> content:byte [] -> WebPart module Writers = val setStatus : status:HttpCode -> WebPart val setHeader : key:string -> value:string -> WebPart val setHeaderValue : key:string -> value:string -> WebPart val addHeader : key:string -> value:string -> WebPart val setUserData : key:string -> value:'T -> WebPart val unsetUserData : key : string -> WebPart val createMimeType : name:string -> compression:bool -> MimeType option val defaultMimeTypesMap : ext:string -> MimeType option val setMimeType : mimeType:string -> WebPart module Intermediate = val CONTINUE : WebPart val SWITCHING_PROTO : WebPart module Successful = val ok : bytes:byte [] -> WebPart val OK : body:string -> WebPart val created : bytes:byte [] -> WebPart val CREATED : body:string -> WebPart val accepted : bytes:byte [] -> WebPart val ACCEPTED : body:string -> WebPart val no_content : WebPart val NO_CONTENT : WebPart module Redirection = val moved_permanently : location:string -> WebPart val MOVED_PERMANENTLY : location:string -> WebPart val found : location:string -> WebPart val FOUND : location:string -> WebPart val redirect : location:string -> WebPart val see_other : location:string -> WebPart val not_modified : WebPart val NOT_MODIFIED : WebPart module RequestErrors = val bad_request : bytes:byte [] -> WebPart val BAD_REQUEST : body:string -> WebPart val unauthorized : bytes:byte [] -> WebPart val UNAUTHORIZED : body:string -> WebPart val challenge : WebPart val forbidden : bytes:byte [] -> WebPart val FORBIDDEN : body:string -> WebPart val not_found : bytes:byte [] -> WebPart val NOT_FOUND : body:string -> WebPart val method_not_allowed : bytes:byte [] -> WebPart val METHOD_NOT_ALLOWED : body:string -> WebPart val not_acceptable : bytes:byte[] -> WebPart val NOT_ACCEPTABLE : body:string -> WebPart val request_timeout : WebPart val conflict : bytes:byte[] -> WebPart val CONFLICT : body:string -> WebPart val gone : bytes:byte [] -> WebPart val GONE : body:string -> WebPart val unsupported_media_type : bytes:byte [] -> WebPart val UNSUPPORTED_MEDIA_TYPE : body:string -> WebPart val unprocessable_entity : bytes:byte [] -> WebPart val UNPROCESSABLE_ENTITY : body:string -> WebPart val precondition_required : bytes:byte[] -> WebPart val PRECONDITION_REQUIRED : body:string -> WebPart val too_many_requests : bytes:byte [] -> WebPart val TOO_MANY_REQUESTS : body:string -> WebPart module ServerErrors = val internal_error : bytes:byte [] -> WebPart val INTERNAL_ERROR : body:string -> WebPart val not_implemented : bytes:byte [] -> WebPart val NOT_IMPLEMENTED : body:string -> WebPart val bad_gateway : bytes:byte [] -> WebPart val BAD_GATEWAY : body:string -> WebPart val service_unavailable : bytes:byte [] -> WebPart val SERVICE_UNAVAILABLE : body:string -> WebPart val gateway_timeout : bytes:byte [] -> WebPart val GATEWAY_TIMEOUT : body:string -> WebPart val invalid_http_version : bytes:byte [] -> WebPart val INVALID_HTTP_VERSION : WebPart module Filters = val path : pathAfterDomain:string -> WebPart val pathCi : pathAfterDomain:string -> WebPart val pathStarts : pathAfterDomainSubstr:string -> WebPart val pathStartsCi : pathAfterDomainSubstr:string -> WebPart val method : method :HttpMethod -> WebPart val isSecure : WebPart val hasFlag : flag:string -> WebPart val pathRegex : pathAfterDomainRegex:string -> WebPart val host : hostname:string -> WebPart val serverHost : hostname:string -> WebPart val clientHost : hostname:string -> WebPart val logFormatStructured : ctx:HttpContext -> string * Map<string,obj> val logWithLevelStructured : level:LogLevel -> logger:Logger -> messageFun:(HttpContext -> string * Map<string,obj>) -> WebPart val logStructured : logger:Logger -> messageFun:(HttpContext -> string * Map<string,obj>) -> WebPart val logFormat : ctx:HttpContext -> string val logWithLevel : level:LogLevel -> logger:Logger -> messageFun:(HttpContext -> string) -> WebPart val log : logger:Logger -> messageFun:(HttpContext -> string) -> WebPart val pathScan : pf:PrintfFormat<'a,'b,'c,'d,'t> -> h:('t -> WebPart) -> WebPart val pathScanCi : format:PrintfFormat<'a,'b,'c,'d,'t> -> handler:('t -> WebPart) -> WebPart val timeoutWebPart : timeout:System.TimeSpan -> child:WebPart -> WebPart val GET : WebPart val POST : WebPart val DELETE : WebPart val PUT : WebPart val HEAD : WebPart val CONNECT : WebPart val PATCH : WebPart val TRACE : WebPart val OPTIONS : WebPart module Files = val sendFile : fileName:string -> compression:bool -> WebPart val file : fileName:string -> WebPart val resolvePath : rootPath:string -> fileName:string -> string val browseFile : rootPath:string -> fileName:string -> WebPart val browseFileHome : fileName:string -> WebPart val browse : rootPath:string -> WebPart val browseHome : WebPart val dir : rootPath:string -> WebPart val dirHome : WebPart module Embedded = val sendResource : source:Assembly -> resourceName:string -> compression:bool -> WebPart val sendResourceFromDefaultAssembly : resourceName:string -> compression:bool -> WebPart val resource : source:Assembly -> name:string -> WebPart val resourceFromDefaultAssembly : name:string -> WebPart val browse : source:Assembly -> WebPart val browseDefaultAsssembly : WebPart module EventSource = val asyncWrite : out:Connection -> data:string -> SocketOp<unit> val (<<.) : out:Connection -> data:string -> SocketOp<unit> val dispatch : out:Connection -> SocketOp<unit> val comment : out:Connection -> cmt:string -> SocketOp<unit> val eventType : out:Connection -> eventType:string -> SocketOp<unit> val data : out:Connection -> data:string -> SocketOp<unit> val esId : out:Connection -> lastEventId:string -> SocketOp<unit> val retry : out:Connection -> retry:uint32 -> SocketOp<unit> type Message = { id : string data : string type : string option } static member create : id:string -> data:string -> Message static member createType : id:string -> data:string -> typ:string -> Message val send : out:Connection -> msg:Message -> SocketOp<unit> val handShake : fCont:(Connection -> SocketOp<Connection>) -> WebPart module TransferEncoding = val chunked: (Connection -> SocketOp<'a * Connection>) -> WebPart module Control = val CLOSE : WebPart module CORS = [<RequireQualifiedAccess>] type InclusiveOption<'T> = | None | Some of 'T | All type CORSConfig = { allowedUris : InclusiveOption<string list> allowedMethods : InclusiveOption<HttpMethod list> allowCookies : bool exposeHeaders : InclusiveOption<string list> maxAge : int option } val cors : CORSConfig:(CORSConfig) -> WebPart val defaultCORSConfig : CORSConfig [<AutoOpen>] module Http = type HttpMethod = | GET | POST | DELETE | PUT | HEAD | CONNECT | PATCH | TRACE | OPTIONS | OTHER of string [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpMethod = val parse : string -> HttpMethod type HttpStatus = { code : int reason : string } type HttpCode = | HTTP_100 | HTTP_101 | HTTP_200 | HTTP_201 | HTTP_202 | HTTP_203 | HTTP_204 | HTTP_205 | HTTP_206 | HTTP_300 | HTTP_301 | HTTP_302 | HTTP_303 | HTTP_304 | HTTP_305 | HTTP_306 | HTTP_307 | HTTP_400 | HTTP_401 | HTTP_402 | HTTP_403 | HTTP_404 | HTTP_405 | HTTP_406 | HTTP_407 | HTTP_408 | HTTP_409 | HTTP_410 | HTTP_411 | HTTP_412 | HTTP_413 | HTTP_422 | HTTP_426 | HTTP_428 | HTTP_429 | HTTP_414 | HTTP_415 | HTTP_416 | HTTP_417 | HTTP_451 | HTTP_500 | HTTP_501 | HTTP_502 | HTTP_503 | HTTP_504 | HTTP_505 member code : int member reason : string member message : string member describe : unit -> string member status : HttpStatus static member tryParse : code:int -> Choice<HttpCode, string> type SameSite = | Strict | Lax type HttpCookie = { name : string value : string expires : DateTimeOffset option path : string option domain : string option secure : bool httpOnly : bool sameSite : SameSite option } [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpCookie = val create : name:string -> value:string -> expires:DateTimeOffset option -> path:string option -> domain:string option -> secure:bool -> httpOnly:bool -> sameSite:SameSite option -> HttpCookie val createKV : name:string -> value:string -> HttpCookie val empty : HttpCookie val toHeader : cookie:HttpCookie -> string type MimeType = { name : string compression : bool } type MimeTypesMap = string -> MimeType option type HttpUpload = { fieldName : string fileName : string mimeType : string tempFilePath : string } [<AllowNullLiteral>] type TlsProvider = abstract wrap : Connection * obj -> SocketOp<Connection> type Protocol = | HTTP | HTTPS of obj member secure : bool type Host = string type HttpBinding = { scheme : Protocol socketBinding : SocketBinding } member uri : path:string -> query:string -> Uri override ToString : unit -> string type HttpRequest = { httpVersion : string binding : HttpBinding rawPath : string rawHost : string rawMethod : string headers : (string * string) list rawForm : byte [] rawQuery : string files : HttpUpload list multiPartFields : (string * string) list trace : TraceHeader } member query : (string * string option) list member queryParam : key:string -> Choice<string, string> member queryParamOpt : key:string -> (string * string option) option member queryFlag : flag:string -> bool member header : key:string -> Choice<string, string> member form : (string * string option) list member formData : key:string -> Choice<string, string> member fieldData : key:string -> Choice<string, string> member Item : key:string -> string option with get member clientHost : trustProxy:bool -> sources:string list -> Host member clientHostTrustProxy : Host member path : string member url : Uri member host : Host member method : HttpMethod [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpRequest = val empty : HttpRequest [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpBinding = val DefaultBindingPort : Port val defaults : HttpBinding val create : scheme:Protocol -> ip:IPAddress -> port:Port -> HttpBinding val createSimple : scheme:Protocol -> ip:string -> port:int -> HttpBinding type HttpContent = | NullContent | Bytes of byte [] | SocketTask of (Connection * HttpResult -> SocketOp<Connection>) and HttpResult = { status : HttpStatus headers : (string * string) list content : HttpContent writePreamble : bool } [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpResult = val empty : HttpResult type ServerKey = byte [] [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module ServerKey = val validate : ServerKey -> ServerKey val fromBase64 : (string -> ServerKey) type IPAddress with static member tryParseC : ip:string -> Choice<IPAddress, unit> type HttpRuntime = { serverKey : ServerKey errorHandler : ErrorHandler mimeTypesMap : MimeTypesMap homeDirectory : string compressionFolder : string logger : Logger matchedBinding : HttpBinding cookieSerialiser : CookieSerialiser tlsProvider : TlsProvider hideHeader : bool maxContentLength : int } and HttpContext = { /// The HTTP request being processed request : HttpRequest runtime : HttpRuntime connection : Connection userState : Dictionary<string, obj> response : HttpResult } member clientIp : trustProxy:bool -> sources:string list -> IPAddress member clientIpTrustProxy : IPAddress member isLocal : bool member isLocalTrustProxy : bool member clientPort : trustProxy:bool -> sources:string list -> Port member clientPortTrustProxy : Port member clientProto : trustProxy:bool -> sources:string list -> string member clientProtoTrustProxy : string and ErrorHandler = Exception -> String -> WebPart<HttpContext> type WebPart = WebPart<HttpContext> [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpRuntime = val ServerKeyLength : uint16 val empty : HttpRuntime val create : serverKey:ServerKey -> errorHandler:ErrorHandler -> mimeTypes:MimeTypesMap -> homeDirectory:string -> compressionFolder:string -> logger:Logger -> cookieSerialiser:CookieSerialiser -> tlsProvider:TlsProvider -> hideHeader:bool -> maxContentLength:int -> binding:HttpBinding -> HttpRuntime [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpContext = val empty : HttpContext val create : request:HttpRequest -> runtime:HttpRuntime -> connection:Connection -> writePreamble:bool -> HttpContext val request : apply:(HttpRequest -> HttpContext -> 'a) -> context:HttpContext -> 'a val context : apply:(HttpContext -> HttpContext -> 'a) -> context:HttpContext -> 'a module Cookie = type CookieLife = | Session | MaxAge of duration:TimeSpan type CookieError = | NoCookieFound of cookieName:string | DecryptionError of error:Crypto.SecretboxDecryptionError val parseCookies : cookieString:string -> HttpCookie list val parseResultCookie : cookieString:string -> HttpCookie type HttpRequest with member cookies : Map<string, HttpCookie> type HttpResult with member cookies : Map<string, HttpCookie> val setCookie : cookie:HttpCookie -> WebPart val unsetCookie : name:string -> WebPart val setPair : httpCookie:HttpCookie -> clientCookie:HttpCookie -> WebPart val unsetPair : httpCookieName:string -> WebPart type CookiesState = { serverKey : ServerKey cookieName : string userStateKey : string relativeExpiry : CookieLife secure : bool } [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module CookiesState = val create : serverKey:ServerKey -> cookieName:string -> userStateKey:string -> relativeExpiry:CookieLife -> secure:bool -> CookiesState val generateCookies : serverKey:ServerKey -> cookieName:string -> relativeExpiry:CookieLife -> secure:bool -> plainData:byte[] -> HttpCookie * HttpCookie val readCookies : key:ServerKey -> cookieName:string -> cookies:Map<string, HttpCookie> -> Choice<HttpCookie * byte [], CookieError> val refreshCookies : expiry:CookieLife -> cookie:HttpCookie -> WebPart val updateCookies : csctx:CookiesState -> fPlainText : (byte [] option -> byte []) -> WebPart val cookieState : csctx:CookiesState -> noCookie:(unit -> Choice<byte [], WebPart>) -> decryptionFailure:(Crypto.SecretboxDecryptionError -> Choice<byte [], WebPart>) -> fSuccess:WebPart -> WebPart val UserNameKey : string val authenticateBasic : f:(string * string -> bool) -> protectedPart:WebPart -> WebPart val authenticateBasicAsync : f:(string * string -> bool Async) -> protectedPart:WebPart -> WebPart val SessionAuthCookie : string val StateStoreType : string val SessionIdLength : int val authenticate : relativeExpiry:CookieLife -> secure:bool -> missingCookie:(unit -> Choice<byte[], WebPart>) -> decryptionFailure:(SecretboxDecryptionError -> Choice<byte [], WebPart>) -> fSuccess:WebPart -> WebPart val authenticateWithLogin : relativeExpiry:CookieLife -> loginPage:string -> fSuccess:WebPart -> WebPart val deauthenticate : WebPart val deauthenticateWithLogin : loginPage :string -> WebPart val authenticated : relativeExpiry:CookieLife -> secure:bool -> WebPart module HttpContext = val sessionId : ctx:HttpContext -> string option Description[<AutoOpen>] module Suave.WebPart type WebPart<'a> = 'a -> Async<'a option> Takes 'a and returns SuaveTask of 'a SuaveTask is also known as AsyncOption val bind : f:('a -> Async<'b option>) -> a: Async<'a option> -> Async<'b option> Classic bind (for SuaveTask) val compose : first:('a -> Async<'b option>) -> second:('b -> Async<'c option>) -> 'a -> Async<'c option> Left-to-right Kleisli composition (for SuaveTask). val asyncOption : AsyncOptionBuilder With this workflow you can write WebParts like this let task ctx = asyncOption { let! _ = GET ctx let! ctx = Writers.setHeader "foo" "bar" return ctx } we can still use the old symbol but now has a new meaning let foo ctx = GET ctx >>= OK "hello" val choose : options:WebPart<'a> list -> WebPart<'a> Entry-point for composing the applicative routes of the http application, by iterating the options, applying the context, arg, to the predicate from the list of options, until there's a match/a Some(x) which can be run. val inject : postOp:WebPart<'a> -> pairs:(WebPart<'a> * WebPart<'a>) list -> WebPart<'a> Inject a webPart +------------+ +--------------+ | url "/a" +----------+ +---------+ cont1 | +------------+ | | +--------------+ | | +-------------+ | +----------+ | +--------------+ | url "/b" +---------+-------+ injected +----+---------+ cont2 | +-------------+ | +----------+ | +--------------+ | | +-------------+ | | +--------------+ | url "/b" +---------+ +---------+ cont3 | +-------------+ +--------------+ val warbler : f:('t -> 't -> 'u) -> 't -> 'u Which bird? A Warbler! Pipe the request through to a bird that can peck at it. Put another way, using 'warbler' lets you look at the first parameter and then make a decision about what thing to return (it's most likely a WebPart you'll be returning). (Remember, WebPart is HttpContext -> Async val cnst : x:'t -> 'u -> 't The constant function, which returns its constant, no matter its input. - theorem: identity = (warbler cnst) (warbler cnst) x = cnst x x = fun _ -> x val cond : item:Choice<'T, _> -> f:('T -> 'U -> 'V) -> g:('U -> 'V) -> 'U -> 'V The conditional function that applies f x a if there's a value in d, or otherwise, applies g a, if there is no value in d. module Response = val response : statusCode:HttpCode -> content:byte [] -> WebPart Respond with a given status code, http message, content in the body to a http request. Respond with a given status code, http reason phrase, content in the body to a http request. module Writers = Module that allows changing the output response in different ways. Functions have signature f :: params... -> HttpContext -> HttpContext. val setStatus : status:HttpCode -> WebPart Sets the HTTP response status val setHeader : key:string -> value:string -> WebPart Ensures that the header named by the val setHeaderValue : key:string -> value:string -> WebPart Ensures that the is unique in the comma-separated list of the response header, denoted by val addHeader : key:string -> value:string -> WebPart Adds the header key with the given value to the list of returned headers, even if that header already exists. This means that Suave will serve a a response with the header denoted by Also consider Furthermore, Cookies must be set on separate header lines (using this function) and not comma-concatenated. See https://github.com/SuaveIO/suave/issues/338#issuecomment-156820747 for defails. val setUserData : key:string -> value:'T -> WebPart Sets a user data key-value pair with the key and value specified. Downstream web parts can read this. val unsetUserData : key : string -> WebPart Unset the user data by the given key val createMimeType : name:string -> compression:bool -> MimeType option val defaultMimeTypesMap : ext:string -> MimeType option val setMimeType : mimeType:string -> WebPart module Intermediate = Control-flow functions, such as 100 Continue and 101 Switching Protocol. val CONTINUE : WebPart val SWITCHING_PROTO : WebPart module Successful = val ok : bytes:byte [] -> WebPart val OK : body:string -> WebPart val created : bytes:byte [] -> WebPart val CREATED : body:string -> WebPart val accepted : bytes:byte [] -> WebPart val ACCEPTED : body:string -> WebPart val no_content : WebPart val NO_CONTENT : WebPart module Redirection = Functions from here are 'end routes' in that they don't require you to keep returning applicatives, but can end up in an async monad/workflow that writes the data to the client in the end. This class of status code indicates that further action needs to be taken by the user agent in order to fulfill the request. The action required MAY be carried out by the user agent without interaction with the user if and only if the method used in the second request is GET or HEAD. A client SHOULD detect infinite redirection loops, since such loops generate network traffic for each redirection. val moved_permanently : location:string -> WebPart val MOVED_PERMANENTLY : location:string -> WebPart val found : location:string -> WebPart val FOUND : location:string -> WebPart val redirect : location:string -> WebPart val see_other : location:string -> WebPart val not_modified : WebPart val NOT_MODIFIED : WebPart module RequestErrors = val bad_request : bytes:byte [] -> WebPart val BAD_REQUEST : body:string -> WebPart val unauthorized : bytes:byte [] -> WebPart val UNAUTHORIZED : body:string -> WebPart val challenge : WebPart val forbidden : bytes:byte [] -> WebPart val FORBIDDEN : body:string -> WebPart val not_found : bytes:byte [] -> WebPart val NOT_FOUND : body:string -> WebPart val method_not_allowed : bytes:byte [] -> WebPart val METHOD_NOT_ALLOWED : body:string -> WebPart val not_acceptable : bytes:byte[] -> WebPart val NOT_ACCEPTABLE : body:string -> WebPart val request_timeout : WebPart val conflict : bytes:byte[] -> WebPart val CONFLICT : body:string -> WebPart val gone : bytes:byte [] -> WebPart val GONE : body:string -> WebPart val unsupported_media_type : bytes:byte [] -> WebPart val UNSUPPORTED_MEDIA_TYPE : body:string -> WebPart val unprocessable_entity : bytes:byte [] -> WebPart val UNPROCESSABLE_ENTITY : body:string -> WebPart val precondition_required : bytes:byte[] -> WebPart <html> <head> <title>Precondition Required</title> </head> <body> <h1>Precondition Required</h1> <p>This request is required to be conditional; try using "If-Match".</p> </body> </html> val PRECONDITION_REQUIRED : body:string -> WebPart <html> <head> <title>Precondition Required</title> </head> <body> <h1>Precondition Required</h1> <p>This request is required to be conditional; try using "If-Match".</p> </body> </html> val too_many_requests : bytes:byte [] -> WebPart val TOO_MANY_REQUESTS : body:string -> WebPart module ServerErrors = 10.5 Server Error 5xx Response status codes beginning with the digit "5" indicate cases in which the server is aware that it has erred or is incapable of performing the request. Except when responding to a HEAD request, the server SHOULD include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition. User agents SHOULD display any included entity to the user. These response codes are applicable to any request method. val internal_error : bytes:byte [] -> WebPart val INTERNAL_ERROR : body:string -> WebPart val not_implemented : bytes:byte [] -> WebPart val NOT_IMPLEMENTED : body:string -> WebPart val bad_gateway : bytes:byte [] -> WebPart An upstream server that suave communicated with did not respond in a timely fashion val BAD_GATEWAY : body:string -> WebPart An upstream server that suave communicated with did not respond in a timely fashion val service_unavailable : bytes:byte [] -> WebPart The service is currently under too much load and cannot service the request val SERVICE_UNAVAILABLE : body:string -> WebPart The service is currently under too much load and cannot service the request val gateway_timeout : bytes:byte [] -> WebPart An upstream server that suave communicated with did not respond in a timely fashion val GATEWAY_TIMEOUT : body:string -> WebPart An upstream server that suave communicated with did not respond in a timely fashion val invalid_http_version : bytes:byte [] -> WebPart Only used internally in Suave. val INVALID_HTTP_VERSION : WebPart Only used internally in Suave. module Filters = Module that deals with the applicatives of suave - use functions from this module to filter what requests a given route responds to. Functions have signature f :: params... -> HttpContext -> HttpContext option. val path : pathAfterDomain:string -> WebPart Match on the path val pathCi : pathAfterDomain:string -> WebPart Match on the path regardless of casing val pathStarts : pathAfterDomainSubstr:string -> WebPart Match on the initial path val pathStartsCi : pathAfterDomainSubstr:string -> WebPart Match on the initial path regardless of casing val method : method :HttpMethod -> WebPart Match on the method val isSecure : WebPart Match on the protocol being HTTPS val hasFlag : flag:string -> WebPart Ensure the query-string parameter exists (it exists even if it does not have a value associated with it.) val pathRegex : pathAfterDomainRegex:string -> WebPart Applies the regex to the path and matches on the result val host : hostname:string -> WebPart Match on the hostname (which is a required header for a Http client to send) -> allows you to have multiple sites with a single application. TODO: support SNI #177 Perform a case-insensitive string comparison with context.request.clientHostTrustProxy which is the client-host; i.e. what the request says is the host, or what the proxy server says is the forwarded Host value. To match on what the web server *knows for sure* is the host, in the case when you've not overridden x-forwarded-host in your proxy, you should use x.request.host or Http.Applicatives.serverHost instead. The normal use- case, however, is to match on what's publically routable, which is the client host. val serverHost : hostname:string -> WebPart This is the server's knowledge of what's the host is. In the case you have a clustered web server deployment, you might be more interested in what the client expects the host to be, since most validation logic you have in your app is concerned with this. val clientHost : hostname:string -> WebPart Alias for val logFormatStructured : ctx:HttpContext -> string * Map<string,obj> 127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 A "-" in a field indicates missing data. 127.0.0.1 is the IP address of the client (remote host) which made the request to the server. user-identifier is the RFC 1413 identity of the client. frank is the userid of the person requesting the document. [10/Oct/2000:13:55:36 -0700] is the date, time, and time zone when the server finished processing the request, by default in strftime format %d/%b/%Y:%H:%M:%S %z. "GET /apache_pb.gif HTTP/1.0" is the request line from the client. The method GET, /apache_pb.gif the resource requested, and HTTP/1.0 the HTTP protocol. 200 is the HTTP status code returned to the client. 2xx is a successful response, 3xx a redirection, 4xx a client error, and 5xx a server error. 2326 is the size of the object returned to the client, measured in bytes. val logWithLevelStructured : level:LogLevel -> logger:Logger -> messageFun:(HttpContext -> string * Map<string,obj>) -> WebPart val logStructured : logger:Logger -> messageFun:(HttpContext -> string * Map<string,obj>) -> WebPart val logFormat : ctx:HttpContext -> string 127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 A "-" in a field indicates missing data. 127.0.0.1 is the IP address of the client (remote host) which made the request to the server. user-identifier is the RFC 1413 identity of the client. frank is the userid of the person requesting the document. [10/Oct/2000:13:55:36 -0700] is the date, time, and time zone when the server finished processing the request, by default in strftime format %d/%b/%Y:%H:%M:%S %z. "GET /apache_pb.gif HTTP/1.0" is the request line from the client. The method GET, /apache_pb.gif the resource requested, and HTTP/1.0 the HTTP protocol. 200 is the HTTP status code returned to the client. 2xx is a successful response, 3xx a redirection, 4xx a client error, and 5xx a server error. 2326 is the size of the object returned to the client, measured in bytes. val logWithLevel : level:LogLevel -> logger:Logger -> messageFun:(HttpContext -> string) -> WebPart val log : logger:Logger -> messageFun:(HttpContext -> string) -> WebPart val pathScan : pf:PrintfFormat<'a,'b,'c,'d,'t> -> h:('t -> WebPart) -> WebPart val pathScanCi : format:PrintfFormat<'a,'b,'c,'d,'t> -> handler:('t -> WebPart) -> WebPart val timeoutWebPart : timeout:System.TimeSpan -> child:WebPart -> WebPart val GET : WebPart val POST : WebPart val DELETE : WebPart val PUT : WebPart val HEAD : WebPart val CONNECT : WebPart val PATCH : WebPart val TRACE : WebPart val OPTIONS : WebPart Match on OPTIONS requests The OPTIONS method represents a request for information about the communication options available on the request/response chain identified by the Request-URI. This method allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval. Responses to this method are not cacheable. module Files = The files module can be used to serve from the file system. It encapsulates common patterns like verifying that back-symlinks or keywords aren't used to gain access outside the intended folder. val sendFile : fileName:string -> compression:bool -> WebPart val file : fileName:string -> WebPart val resolvePath : rootPath:string -> fileName:string -> string val browseFile : rootPath:string -> fileName:string -> WebPart val browseFileHome : fileName:string -> WebPart val browse : rootPath:string -> WebPart val browseHome : WebPart val dir : rootPath:string -> WebPart val dirHome : WebPart module Embedded = val sendResource : source:Assembly -> resourceName:string -> compression:bool -> WebPart val sendResourceFromDefaultAssembly : resourceName:string -> compression:bool -> WebPart val resource : source:Assembly -> name:string -> WebPart val resourceFromDefaultAssembly : name:string -> WebPart val browse : source:Assembly -> WebPart val browseDefaultAsssembly : WebPart module EventSource = A module that implements the Server-Sent Event specification, which can be read at www.w3.org/TR/eventsource. val asyncWrite : out:Connection -> data:string -> SocketOp<unit> Helper function that writes a string of data. Most often you are better off using the val (<<.) : out:Connection -> data:string -> SocketOp<unit> Same as val dispatch : out:Connection -> SocketOp<unit> "If the line is empty (a blank line) - dispatch the event." Dispatches the event properly to the browser. val comment : out:Connection -> cmt:string -> SocketOp<unit> "If the line starts with a U+003A COLON character (:) - Ignore the line." Writes a comment to the stream val eventType : out:Connection -> eventType:string -> SocketOp<unit> "If the field name is 'event' - Set the event type buffer to field value." Writes the event type to the stream val data : out:Connection -> data:string -> SocketOp<unit> "If the field name is 'data' - Append the field value to the data buffer, then append a single U+000A LINE FEED (LF) character to the data buffer." Write a piece of data as part of the event val esId : out:Connection -> lastEventId:string -> SocketOp<unit> "If the field name is 'id' - Set the last event ID buffer to the field value." Sets the last event id in the stream. val retry : out:Connection -> retry:uint32 -> SocketOp<unit> Sets the option for the EventSource instance, of how long to wait in ms until a new connection is spawned as a retry. type Message = A container data type for the output events static member create : id:string -> data:string -> Message Create a new message to send over SSE static member createType : id:string -> data:string -> typ:string -> Message Create a new message with a given type to send over SSE val send : out:Connection -> msg:Message -> SocketOp<unit> send a message containing data to the output stream val handShake : fCont:(Connection -> SocketOp<Connection>) -> WebPart This function composes the passed function f with the hand-shake required to start a new event-stream protocol session with the browser. module Control = module CORS = type CORSConfig = The configuration values for CORS allowedUris : InclusiveOption<string list> The list of allowed Uri(s) for requests. allowedMethods : InclusiveOption<HttpMethod list> The list of allowed HttpMethods for the request. allowCookies : bool Allow cookies? This is sent in the AccessControlAllowCredentials header. exposeHeaders : InclusiveOption<string list> The list of response headers exposed to client. This is sent in AccessControlExposeHeaders header. maxAge : int option } Max age in seconds the user agent is allowed to cache the result of the request. val cors : CORSConfig:(CORSConfig) -> WebPart [<AutoOpen>] module Http = type HttpMethod = | GET | POST | DELETE | PUT | HEAD | CONNECT | PATCH | TRACE | OPTIONS | OTHER of string These are the known HTTP methods. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpMethod = val parse : string -> HttpMethod Parse a string into a HttpMethod type HttpStatus = A HTTP status code and reason message type HttpCode = The standard HTTP response codes type HttpCookie = HTTP cookie domain : string option This cookies is only valid for the given domain secure : bool This cookie is not forwarded over plaintext transports httpOnly : bool This cookie is not readable from JavaScript [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpCookie = val create : name:string -> value:string -> expires:DateTimeOffset option -> path:string option -> domain:string option -> secure:bool -> httpOnly:bool -> sameSite:SameSite option -> HttpCookie Create a new HttpCookie with all the given values. val createKV : name:string -> value:string -> HttpCookie Create a new cookie with the given name, value, and defaults: - no explicit expiry time - path at "/", so that it's global to the domain that it's created under. - no specific domain (defaults to the current domain plus its subdomains) - secure = false (you can set it over plain text HTTP - change to true in SSL terminator) - http_only = true - the cookie can be read from JS - change this to false if you want to only be able to read the cookie from JS, but Good default if you're implementing session handling. - version: an optional version field More reading: - http://www.nczonline.net/blog/2009/05/05/http-cookies-explained/ - https://developer.mozilla.org/en-US/docs/Web/API/document.cookie val empty : HttpCookie An empty cookie value val toHeader : cookie:HttpCookie -> string Assumes only valid characters go in, see http://tools.ietf.org/html/rfc6265#section-4.1.1 type MimeType = A file's mime type and if compression is enabled or not type HttpUpload = A holder for uploaded file meta-data type Protocol = Gets the supported protocols, HTTP and HTTPS with a certificate type Host = string Type alias for string. This is the host as seen from the server; not necessarily as seen from the client. type HttpBinding = A HTTP binding is a protocol is the product of HTTP or HTTP, a DNS or IP binding and a port number. override ToString : unit -> string Overrides the default ToString() method to provide an implementation that is assignable to a BaseUri for a RestClient/HttpClient. type HttpRequest = A holder for the data extracted from the request. member query : (string * string option) list Gets the query string from the HttpRequest. Use queryParam to try to fetch data for individual items. member queryParam : key:string -> Choice<string, string> Finds the key k from the query string in the HttpRequest. To access form data, use either member queryParamOpt : key:string -> (string * string option) option Try to find the query parameter named member queryFlag : flag:string -> bool Check the query string for a - member header : key:string -> Choice<string, string> Gets the header for the given key in the HttpRequest member form : (string * string option) list Gets the form as a ((string * string option) list) from the HttpRequest. Use formData to get the data for a particular key or use the indexed property in the HttpRequest. member formData : key:string -> Choice<string, string> Finds the key k from the form of the HttpRequest. To access query string parameters, use member fieldData : key:string -> Choice<string, string> Finds the key k from the multipart-form of the HttpRequest. To access query string parameters, use member Item : key:string -> string option with get Syntactic Sugar to retrieve query string, form or multi-field values from HttpRequest member clientHost : trustProxy:bool -> sources:string list -> Host Get the client's view of what host is being called. If you trust your proxy the value will be fetched from X-Forwarded-Host, then the Host headers. If you don't explicitly overwrite these headers in the proxy you may be open to clients spoofing the headers. Hence the explicit interfaces which force you as a developer to think abou the problem. member clientHostTrustProxy : Host See docs on clientHost member path : string path is equal to UrlDecode(rawPath) member url : Uri Returns Uri object representing the url associated with this request member host : Host The Host that the web server responds to; not necessarily the host called by the client, as the request may have traversed proxies. As Suave binds to an IP rather than IP+Hostname, this can be anything the client has passed as the Host header. If you're behind a proxy, it may be the DNS name of the node that the reverse proxy forwards to, or if you're exposing Suave publically, it should match the public DNS name of the node. To ensure the correct host-name is being called, you can use member method : HttpMethod Returns a HttpMethod [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpBinding = val defaults : HttpBinding This is the value of the default HttpBinding. val create : scheme:Protocol -> ip:IPAddress -> port:Port -> HttpBinding Create a HttpBinding for the given protocol, an IP address to bind to and a port to listen on – this is the strongly typed overload. val createSimple : scheme:Protocol -> ip:string -> port:int -> HttpBinding Create a HttpBinding for the given protocol, an IP address to bind to and a port to listen on – this is the "stringly typed" overload. and HttpResult = The HttpResult is the structure that you work with to tell Suave how to send the response. Have a look at the docs for HttpContent for further details on what is possible. [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpResult = val empty : HttpResult The empty HttpResult, with a 404 and a HttpContent.NullContent content type ServerKey = byte [] A server-key is a 256 bit key with high entropy [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module ServerKey = Utilities to ensure server keys are well-formed val validate : ServerKey -> ServerKey Ensure that a server key is the proper length val fromBase64 : (string -> ServerKey) Create a key from a base-64 encoded string type IPAddress with static member tryParseC : ip:string -> Choice<IPAddress, unit> Try parse the IP address from a string, returning a choice. type HttpRuntime = The HttpRuntime is created from the SuaveConfig structure when the web server starts. You can also use the and HttpContext = The HttpContext is the container of the request, runtime, user-state and response. runtime : HttpRuntime The HttpRuntime for the request being processed connection : Connection The connection for the request being processed userState : Dictionary<string, obj> The user state for the request being processed response : HttpResult } The response for the request being processed member clientIp : trustProxy:bool -> sources:string list -> IPAddress Get the IP of the client from the HttpContext. member clientIpTrustProxy : IPAddress Warning; if you don't write these headers in your rev.proxy, the client will be able to spoof them. Related headers: - client-ip - x-forwarded-for: the "X-Forwarded-For" client request header field with the $remote_addr variable appended to it, separated by a comma. If the "X-Forwarded-For" field is not present in the client request header, the $proxy_add_x_forwarded_for variable is equal to the $remote_addr variable. from http://nginx.org/en/docs/http/ngx_http_proxy_module.html Related blog entry, with suggestion on nginx module to use to recursively tell all upstream proxies to overwrite X-Real-IP: http://distinctplace.com/infrastructure/2014/04/23/story-behind-x-forwarded-for-and-x-real-ip-headers/ and ErrorHandler = Exception -> String -> WebPart<HttpContext> A WebPart is an asynchronous function that transforms the HttpContext. An asynchronous return value of None indicates 'did not handle'. An error handler takes the exception, a programmer-provided message, a request (that failed) and returns an asynchronous workflow for the handling of the error. [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpRuntime = a module that gives you the val ServerKeyLength : uint16 The key length in bytes, references Crypto.KeyLength which is appropriate for the underlying AES-256 bit symmetric crypto in use. val empty : HttpRuntime warn: this is not to be played around with; prefer using the config defaults instead, from Web.fs, as they contain the logic for printing to the output stream correctly. val create : serverKey:ServerKey -> errorHandler:ErrorHandler -> mimeTypes:MimeTypesMap -> homeDirectory:string -> compressionFolder:string -> logger:Logger -> cookieSerialiser:CookieSerialiser -> tlsProvider:TlsProvider -> hideHeader:bool -> maxContentLength:int -> binding:HttpBinding -> HttpRuntime make a new HttpRuntime from the given parameters [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module HttpContext = A module that provides functions to create a new HttpContext. val empty : HttpContext The empty HttpContext is fairly useless for doing real work; you'd be well adviced to write some of the properties. However, it can be quite useful in unit tests. module Cookie = The cookie module is geared towards the server having the client store state but the client not being able to read that state. type CookieLife = | Session | MaxAge of duration:TimeSpan For how long should the cookie persist in the client's browser? type CookieError = | NoCookieFound of cookieName:string | DecryptionError of error:Crypto.SecretboxDecryptionError There was an error reading or decrypting the cookie. val parseCookies : cookieString:string -> HttpCookie list Parse the cookie's name and data in the string into a dictionary. type HttpRequest with member cookies : Map<string, HttpCookie> Finds the cookies of the request, or an empty Map otherwise, if there are no cookies. val setPair : httpCookie:HttpCookie -> clientCookie:HttpCookie -> WebPart Sets the cookies to the HttpResult type CookiesState = A DTO structure for passing the right parameters to the XXX_cookies functions in this module. val generateCookies : serverKey:ServerKey -> cookieName:string -> relativeExpiry:CookieLife -> secure:bool -> plainData:byte[] -> HttpCookie * HttpCookie Generate one server-side cookie, and another client-side cookie with name "${server-side-name}-client" val readCookies : key:ServerKey -> cookieName:string -> cookies:Map<string, HttpCookie> -> Choice<HttpCookie * byte [], CookieError> Tries to read the cookie of the given name from the HttpContext, and returns the cookie and its plaintext value if successful. val refreshCookies : expiry:CookieLife -> cookie:HttpCookie -> WebPart Bumps the expiry dates for all the cookies. val UserNameKey : string The key of the username placed in the userState map if present in the request val authenticateBasic : f:(string * string -> bool) -> protectedPart:WebPart -> WebPart val authenticateBasicAsync : f:(string * string -> bool Async) -> protectedPart:WebPart -> WebPart val StateStoreType : string The key used in val deauthenticate : WebPart Deauthenticates, or 'logs out' the user val deauthenticateWithLogin : loginPage :string -> WebPart Deauthenticates the user and then sends them to path specified by loginPage string val authenticated : relativeExpiry:CookieLife -> secure:bool -> WebPart Set server-signed cookies to make the response contain a cookie with a valid session id. It's worth having in mind that when you use this web part, you're setting cookies on the response; so you'll need to have the client re-send a request if you require authentication for it, after this web part has run. Parameters: - Always succeeds. module HttpContext = val sessionId : ctx:HttpContext -> string option Read the session id from the HttpContext |