Running snippets via HTTP API
This page gives a very brief overview of the commands exposed by the FsInteractiveService.exe
server.
The server exposes endpoints:
/output
for getting output that was printed by F# interactive/eval
for evaluating expressions and interactions/cancel
for cancelling running computation/reset
for restarting the F# Interactive (this is limited though; see below)- endpoints for IntelliSense are discussed in a separate document
Starting the server
For the purpose of the demo, we start the server using Process.Start
. The process takes one optional
parameter, which is the binding address and port to be used. Either part may also be omitted, in which
case the defaults are used (127.0.0.1
and 8707
, respectively).
1: 2: 3: 4: 5: 6: |
|
Here, we start the process at a port 18082
. You could specify address and port by providing an
argument in the format 0.0.0.0:80
. When the parameter does not contain :
, it is treated either
as a port or as an address, depending on whether it can be parsed as an integer.
Reading FSI output
F# Interactive can print output at any time (e.g. from a background async workflow or after starting). You can get the output printed since the last time by calling:
1: 2: |
|
|
In the resulting JSON, the result is set to output
and you can find the printed message in output
.
Evaluating code
To evaluate code, you can call /eval
with a JSON that contains the file name, line of the source code
in the source file and the code itself (the file does not have to exist).
1: 2: 3: |
|
|
The result is set to success
and F# Interactive prints the returned value into output
.
If the evaluates code is an expression, the string
field in details
contains the value formatted
using ToString
. If your code prints something, you will find the printed result in output
too:
1: 2: 3: |
|
|
Note that this is still an expression (that can be formatted) and so the output includes the it
value,
but string
is null
. Finally, the following snippet evaluates code that throws an exception:
1: 2: 3: 4: |
|
|
In this case, the result is exception
and you can find the formatted exception (using ToString
) in the
details
field.
Errors and warnings
The following tries to evaluate 1+1.0
, which is a type error:
1: 2: 3: 4: |
|
|
For errors, the result is errror
and details
contains an array with detailed information about the
individual messages. Note that the line number is calculated relatively to the number you provide in the
input. Next, let's look at code that runs, but with warnings:
1: 2: 3: 4: |
|
|
This evaluates fine so result is success
, but the details
field contains warnings
where you can
find an array of warnings (in the same format as errors above).
Cancelling computation
If you run an infinite loop in the F# interactive process, you can cancel it by calling /cancel
.
The following starts a request (in background) with an infinite loop and then cancels it later:
1: 2: 3: 4: 5: 6: 7: 8: 9: |
|
|
You can also reset the F# Interactive service by calling /reset
, but that has limitations.
It resets whatever F# Interactive is doing, but it does not kill all background processes that
it might have started (like async
workflow started using Async.Start
), so it is probably better
to just kill the process and restart it completely.
Adding HTML printers
As discussed in HTML printer docs, you can use AddHtmlPrinter
to register
printer for formatting values as HTML. The FsInteractiveService defines a special symbol
HAS_FSI_ADDHTMLPRINTER
that can be used to call the method only when running in the
FsInteractiveService context.
The method registers printers based on types. For example, the following silly example defines a printer that makes integers bold:
1: 2: 3: 4: 5: |
|
This evaluates without returning anything interesting. Now, we can evaluate an expression
that returns an int
:
1: 2: 3: 4: |
|
|
When HTML printer is registered for a type, the details
field will incldue the result of calling the
HTML printer in the html
field. You can see that we got "<b>42</b>"
here! The Seq.empty
parameter
here specifies that no additional styles or scripts are required - for more information, see the
AddHtmlPrinter documentation page.
Wrapping up
Do not forget to kill the FsInteractiveService.exe
process at the end...
1:
|
|
namespace FSharp
--------------------
namespace Microsoft.FSharp
namespace FSharp.Data
--------------------
namespace Microsoft.FSharp.Data
Full name: Http.root
Full name: Http.fsiservice
type ProcessStartInfo =
new : unit -> ProcessStartInfo + 2 overloads
member Arguments : string with get, set
member CreateNoWindow : bool with get, set
member Domain : string with get, set
member EnvironmentVariables : StringDictionary
member ErrorDialog : bool with get, set
member ErrorDialogParentHandle : nativeint with get, set
member FileName : string with get, set
member LoadUserProfile : bool with get, set
member Password : SecureString with get, set
...
Full name: System.Diagnostics.ProcessStartInfo
--------------------
ProcessStartInfo() : unit
ProcessStartInfo(fileName: string) : unit
ProcessStartInfo(fileName: string, arguments: string) : unit
type Process =
inherit Component
new : unit -> Process
member BasePriority : int
member BeginErrorReadLine : unit -> unit
member BeginOutputReadLine : unit -> unit
member CancelErrorRead : unit -> unit
member CancelOutputRead : unit -> unit
member Close : unit -> unit
member CloseMainWindow : unit -> bool
member EnableRaisingEvents : bool with get, set
member ExitCode : int
...
Full name: System.Diagnostics.Process
--------------------
Process() : unit
Process.Start(fileName: string) : Process
Process.Start(fileName: string, arguments: string) : Process
Process.Start(fileName: string, userName: string, password: System.Security.SecureString, domain: string) : Process
Process.Start(fileName: string, arguments: string, userName: string, password: System.Security.SecureString, domain: string) : Process
private new : unit -> Http
static member private AppendQueryToUrl : url:string * query:(string * string) list -> string
static member AsyncRequest : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?responseEncodingOverride:string * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) -> Async<HttpResponse>
static member AsyncRequestStream : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) -> Async<HttpResponseWithStream>
static member AsyncRequestString : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?responseEncodingOverride:string * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) -> Async<string>
static member private InnerRequest : url:string * toHttpResponse:(string -> int -> string -> string -> string -> 'a0 option -> Map<string,string> -> Map<string,string> -> Stream -> Async<'a1>) * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?responseEncodingOverride:'a0 * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) -> Async<'a1>
static member Request : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?responseEncodingOverride:string * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) -> HttpResponse
static member RequestStream : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) -> HttpResponseWithStream
static member RequestString : url:string * ?query:(string * string) list * ?headers:seq<string * string> * ?httpMethod:string * ?body:HttpRequestBody * ?cookies:seq<string * string> * ?cookieContainer:CookieContainer * ?silentHttpErrors:bool * ?responseEncodingOverride:string * ?customizeHttpRequest:(HttpWebRequest -> HttpWebRequest) -> string
Full name: FSharp.Data.Http
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.async
type Async
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task -> Async<unit>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken
Full name: Microsoft.FSharp.Control.Async
--------------------
type Async<'T>
Full name: Microsoft.FSharp.Control.Async<_>
type Thread =
inherit CriticalFinalizerObject
new : start:ThreadStart -> Thread + 3 overloads
member Abort : unit -> unit + 1 overload
member ApartmentState : ApartmentState with get, set
member CurrentCulture : CultureInfo with get, set
member CurrentUICulture : CultureInfo with get, set
member DisableComObjectEagerCleanup : unit -> unit
member ExecutionContext : ExecutionContext
member GetApartmentState : unit -> ApartmentState
member GetCompressedStack : unit -> CompressedStack
member GetHashCode : unit -> int
...
Full name: System.Threading.Thread
--------------------
System.Threading.Thread(start: System.Threading.ThreadStart) : unit
System.Threading.Thread(start: System.Threading.ParameterizedThreadStart) : unit
System.Threading.Thread(start: System.Threading.ThreadStart, maxStackSize: int) : unit
System.Threading.Thread(start: System.Threading.ParameterizedThreadStart, maxStackSize: int) : unit
System.Threading.Thread.Sleep(millisecondsTimeout: int) : unit