pimbrouwers / falco Goto Github PK
View Code? Open in Web Editor NEWA toolkit for building fast and functional-first web applications using F#.
Home Page: https://www.falcoframework.com
License: Apache License 2.0
A toolkit for building fast and functional-first web applications using F#.
Home Page: https://www.falcoframework.com
License: Apache License 2.0
I'm currently using OrchardCore to build a SaaS platform, and it relies exclusively on C# MVC using .NET Core. It uses a system that pulls Startup
classes from any referenced class libraries ("modules") and merges together their content. Specifically, each Startup mounts endpoints using an IEndpointRouteBuilder
with calls to MapAreaControllerRoute
which all have to specify exact details like the controller, the action, the area, the pattern, etc.
I've been trying to see if I can use F# from start to finish in creating a basic module, but I have to fully emulate the experience of using MVC. That is...
Task<IActionResult>
, and if it's a View, then it gets embedded within a larger View powered by a configurable Theme system in OrchardCore.I can't really use Giraffe since it just writes content to the response directly (which would disregard the Theme system). It also only supports Microsoft's endpoint stuff in it's most recent alpha builds, so meh. Falco, on the other hand, is built entirely with seamless integration of AspNetCore in mind, so I'm hoping you have suggestions on how I might approach this.
I figure I could write some sort of HttpHandler that registers the endpoints along with the appropriate metadata. Then, it's just a matter of figuring out how to take an HTML string and directly inject it into an inline View that is picked up by Razor and used in OC's theme system.
Is there a way to integrate OpenAPI docs, like say Swashbuckle?
I've been thinking here, could we add support for the library consumer to register his own JsonSerializerOptions from the Services collection?
Say he has his own settings to apply for JSON parsing or has another library to be used in place. We could look for a JsonSerializerOptions from the services and use that instead of Constants.defaultJsonOptions
if it exists.
Thereβs a typo in a link on https://www.nuget.org/packages/Falco/4.0.0
Uniform API for [accessing request data](https://github.com/pimbrouwers/Falco/tree/master/doc/re uest.md).
Hello,
I am following the steps here: https://www.falcoframework.com/#getting-started
I run the following steps:
I get this error message
Template name "Falco" (falco) from author "Pim Brouwers, Daniel Tuna and contributors" in pack Falco.Template
To use this template, run the following command and try again:
dotnet new -i Falco.Template::3.0.0`
I have tried VSCode and Visual Studio as well.
Please help.
Could you enable the Discussions
page? So that users can ask questions that are not issues
When doing handler composition, there seems to be a regression in Falco 4 which causes the handler to not respond correctly (200 OK with empty body). This however, works as expected in Falco 3
You can view a repro here: https://github.com/sheridanchris/FalcoRepro
You'll notice in the repro there's a do! Task.Delay(...)
in both versions. If you remove this from the Falco 4.0 version it seems to work fine (if that gives you any hints).
Hi Pim. Thanks for putting time on Falco. I'm new to both F# and Falco and I'm learning through creating stuff π . One question I have is how do I render .html static files and edit the attributes and elements/nodes in Falco or something like template rendering.
How do you feel about providing a resource builder?
Currently there is no way to activate configuration files (appsettings.json)
A typical webhost builder:
WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.Configure(configureApp)
.ConfigureServices(configureServices)
.ConfigureLogging(configureLogging)
.UseConfiguration(config) // this is missing
.Build()
.Run()
The latest version of the library is 4.0.3 on NuGet, but the latest tag/release on GitHub is 3.1
Since there's no CHANGELOG.md in the repository, it can be confusing trying to identify
The Releases page for the repository is commonly used to help developers understand when new releases and what the changes were for each version. It can be really helpful for new developers trying to orient themselves in the repository/versioning history.
Could the Releases/Tags be updated for Falco to reflect that 4.0.3 is the latest and what changes are in it since 3.1 (even if you just summarize the changes).
Thanks!
Clicking on the first random link, dead:
There are dead link checkers. It looks very unprofessional for a web framework, it your own webpage is not even able to maintain links.
Dead Link: https://github.com/pimbrouwers/Falco/tree/master/docs/en/markup.html
https://www.falcoframework.com/
Key features:
Native F# view engine.
Hi, this project looks great, but what i'd really love to see would be comparison with existing & popular web frameworks like Giraffe and Suave.
Also, it would be nice to include some benchmarks - one of core feature of .net platform is it's speed.
Thanks for your work & keep it up!
Hi Pim,
After Ben Gobeil's great introduction to Falco (https://www.youtube.com/watch?v=DTy5gIUWvpo), I decided to take a closer look at your repo.
I especially liked your blog example where you use markdown and YAML frontmatter for the content (https://github.com/pimbrouwers/Falco/tree/master/samples/Blog). This approach might be a good way to convert a tiny PHP site of mine (http://www.zp-tec.com) and use it a training ground to sharpen my F# skills.
OK, now to my question:
The new version of my site will be multilingual, so all URLs of the second language have to be prefixed the with country code like this: /<country_code>/path/to/slug/.
How do I do this with Falco? Do I need to add the prefix to every slug manually, or is there some concept of nested routing like in Saturn? Or any other way to deal with multilanguage URLs?
For example, Saturn has something like nested routes (https://saturnframework.org/explanations/routing.html), but Falco's route
and all
functions in Routing.fs
don't seem to have this feature.
I also read Microsoft's article about endpoint routing you link to on your README page, but couldn't find a solution there either. That said, although I feel more and more comfortable programming in F#, I've never done anything with ASP.NET.
Have a good day!
Stefan
Proposing that a computation be created to simplify the process of creating the webhost.
webhost {
logging (fun options-> ...
services (fun services -> ...
activateWhen isDevelopment (fun app -> ...
activate (fun app -> ...
}
I am trying falco with swagger. Because recently I read some post that swaggert now support .net 6 endpoint routing start from preview 6. But unfortuatly it is not working with falco endpoint.
Below is the demo code:
open System
open System.Threading.Tasks
open Microsoft.AspNetCore.Http
open Microsoft.AspNetCore.Builder
open Microsoft.Extensions.DependencyInjection
open Falco
open Falco.Routing
let builder = WebApplication.CreateBuilder()
builder.Services.AddEndpointsApiExplorer()
builder.Services.AddHttpContextAccessor() |> ignore
builder.Services.AddSwaggerGen() |> ignore
let application = builder.Build()
application.UseSwagger() |> ignore
application.UseFalcoEndpoints [
get "/" (Response.ofPlainText "Hello World")
]
// not working
// falco will call toRequestDelegate to convert handler into RequestDelegate which will erase the return type wrapped in Task
// if we can find a way to change to Func<_, _> style with more type info then we can integrate with swagger
application.MapGet("/hello1", RequestDelegate(fun (ctx: HttpContext) -> Task.FromResult $"Hi {ctx.Request.Path}" :> Task)) |> ignore
// working
application.MapGet("/hello2", Func<_, _>(fun (ctx: HttpContext) -> $"Hi {ctx.Request.Path}")) |> ignore
application.UseSwaggerUI() |> ignore
application.Run()
Out of curiosity, why does this project contain another F# view engine? In other words, how does this one differ from the ones in Fable, Giraffe, etc.?
Hello, what follows is just a nitpick from browsing the code. Feel free to disregard and close if it's not relevant.
I was having a look at the library and noticed that the namespace handling AntiForgeryTokens was named "XSS".
Most of the time I see such a module named something to do with CSRF rather than XSS, since the responsibility of the AntiForgeryTokens is to prevent Cross-Site Requests. While Cross-Site Requests could be triggered by an XSS attack triggering an ajax form request, the scope of XSS is much more broad in it's scope (reflected vs stored vs DOM), and the defenses have more to do with output sanitization/encoding ("safe sinks") rather than input origin verification.
On this line,
Line 237 in f2c5753
The link is broken when clicking.
function composition is spelled function compoistion
Hi, would it be possible to combine multiple class attributes the way Elm does it?
I'm using tailwindcss and usually define some helper functions for commonly used components e.g.:
let button (attrs : list<XmlAttribute>) =
Elem.button (
Attr.class' "border rounded px-4 py-2 bg-blue-500 text-white"
:: attrs
)
let wideButton =
button [ Attr.class' "w-64" ]
Unfortunately this doesn't work at the moment because only the first class attribute will be used by the browser. Do you think this would be a useful feature?
Also thank you for creating Falco!
I have a very strange bug. I am unable to serialize an object. I am using https://github.com/DataTables/Editor-NET. I am able to wire up all the request info properly and I have even been able to serialize single fields of the DtResponse object, but not the object itself. There's no errors and I'm kind of unsure as to what's happening. I tried looking over the code for projects but I don't really see anything that would cause the object to not serialize.
One thing I did notice in my research is that the ".Flush()" method is overridden on MemoryStream so calling it in the serialize function doesn't do anything according to: https://docs.microsoft.com/en-us/dotnet/api/system.io.memorystream.flush?view=net-6.0.
I'm new to F#. I've setup VS code with Ionide, it works well.
But I also would like to try Visual Studio, and can't connect it with Falco for debugging (server doesn't start), could you help please?
Suggestion: in the configuration builder add the ability to use user secrets.
I'm working with Falco and a SPA that needs to call different services.
Thus I need CORS enabled on each of them.
As I did not find CORS support in Falco yet and I think it's useful to have I propose extending the webHost CE accordingly.
I'll work on a PR for the feature.
Hello,
I think it can be useful to extract this code
Lines 157 to 170 in 235a062
in another extension method to do it manually and be more compatible with existing C# endpoint extension like this :
app
.UseBlazorFrameworkFiles()
.UseRouting()
.UseEndpoints(fun e ->
e.UseFalcoEndpoints(endpoints) // <- new extension
e.UseHotReload() |> ignore
e.MapBlazorHub() |> ignore
e.MapFallbackToPage("/_Host") |> ignore)
If you ok I can also do this in a PR π
Hi @pimbrouwers, do you have a barebones Dockerfile you'd recommend for Falco?
For some context: New to Falco and F#. I come from the Node/JS world. This file seems reasonable.
With .NET 5.0 finally here, it seems like a good time to begin exploring v3.x.x which will support both the netcoreapp3.1
and net5.0
build targets.
In saying that, this is a great opporunity to include any new features and/or breaking changes to the API. Included so far:
[<AutoOpen>]
attribute in the routing module to prevent polluting the global scopeSo, if you're a user of Falco and you have some ideas, I want to hear from you!
Credit goes to @pblasucci for pointing this out.
Would you be interested in some static website documentation π?
something like this it's basically a Fornax "blog"
my UI design skills are atrocious as you can see but I can help you setting it up and pushing content if you like the idea
Hey there! I was browsing over the Crypto
file and I noticed you had a randomInt
function.
Lines 16 to 17 in bce4852
Since this a Crypto
module, I think this should use RNGCryptoServiceProvider. Luckily it's an easy swap, since dotnet core 3.0 they've added a easy helper function to replicate the Int32 generation with the RandomNumberGenerator.GetInt32
API.
code in https://www.falcoframework.com/#host-builder is not working
Error, Now
let configureWebHost : HttpEndpoint list -> IWebHostBuilder =
To be
let configureWebHost : HttpEndpoint list -> IWebHostBuilder -> IWebHostBuilder =
Tabling this discussion since there's enough of us now using, or at least watching this project from a distance.
I originally wrote the comp expr for the web host to avoid the need for so much boiler plate code around creating a new web host. I'm beginning to feel as though I'm not a fan of hiding away the complexity, and the additional API that now needs to be maintained.
So what do you think?
The cols attribute function is not present in Falco.Markup.Attr module, used by textarea element.
Hey Pim
are there any plans for integrating with a template engine?
A lot of my frontend work is just copy paste from various sites and having support for html syntax would be great.
Opening the floor to ideas for sample projects.
We currently have:
Some of my ideas:
Hey, I just discovered Falco and it looks pretty neat! I'll try to give it a run on the following days
I just have a question about JSON serialization/deserialization I saw that you are using the System.Text.Json API's
I believe I tried those previously in another project but ran into exceptions once I tried to deserialize option types as well as Discriminated Unions, with that in mind
Is it safe to just deserialize json?
if not, you might want to consider taking a look at
https://github.com/Tarmil/FSharp.SystemTextJson
which uses the same API's but with some F# sugar for those mentioned types
Consider:
[<Fact>]
let ``StringCollectionReader value lookups are case-insensitive`` () =
let values =
[
"FString", [|"John Doe"; "Jane Doe"|] |> StringValues
]
|> Map.ofList
|> fun m -> Dictionary(m)
let scr = StringCollectionReader(values)
// single values
scr.TryGet "FSTRING" |> Option.iter (should equal "John Doe")
scr.TryGet "FString" |> Option.iter (should equal "John Doe")
scr.TryGet "fstriNG" |> Option.iter (should equal "John Doe")
scr?FSTRING.AsString() |> should equal "John Doe"
scr?FString.AsString() |> should equal "John Doe"
scr?fstrINg.AsString() |> should equal "John Doe"
// arrays
scr.TryArrayString "FSTRING" |> Option.iter (should equal [|"John Doe";"Jane Doe"|])
scr.TryArrayString "fString" |> Option.iter (should equal [|"John Doe";"Jane Doe"|])
scr.TryArrayString "fstriNG" |> Option.iter (should equal [|"John Doe";"Jane Doe"|])
scr?FSTRING.AsArrayString() |> should equal [|"John Doe";"Jane Doe"|]
scr?fString.AsArrayString() |> should equal [|"John Doe";"Jane Doe"|]
scr?fstriNG.AsArrayString() |> should equal [|"John Doe";"Jane Doe"|]
I think there's an error in the code sample under the heading "Combining views to create complex output". It currently reads:
// Template
let master (title : string) (content : XmlNode list) =
Elem.html [ Attr.lang "en" ] [
Elem.head [] [
Elem.title [] [ Text.raw "Sample App" ]
]
Elem.body [] content
]
That hard-codes the page title to "Sample App", whereas if I'm right(?) it should use the title
parameter. Corrected code:
// Template
let master (title : string) (content : XmlNode list) =
Elem.html [ Attr.lang "en" ] [
Elem.head [] [
Elem.title [] [ Text.raw title ]
]
Elem.body [] content
]
Happy to submit a PR though realise it's a trivial change so might be overkill. Thanks.
Falco and dotnet newbie here, so apologies if this is mistaken.
The redirect docs suggest there are two functions, one each for perm and temp redirects. However, the examples don't compile using Falco 3.1.14 & Fsharp.Core 7.0.0. I think the examples should be as follows:
let oldUrlHandler : HttpHandler =
Response.redirect "/new-url" true
let redirectUrlHandler : HttpHandler =
Response.redirect "/new-url" false
Hope that helps. As an aside, I'm really enjoying the Falco "on ramp" experience. Thanks for all your hard work.
Hello, I've noticed a small issue here:
https://github.com/pimbrouwers/Falco/blob/master/doc/routing.md
open Falco
open Falco.Routing
open Falco.HostBuilder
webHost [||] {
endpoints [
get "/hello/{name:alpha}" (fun ctx ->
let route = Request.getRoute ctx
let name = route.GetString "name" "" // <- This Doesn't compile for me
let message = sprintf "Hello %s" name
Response.ofPlainText message ctx)
]
}
However this is completely fine:
webHost [||] {
endpoints [
get "/hello/{name:alpha}" (fun ctx ->
let route = Request.getRoute ctx
let name = route.GetString ("name", "") // Change to tupled parameters made here
let message = sprintf "Hello %s" name
Response.ofPlainText message ctx)
]
}
The route binding example from here: https://www.falcoframework.com/docs/request.html#route-binding
Is completely fine and uses a simplified version, like this:
open Falco
// Assuming a route pattern of /{Name}
let manualRouteHandler : HttpHandler = fun ctx ->
let r = Request.getRoute ctx
let name = r.GetString "Name"
Response.ofPlainText name ctx
let mapRouteHandler : HttpHandler =
Request.mapRoute (fun r ->
r.GetString "Name")
Response.ofPlainText
Which would translate our first example to something like this:
webHost [||] {
endpoints [
get "/hello/{name:alpha}" (fun ctx ->
let route = Request.getRoute ctx
let name = route.GetString "name"
let message = sprintf "Hello %s" name
Response.ofPlainText message ctx)
]
}
That would be one of my suggestion the other is using a working tupled example in a more descriptive way:
webHost [||] {
endpoints [
get "/hello/{name:alpha}" (fun ctx ->
let route = Request.getRoute ctx
let name = route.GetString ("name", "FalcoEnthusiast") // Could be "defaultValue", "fallbackValue"
let message = sprintf "Hello %s" name
Response.ofPlainText message ctx)
]
}
But my question is will it ever be an empty string here? Maybe the fallback value is never needed in this example?
I would be very happy to make a PR for that, but it is also a trivial change so might be an overkill.
Have a great New Year Pim and everyone! :)
I was wondering how you configure the host to use a different port? It seems like it would be a useful feature in the CE for webHost.
Good day, I'd like to create a web service, which should use http2 protocol. How to do it? 1) put Nginx with http2 at front of Falco, or 2) setup Kestrel with http2 support? If 2 is preferable, how to setup Kestrel from Falco? Thanks in advance.
https://github.com/pimbrouwers/Falco/blob/master/src/Falco/Request.fs#L302
you forgot to call next
Hello,
how do I assign function to button's onClick in Falco?
I am attempting something like: let button = Elem.button [ Attr.onClick (fun _ -> xxxx) ] [ ]
but it does not exist. I was looking into Falco source code for something like onClick but I have not found anything.
Should look something like:
let _placeholder v = attr "placeholder" (Some v)
Hi all, I'm discovering Falco and going through the samples.
I tried the following:
[<EntryPoint>]
let main args =
webHost args {
use_if FalcoExtensions.IsDevelopment DeveloperExceptionPageExtensions.UseDeveloperExceptionPage
use_ifnot FalcoExtensions.IsDevelopment (FalcoExtensions.UseFalcoExceptionHandler exceptionHandler)
endpoints [
get "/" (Response.ofPlainText "Hello world")
get "/hello/{name:alpha}" (Request.mapRoute (fun route -> route.GetString "name" "") Response.ofPlainText)
get "/form" (Response.ofHtml form)
post "/form" (Response.debugRequest)
]
}
I'm getting the following error when I compile:
Program.fs(34, 36): [FS0039] The value, constructor, namespace or type 'debugRequest' is not defined.
I'm running the version:
<ItemGroup>
<PackageReference Include="Falco" Version="3.1.*" />
</ItemGroup>
i can clearly find the function debugRequest
on the source code on the latest release and does not seem to find any commit that removed it... weird...
I'm running on Mac OS M1. Can this be related?
Thank for any help
It's really confusing to use without the param names in the signature.
Hello guys.
I'm having trouble adding Dapper to Falco.
Do you have any code example?
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.