Utilities for Fable apps.
ATTENTION: Modules have been published as standalone packages (see #63). Fable.PowerPack won't receive more updates.
Utilities for Fable apps
Home Page: http://fable.io/fable-powerpack/
License: MIT License
Hi!
I'm currently working with PouchDB a JS based NoSQL browser database.
When inserting a new record I use promises:
promise {
let! r= db.put(o)
return r
}
|> Fable.PowerPack.Promise.map(fun response -> handler (Load response))
When this fails, PouchDB sends back an object with some interesting information, for instance the error status which would allow me to create a custom handler:
How can I get this object using Fable.PowerPack.Promise.catch
? Is it possible?
Thanks!
According to the spec, Promise.catch(f)
is sugar for Promise.then(id, f)
, which allows f : exn -> U2<'T, Promise<'T>>
, whereas the Fable.PowerPack's current implementations only allow f : exn -> 'T
.
To avoid breaking changes, I propose not to change the signatures of catch
and either
, but add two new functions, catchBind
and eitherBind
respectively:
[<Emit("$1.catch($0)")>]
let catchBind (a: Exception->Promise<'T>) (pr: JS.Promise<'T>): JS.Promise<'T> = jsNative
[<Emit("$2.then($0,$1)")>]
let eitherBind (success: 'T->'R) (fail: Exception->Promise<'R>) (pr: JS.Promise<'T>): JS.Promise<'R> = jsNative
(I'm not completely sure about the names - not a native English speaker myself - so if anyone has better ideas...)
So does patch, I imagine.
The specific use case is authentication header, but it would be true for any property: the merge of passed and default properties needs to prefer passed properties and use default only if not set explicitly (I could see myself using specific content-type
, for example, even if serialization method is json).
Just a reminder that I need to update the readme to follow the new build system.
The fetch
api can be used in node via node-fetch
.
node-fetch
exposes the following additional request options:
follow: 20, // maximum redirect count. 0 to not follow redirect
timeout: 0, // req/res timeout in ms, it resets on redirect. 0 to disable (OS limit applies)
compress: true, // support gzip/deflate content encoding. false to disable
size: 0, // maximum response body size in bytes. 0 to disable
agent: null // http(s).Agent instance, allows custom proxy, certificate etc.
Would it make sense to add these to RequestProperties
?
If so, I can send a PR.
Hi, this is a question / suggestion about adding more data to Date.Local:
Opinions? Go for it? I guess I can do it for the current locales.
CompositionalIT/SAFE-Dojo#26 details an issue that seems to be related to deserialization of response data coming back from a POST:
fetchAs<'T>
all works fine.postRecord
returns you a Response
object, which you can in turn call .json<'T>
on. This works for basic records, but when the response record contains a discriminated union, the deserialization fails..text() |> Promise.map ofJson<'T>
on the response instead of .json<'T>
.What is different between json<'T>
and ofJson<'T>
? I would have expected both to behave in the same way, and not to fail because there's a discriminated union in the record.
The issue linked above also contains a branch with a repro of this issue (see https://github.com/CompositionalIT/SAFE-Dojo/blob/post-serialization-issue/src/Client/app.fs#L62)
If I create and cache a promise, then it is re-executed each time I do a .then
.
A reproduction is here.
In that snippet, I create a Map<string, Promise<string>>
.
I would expect the promise to behave like the C# async
, be executed once, and further let!
to access the cached value.
Instead it behaves like the F# async
and is re-executed each time.
The workaround is to do a .then(id)
, and cache that.
In case of 5xx response, exception.Message
contains nothing useful:
The server is based on Akka-Http, and handler is as following:
val route: Route =
handleExceptions(exceptionHandler) {
path("account") {
post {
entity(as[AccountDto]) { account =>
complete(...a Future that can fail...)
}
}
} ~ ...
val exceptionHandler = ExceptionHandler {
case e: Exception =>
extractUri { uri =>
println(s"Request to $uri could not be handled normally: ${e.getMessage}")
complete(HttpResponse(StatusCodes.InternalServerError, entity = e.getMessage))
}
}
In short, what I need is get the following response body in case of 5xx response:
Is it possible?
let props =
[ RequestProperties.Method HttpMethod.POST
requestHeaders [ContentType "application/json"]
RequestProperties.Credentials RequestCredentials.Sameorigin
RequestProperties.Body !^ body ]
GlobalFetch.fetch(RequestInfo.Url url, requestProps props)
The server is a Giraffe one, which makes redirect:
routef "/api/foo/%s" (fun path -> redirectTo false (sprintf "http://localhost:8090/%s" path))
It works completely fine against http://localhost:8090/...
until I added the redirect.
This might be subjective, but according to certain API design guidelines, API namespace should include all the types required to work with it.
Currently I have to include Fetch_types
to do anything useful with Fetch API, which perhaps shouldn't be necessary?
Now that Fable is out of beta, PowerPack is the only "dev" release at this point that prevents me from publishing my packages as "stable" as well.
Sorry for noob question: what is the easy way to add custom headers in Fable.PowerPack.Fetch?
the following code doesn't compile (which is expected because I messed up types):
type ImageType =
| NoImage
| Image of string
let takePicture() = async { return Some "" }
let requestImageForConfirmation () = async {
match 1 with
| 2 ->
return ImageType.NoImage
| _ -> return! takePicture()
}
but the same version with promises does (but should not):
type ImageType =
| NoImage
| Image of string
let takePicture() = promise { return Some "" }
let requestImageForConfirmation () = promise {
match 1 with
| 2 ->
return ImageType.NoImage
| _ -> return! takePicture() // should fail here
}
Currently Promise.catch
and Promise.catchBind
emit $1.catch($0)
. This is the only point where anything except then
is used, and this makes PowerPack's promises incompatible with minimal implementations, such as VSCode's Thenable
.
This, in turn, forces us to do a conversion (aka "wrapper") when interacting with VSCode, which could be unnecessary if only PowerPack's Promise
relied solely on then
, in which case just a dirty cast !!x
would be sufficient.
The proposal is to make Promise.catch
and Promise.catchBind
emit $1.then(undefined, $0)
(per the spec) instead of the current $1.catch($0)
.
When I paste the example code from the json.md
file into a Fable
project the compiler complains that the unwrapResult
function and the result
computation expression are not defined.
Fable.PowerPack was born to provide a common set of utilities for Fable apps that weren't tied to the compiler (as it happens with Fable.Core). However it's now becoming a hotchpotch with modules that are (I believe) very rarely used. Moreover, fortunately we've now competing libraries that are well maintained and provide better solutions.
Let's say I start a project and want to use:
Besides the problem of package visibility (we need to solve this in fable-compiler/fable-compiler.github.io#32), users may wonder why they need to add the full Fable.PowerPack to use a small part of it. Technically it's not a problem, because tree-shaking will ensure that code not-used will stay out of the bundle, but PowerPack may convey the message to new users that it's an all-in solution, when currently it's not.
So the idea would be to split Fable.PowerPack modules in different packages: Fable.Promise, Fable.Fetch, etc, and let users take ownership of some modules if they want (or just let die those that are not really used). As Elmish 3 is in beta, we could also use the opportunity to replace the dependency of Fable.PowerPack.
I have the following code:
let submitForm (model:Model) dispatch =
fun (evt:React.FormEvent) ->
evt.preventDefault()
tryPostRecord "http://localhost:5000/invoices" model []
|> Promise.bind(fun result ->
match result with
| Ok response ->
response.text()
|> Promise.map(fun url -> PostResponse.Success url)
| Error err ->
err.???.json<string list>()
|> Promise.map(fun errors -> PostResponse.Errors errors)
)
|> Promise.map(fun (responseData) ->
match responseData with
| PostResponse.Success url ->
Browser.window.location.href <- url
()
| PostResponse.Errors errors ->
(UpdateErrors errors) |> dispatch
) |> ignore
My server returns a bad request (400) with a json array of strings containing everything that is wrong with the model. The Error err
is an exception so how do I get the response data?
A little document to do simple things would be good. As Fable is reaching 1.0 and not everyone like to read test cases. I guess document will surely help.
Date.Format.localFormat Date.Local.englishUS "h" (DateTime(2017,8,8,12,0,0))
produces "0" instead of "12".
I can make a PR with new tests and a fix if you want.
Hi,
I have been struggling to send some json data through a POST request using Fetch from a fable 2 project.
let withProps body=
[
requestHeaders [ContentType "application/json"]
RequestProperties.Mode RequestMode.Nocors
RequestProperties.Body !!body
]
let! result =
let props = body |> withProps
tryPostRecord url body props
or
let withProps body=
[
RequestProperties.Method HttpMethod.POST
requestHeaders
[
HttpRequestHeaders.ContentType "application/json"
]
RequestProperties.Mode RequestMode.Nocors
RequestProperties.Body !!body
]
body
|> withProps
|> fetch url
|> Promise.bind (fun res ->
res.text())
|> Promise.map (Decode.fromString decoder)
However, it seems that whatever the ContentType used, it will revert to text/plain;charset=UTF-8
.
I never had this problem with any of my Fable 1 projects.
So maybe I'm missing something?
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.