Azure Static Web Apps with Sapper + Azure Functions

In the last post, I walked through setting up a simple Sapper application on Microsoft’s new Azure Static Web Apps. In this post, I’ll walk through my experience adding and deploying an Azure Functions API.

TL;DR Azure Static Web Apps currently only supports Azure Functions v3 with Node.js v12 and HttpTrigger bindings for APIs. See the docs.

Continue reading
Advertisement

A New Web for .NET

A number of things have been happening these last few years in the .NET community in relation to the Web. Specifically, OpenRasta and FubuMvc demonstrated 1) new approaches to web development in a static-typed world and 2) that other developers were growing tired of the existing options. Since then a host of new micro-frameworks, generally inspired by the Ruby dynamic duo of Rack and Sinatra, have popped up on github. In addition, several new server options have begun cropping up, most notably Kayak and Manos de Mono, both of which use an event loop a la node.js and primarily targeting Mono.

Microsoft has not be sitting idly by either. The WCF team is working on a new Web API to provide WCF developers simpler, more direct control over HTTP services. This is no slouch effort either. In fact, aside from OpenRasta, it may be the most thorough HTTP implementation available.

While exciting on their own, the best news, imho, is the .NET HTTP Abstractions group, started by Scott Koon. This group has been working on a standard, currently called Open Web Interface for .NET, or OWIN. It’s intent is to define a common interface by which any application can talk to any server. The idea comes from the Web Server Gateway Interface (Python) and Rack. The primary difference in this and other similar specs is the inclusion of asynchronous network I/O as a primary concern. Discussions are still underway and include nearly all of the developers of the aforementioned projects, as well as some members of the ASP.NET team.

If you are a F# fanboy, such as myself, you will be happy to know that F# is not silent in this space. WebSharper is now in its second iteration, and my own projects, Frack and Frank, are making nice headway. Frack is now a web server, similar in spirit to node.js. Frank is, as the name implies, a Sinatra-inspired clone that takes cues from the Haskell Snap framework. If you are interested in parsing and agent-based development, you’ll find more examples of how F# handles these things as these two projects progress.

Expect to find more posts (shock!) coming soon describing in more detail the WCF Web APIs, OWIN, Frack, Frank, and more. In the meantime, join the discussion on the .NET HTTP Abstractions group!

Programming the Semantic Web With F#

I’m currently reading O’Reilly’s Programming the Semantic Web (when I have a chance), and I decided I would try the samples in F# instead of Python. Why? Well, 1) I love F#, and 2) I want to see how closely the two languages really are related. They seem very much related syntactically, and I’m finding that’s somewhat true. Either way, it’s fun, I get to explore several things I’m interested in at once, and it still (loosely) relates to all the other stuff I have going on. 🙂 Anyway, here’s some snippets from Chapter 2. If you have feedback or fixes, please feel free to share!


namespace SemanticWeb
open System
open System.Collections.Generic
open System.IO
open System.Text
open Kent.Boogaart.KBCsv
/// A simple triple store
type SimpleGraph(spo: Map<string, Map<string, Set<string>>>,
pos: Map<string, Map<string, Set<string>>>,
osp: Map<string, Map<string, Set<string>>>) =
/// Adds a triple to the specified index.
let addToIndex index (a, b, c) =
// TODO: Could this be simpler with Active Patterns?
match Map.tryFind a index with
| None -> index |> Map.add a (Map.ofList [(b, Set.ofList [c])])
| Some(indexA) -> match Map.tryFind b indexA with
| None -> index |> Map.add a (indexA |> Map.add b (Set.ofList [c]))
| Some(indexB) -> index |> Map.add a (indexA |> Map.add b (indexB |> Set.add c))
/// Removes a triple from the specified index.
let removeFromIndex (index: Map<string, Map<string, Set<string>>>) (a, b, c) =
try
let bs = index.[a]
let cset = bs.[b]
let newCset = cset |> Set.remove c
let newBs = bs |> if Set.isEmpty newCset then Map.remove b else Map.add b newCset
index |> if Map.isEmpty newBs then Map.remove a else Map.add a newBs
with
| :? KeyNotFoundException -> index
/// Retrieves tripes based on a filter. (None, None, None) returns all.
let triples (sub, pred, obj) =
// TODO: Could this be simpler with Active Patterns?
try
seq { match sub with
| Some(s) -> match pred with
| Some(p) -> match obj with
| Some(o) -> if spo.[s].[p].Contains(o) then yield (s, p, o)
| None -> for retObj in spo.[s].[p] do yield (s, p, retObj)
| None -> match obj with
| Some(o) -> for retPred in osp.[o].[s] do yield (s, retPred, o)
| None -> for KeyValue(retPred, objSet) in spo.[s] do
for retObj in objSet do
yield (s, retPred, retObj)
| None -> match pred with
| Some(p) -> match obj with
| Some(o) -> for retSub in pos.[p].[o] do yield (retSub, p, o)
| None -> for KeyValue(retObj, subSet) in pos.[p] do
for retSub in subSet do
yield (retSub, p, retObj)
| None -> match obj with
| Some(o) -> for KeyValue(retSub, predSet) in osp.[o] do
for retPred in predSet do
yield (retSub, retPred, o)
| None -> for KeyValue(retSub, predSet) in spo do
for KeyValue(retPred, objSet) in predSet do
for retObj in objSet do
yield (retSub, retPred, retObj)
}
with
| :? KeyNotFoundException -> Seq.empty
/// A simple triple store
new() = SimpleGraph(Map.empty, Map.empty, Map.empty)
/// Add a new triple
member this.Add(sub, pred, obj) =
let newSpo = addToIndex spo (sub, pred, obj)
let newPos = addToIndex pos (pred, obj, sub)
let newOsp = addToIndex osp (obj, sub, pred)
SimpleGraph(newSpo, newPos, newOsp)
/// Remove a triple
member this.Remove(sub, pred, obj) =
let removeFromIndices (oldSpo, oldPos, oldOsp) (delSub, delPred, delObj) =
let newSpo = removeFromIndex oldSpo (delSub, delPred, delObj)
let newPos = removeFromIndex oldPos (delPred, delObj, delSub)
let newOsp = removeFromIndex oldOsp (delObj, delSub, delPred)
(newSpo, newPos, newOsp)
let trips = triples (sub, pred, obj)
let newSpo, newPos, newOsp = trips |> Seq.fold (removeFromIndices) (spo, pos, osp)
SimpleGraph(newSpo, newPos, newOsp)
/// Load triples from a csv file
member this.Load(filename: string) =
let loader (graph: SimpleGraph) (line: string []) =
graph.Add(line.[0], line.[1], line.[2])
use rdr = new CsvReader(filename, Encoding.UTF8)
rdr.DataRecordsAsStrings |> Seq.fold loader (SimpleGraph())
/// Save triples back to a csv file
member this.Save(filename: string) =
let trips = triples (None, None, None)
|> Seq.map (fun (sub, pred, obj) -> [| sub; pred; obj |])
use wtr = new CsvWriter(filename, Encoding.UTF8)
trips |> Seq.iter (wtr.WriteDataRecord)
/// Queries triples based on options.
member this.Triples(sub, pred, obj) = triples(sub, pred, obj)
/// Retrieves a single value from a triple using None. All other values must be specified.
member this.Value(sub, pred, obj) =
triples (sub, pred, obj)
|> Seq.pick (fun (retSub, retPred, retObj) ->
if Option.isNone sub then Some(retSub)
elif Option.isNone pred then Some(retPred)
elif Option.isNone obj then Some(retObj)
else None)

view raw

SimpleGraph.fs

hosted with ❤ by GitHub


#r "..\KBCsv-1.2.0.0-bin\Kent.Boogaart.KBCsv.dll"
#load "SimpleGraph.fs"
open SemanticWeb;;
printfn "*** SimpleGraph tests ***";;
let mutable g = SimpleGraph();;
g <- g.Add("blade_runner", "name", "Blade Runner");;
g <- g.Add("blade_runner", "name", "Blade Runner");;
g <- g.Add("blade_runner", "release_date", "June 25, 1982");;
g <- g.Add("blade_runner", "directed_by", "Ridley Scott");;
g.Triples(None, None, None) |> Seq.toList |> printfn "%A";;
g.Triples(Some("blade_runner"), None, None) |> Seq.toList |> printfn "%A";;
g.Triples(Some("blade_runner"), Some("name"), None) |> Seq.toList |> printfn "%A";;
g.Triples(Some("blade_runner"), Some("name"), Some("Blade Runner")) |> Seq.toList |> printfn "%A";;
g.Triples(None, Some("name"), Some("Blade Runner")) |> Seq.toList |> printfn "%A";;
g.Triples(None, None, Some("Blade Runner")) |> Seq.toList |> printfn "%A";;
printfn "\n*** Business Triples ***";;
let bg = SimpleGraph().Load(@"C:\Users\ryan\dev\SemanticWeb\business_triples.csv");;
let ibanks = bg.Triples(None, Some("industry"), Some("Investment Banking")) |> Seq.take 10 |> Seq.toList;;
printfn "%A" ibanks;;
printfn "\n*** Take one value ***";;
let labIndustry = bg.Value(Some("LAB"), Some("industry"), None);;
printfn "%A" labIndustry;;

Tutorial D in F#

Does anyone know of a project to implement Tutorial D in F#, similar to the Dee project for Python? I’m currently trying to get Dee working on IronPython, which would get me closer to my goal of using a true relational model for data access. I would like to stick with a .NET implementation, so that leaves out Rel. I have tried Dataphor, but I find it trying to be too much a complete platform and not easy to use as just a utility. I think either a good C# or F# implementation would be both excellent to have and a fun project on which to work. Anyone interested?