Thoth.Fetch
This documentation is for Thoth.Fetch v2, documentation for older versions can be found here:
Usage
Thoth.Fetch provides an easy to use API for working with Fable.Fetch and Thoth.Json. It supports both manual and auto coders depending on your preferences.
For each method, it provides a safe and an unsafe version.
We call safe a method which returns a Result<'T, FetchError>.
We call unsafe a method that will throw an exception when a coder fails.
List of "unsafe" methods:
- fetchAs
- get
- post
- put
- patch
- delete
List of "safe" methods:
- tryFetchAs
- tryGet
- tryPost
- tryPut
- tryPatch
- tryDelete
Successful request
A request is successful if no error case has been encounter. There is one exception to this rule which is unit request.
In the case of unit, Thoth.Fetch will consider the request valid if it gets a result from the server. It means it doesn't validate the body content.
It is useful if you want to send a request to the server and want to ignore the result.
Example:
promise {
// ...
do! Fetch.post("https://my-servver.com/log", "Some data to log")
// or
do! Fetch.delete("https://my-servver.com/user/2")
// or
let! res = Fetch.delete("https://my-servver.com/user/2")
// res value is ()
// ...
}Errored request
Thoth.Fetch can return different errors:
If an exception occured by preparing the request, you will get
PreparingRequestFailedwith theexceptionas an argument.If there was an error during the request execution, you will get
NetworkErrorwith theexceptionas an argument.If we received a result but the
statusCodewas not ok (outside of the range 200-299), you will getFetchFailedwith the rawresponseas an argument.If we received a result but
Thoth.Jsondecoding failed, you will getDecodingFailedwith the error message as an argument.
Manual coders
Example
Define your decoder, encoder, and extracoder
open Thoth.Fetch
open Thoth.Json
open System
/// Type representing our ressource
type Book =
{ Id : int
Title : string
Author : string
CreatedAt : DateTime
UpdatedAt : DateTime option }
/// Transform a Book from JSON
static member Decoder =
Decode.object (fun get ->
{ Id = get.Required.Field "id" Decode.int
Title = get.Required.Field "title" Decode.string
Author = get.Required.Field "author" Decode.string
CreatedAt = get.Required.Field "createdAt" Decode.datetime
UpdatedAt = get.Optional.Field "updatedAt" Decode.datetime }
)
/// Transform JSON as Book
static member Encoder (book : Book)=
Encode.object [
"id", Encode.int book.Id
"title", Encode.string book.Title
"author", Encode.string book.Author
"createdAt", Encode.datetime book.CreatedAt
"updatedAt", Encode.option Encode.datetime book.UpdatedAt
]
let bookCoder: ExtraCoders = Extra.empty
|> Extra.withCustom Book.Encoder Book.DecoderGET request
let getBookById (id : int) =
promise {
let url = sprintf "http://localhost:8080/books/%i" id
return! Fetch.get(url, decoder = Book.Decoder)
}POST request
let createBook (book : Book) =
promise {
let url = "http://localhost:8080/books/"
let data =
Encode.object [
"title", Encode.string book.Title
"author", Encode.string book.Author
"createdAt", Encode.datetime book.CreatedAt
"updatedAt", Encode.option Encode.datetime book.UpdatedAt
]
return! Fetch.post(url, data, decoder = Book.Decoder)
}PUT request
let updateBook (book : Book) =
promise {
let url = "http://localhost:8080/books/"
let data =
Encode.object [
"id", Encode.int book.Id
"title", Encode.string book.Title
"author", Encode.string book.Author
"createdAt", Encode.datetime book.CreatedAt
"updatedAt", Encode.option Encode.datetime book.UpdatedAt
]
return! Fetch.put(url, data, decoder = Book.Decoder)
}DELETE request
let deleteBook (book : Book) : JS.Promise<bool> =
promise {
let url = sprintf "http://localhost:8080/books/%i" book.Id
return! Fetch.delete()
}Auto coders
You need to help F# type inference determine which type is expected.
Here is two ways to do it, more exists but thuse are the simpler:
Type via the promise result
let getBookById (id : int) : JS.Promise<Book> =
promise {
let url = sprintf "http://localhost:8080/books/%i" id
return! Fetch.get(url, caseStrategy = CamelCase)
}
let createBook (book : Book) : JS.Promise<Book> =
promise {
let url = "http://localhost:8080/books/"
let data =
{| title = book.Title
author = book.Author
createdAt = book.CreatedAt
updatedAt = book.UpdatedAt |}
return! Fetch.post(url, data, caseStrategy = CamelCase)
}Type when calling Fetch method
let getBookById (id : int) =
promise {
let url = sprintf "http://localhost:8080/books/%i" id
return! Fetch.get<_, Book>(url, caseStrategy = CamelCase)
}
let createBook (book : Book) =
promise {
let url = "http://localhost:8080/books/"
let data =
{| title = book.Title
author = book.Author
createdAt = book.CreatedAt
updatedAt = book.UpdatedAt |}
return! Fetch.post<_, Book>(url, data, caseStrategy = CamelCase)
}Example
Define your type
open Fable.Core
open Thoth.Fetch
open System
/// Type representing our ressource
type Book =
{ Id : int
Title : string
Author : string
CreatedAt : DateTime
UpdatedAt : DateTime option }GET request
let getBookById (id : int) : JS.Promise<Book> =
promise {
let url = sprintf "http://localhost:8080/books/%i" id
return! Fetch.get(url, caseStrategy = CamelCase)
}POST request
let createBook (book : Book) : JS.Promise<Book> =
promise {
let url = "http://localhost:8080/books/"
let data =
{| title = book.Title
author = book.Author
createdAt = book.CreatedAt
updatedAt = book.UpdatedAt |}
return! Fetch.post(url, data, caseStrategy = CamelCase)
}PUT request
let updateBook (book : Book) : JS.Promise<Book> =
promise {
let url = "http://localhost:8080/books/"
let data =
{| id = book.Id
title = book.Title
author = book.Author
createdAt = book.CreatedAt
updatedAt = book.UpdatedAt |}
return! Fetch.put(url, data, caseStrategy = CamelCase)
}DELETE request
let deleteBook (book : Book) : JS.Promise<unit> =
promise {
let url = sprintf "http://localhost:8080/books/%i" book.Id
return! Fetch.delete(url)
}Keep control over Thoth.Json
When using auto coders, you can pass caseStrategy and/or extra arguments in order to control Thoth.Json behaviour. You can learn more about them by reading Thoth.Json documentation.