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
PreparingRequestFailed
with theexception
as an argument.If there was an error during the request execution, you will get
NetworkError
with theexception
as an argument.If we received a result but the
statusCode
was not ok (outside of the range 200-299), you will getFetchFailed
with the rawresponse
as an argument.If we received a result but
Thoth.Json
decoding failed, you will getDecodingFailed
with 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.Decoder
GET 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.