{"id":14805,"date":"2017-09-26T09:39:23","date_gmt":"2017-09-26T16:39:23","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/dotnet\/?p=14805"},"modified":"2019-06-20T16:12:31","modified_gmt":"2019-06-20T23:12:31","slug":"build-a-web-service-with-f-and-net-core-2-0","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/build-a-web-service-with-f-and-net-core-2-0\/","title":{"rendered":"Build a web service with F# and .NET Core 2.0"},"content":{"rendered":"<p>Earlier this year, I wrote about an <a href=\"https:\/\/blogs.msdn.microsoft.com\/dotnet\/2017\/08\/14\/f-and-net-core-roadmap-update\/\">update to the roadmap for F# and .NET Core<\/a>. I had mentioned that there were a number of things you could build with F# and .NET Core today, such as web services. In this post, I&#8217;ll walk through building a web service with F# and .NET Core 2.0 using the <a href=\"https:\/\/github.com\/dustinmoris\/Giraffe\">Giraffe library<\/a>.<\/p>\n<p>It&#8217;s also worth noting that Giraffe is not the only technology you can use to build web APIs. <a href=\"https:\/\/suave.io\/index.html\">Suave<\/a> and <a href=\"https:\/\/freya.io\/\">Freya<\/a> are two other great technologies that can be used on .NET Core. I encourage you to try each of them and see which you prefer.<\/p>\n<p>A complete application shown in this post is <a href=\"https:\/\/github.com\/cartermp\/GiraffeSample\">available on GitHub<\/a>.<\/p>\n<h2>Overview of Giraffe<\/h2>\n<p>Giraffe allows you to write web API routes in a functional style. Although F# is fully supported in ASP.NET Core MVC, Giraffe has a different technical philosphy which takes advantage of multiple F# features, such as <a href=\"https:\/\/en.wikibooks.org\/wiki\/F_Sharp_Programming\/Higher_Order_Functions\">higher-order functions<\/a>, <a href=\"https:\/\/docs.microsoft.com\/dotnet\/fsharp\/language-reference\/functions\/#partial-application-of-arguments\">partial application of arguments<\/a>, and <a href=\"https:\/\/docs.microsoft.com\/dotnet\/fsharp\/language-reference\/fsharp-types\">F# Types<\/a>.<\/p>\n<p>Additionally, Giraffe sits atop the Kestrel HTTP Server, which is the same underlying technology that ASP.NET Core uses. This means that services written in Giraffe will have comparable performance to services written with ASP.NET Core MVC.<\/p>\n<h2>Creating the Giraffe project<\/h2>\n<p>To get started with Giraffe on .NET Core 2.0, you&#8217;ll need to ensure you have the <a href=\"https:\/\/www.microsoft.com\/net\/core\">.NET Core 2.0 SDK<\/a> installed. Next, enter this into your terminal:<\/p>\n<p><code>dotnet new -i \"giraffe-template\"<\/code><\/p>\n<p>This will install the <a href=\"https:\/\/github.com\/dustinmoris\/Giraffe\/tree\/master\/template\">Giraffe template<\/a> for you, and you&#8217;ll see it in the list of project types when you enter <code>dotnet new<\/code> into the terminal.<\/p>\n<p>Next, create a new giraffe project:<\/p>\n<p><code>dotnet new giraffe -o GiraffeSample<\/code><\/p>\n<p>This will place the template in a new folder called <code>GiraffeSample<\/code>.<\/p>\n<h2>Inspecting the code<\/h2>\n<p>In this example, I&#8217;ll use <a href=\"https:\/\/docs.microsoft.com\/dotnet\/fsharp\/get-started\/get-started-vscode\">Visual Studio Code<\/a> with the <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=Ionide.Ionide-fsharp\">Ionide-FSharp plugin<\/a> to explore and edit the project. If you don&#8217;t have it installed already, you can learn how to do so in our <a href=\"https:\/\/docs.microsoft.com\/dotnet\/fsharp\/get-started\/get-started-vscode\">official documentation<\/a>.<\/p>\n<p>Open Visual Studio Code in the newly created project by navigating to it and entering the following in the <code>GiraffeSample<\/code> directory:<\/p>\n<p><code>code .<\/code><\/p>\n<p>To get IntelliSense for this project, enter <code>dotnet restore<\/code> in your terminal. Red squiggles in the editor will go away after this is completed.<\/p>\n<p>There are two relevant files here:<\/p>\n<ul>\n<li><code>GiraffeSample.fsproj<\/code> &#8211; This is the project file. If you open it, you&#8217;ll notice F# source files listed alongside package dependencies. This is where new files, project references, and package references are added.<\/li>\n<li><code>Program.fs<\/code> &#8211; This file contains the entry point of the application, setup code to bind API routes to the <a href=\"https:\/\/docs.microsoft.com\/aspnet\/core\/fundamentals\/servers\/kestrel\">Kestrel HTTP server<\/a>, and the API routes themselves.<\/li>\n<\/ul>\n<p>The rest of the scaffolded files and folders can be safely ignored.<\/p>\n<p>Here is the <code>Program.fs<\/code> file scaffolded by the template in its entirety:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/cartermp\/a5cab4ccdf26199541f6410da8ad2358.js\"><\/script><\/p>\n<p>Upon inspecting <code>Program.fs<\/code>, you&#8217;ll notice three major regions:<\/p>\n<ol>\n<li>The Web App. This contains the web API routes that we&#8217;ll be adding to later.<\/li>\n<li>The Error Handler. This logs exceptions that can occur on the server and configures the HTTP 500 returned.<\/li>\n<li>Setup. These various functions configure the error handler, configure services for ASP.NET Core, configure application logging, and perform setup to allow the web app to run on Kestrel.<\/li>\n<\/ol>\n<p>The best way to run this app while developing is by entering <code>dotnet watch run<\/code> in your terminal. This will start a process which watches for changed files on your machine, recompiles the source files, and restarts the web server. If you open your browser to <code>http:\/\/localhost:5000<\/code>, you&#8217;ll see &#8220;Hello World, from my Giraffe App!&#8221;.<\/p>\n<p>Let&#8217;s take a look at some of the syntax. The most important section for this blog post is the web App.<\/p>\n<p><script src=\"https:\/\/gist.github.com\/cartermp\/b2aabb072575f590178709538f3b2222.js\"><\/script><\/p>\n<p>This is known as &#8220;Combinator-based Routing&#8221;. There are four important pieces here:<\/p>\n<ol>\n<li>The <code>choose<\/code> function, which defines expressions that can be evaluated based on input.<\/li>\n<li>The <code>GET<\/code> function, which represents routes which are HTTP GETs.<\/li>\n<li>The <code>setStatusCode<\/code> function, which allows you to define the behavior for a given HTTP status code.<\/li>\n<li>The <code>&gt;=&gt;<\/code> operator, which chains together expressions.<\/li>\n<\/ol>\n<p>Let&#8217;s walk through each one.<\/p>\n<p>The <code>choose<\/code> function is at the core of how routes are defined. If you hover over it, you&#8217;ll see the following type signature:<\/p>\n<p><code>val choose : handlers:HttpHandler list -&gt; next:HttpFunc -&gt; HttpFunc<\/code><\/p>\n<p>This is saying that <code>choose<\/code> is a function which takes two parameters as input: an F# list of <code>HttpHandler<\/code>, and an <code>HttpFunc<\/code>. It then produces an <code>HttpFunc<\/code>. The first parameter, the F# list of <code>HttpHandler<\/code>, is specified after the <code>choose<\/code> function by <code>[]<\/code> (an F# list), with <code>HttpHandler<\/code> functions inside. The <a href=\"https:\/\/github.com\/dustinmoris\/Giraffe#choose\">behavior of <code>choose<\/code><\/a> is simple: a running web application will iterate through the list of <code>HttpHandler<\/code> functions to find one which matches the incoming request.<\/p>\n<p>If you hover over <code>GET<\/code>, you&#8217;ll see that is of type <code>HttpHandler<\/code>. No surprises there! All this does is <a href=\"https:\/\/github.com\/dustinmoris\/Giraffe#get-post-put-patch-delete\">filter all HTTP GET requests<\/a> into the next <code>choose<\/code> function.<\/p>\n<p>The <code>setStatusCode<\/code> function is a fallback: if an incoming request uses a route which isn&#8217;t defined, the above code will set the response to a 404, with the text &#8220;Not Found&#8221;.<\/p>\n<p>Finally, the <code>&gt;=&gt;<\/code> operator (known as the <a href=\"https:\/\/github.com\/dustinmoris\/Giraffe#compose\">compose combinator<\/a>), is what chains everything together. The <code>GET<\/code> handler is composed with an inner <code>choose<\/code> combinator, which defines <a href=\"https:\/\/github.com\/dustinmoris\/Giraffe#route\">API routes<\/a>.<\/p>\n<h2>Adding more routes<\/h2>\n<p>Let&#8217;s add two more routes. Replace the <code>webApp<\/code> function with this one below:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/cartermp\/0f5b3184131c3b77ecdb8755a2d4303d.js\"><\/script><\/p>\n<p>When you save <code>Program.fs<\/code>, the .NET watch tool will notice your changes, recompile your application, and re-run the web server. You can navigate to each route (&#8220;localhost:5000\/hello-json&#8221; and &#8220;localhost:5000\/goodbye-xml&#8221;) to see the JSON and XML returned. The <code>json<\/code> and <code>xml<\/code> functions are built into Giraffe so that you don&#8217;t need to serialize things yourself.<\/p>\n<h2>Extending the API to add and find restaurants<\/h2>\n<p>At Microsoft, we&#8217;ll often gather in small groups and go out to lunch together. However, people have different preferences and dietary requirements, so the task of finding a suitable place to eat can take some time. Let&#8217;s solve that problem.<\/p>\n<p>As a reminder, the entire source code (and database) is <a href=\"https:\/\/github.com\/cartermp\/GiraffeSample\">available on GitHub<\/a>. Clone the repository or download the code to follow along.<\/p>\n<h3>Database and types used in the API<\/h3>\n<p>First, let&#8217;s establish the source of the data. I&#8217;m choosing SQLite. I&#8217;m a big fan of <a href=\"https:\/\/sqlite.org\/\">SQLite<\/a>. It&#8217;s perfectly suitable for a basic web API like this, extremely simple to configure and use, and easy to develop for. It&#8217;s also completely free! When building a more robust production system, you&#8217;ll probably want to use other database technologies (such as MSSQL, MySQL, and PostgreSql), as SQLite struggles under moderate load in an environment such as a web service. But for something which would see very little request activity, it&#8217;s quite suitable.<\/p>\n<p>Let&#8217;s create a new SQLite database with a single table:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/cartermp\/890649bb04e91b7ec7b0cc79e5d98e99.js\"><\/script><\/p>\n<p>The database file (I called it <code>Sample.db<\/code>) can then be saved in the root directory of the project. This is an easy place to store it.<\/p>\n<p>Next, let&#8217;s define some simple types for our domain, in a new file called <code>LunchTypes.fs<\/code>. First, create the file, and add it to the project file (<code>.fsproj<\/code>). To add this to the project, simply add the following line to the project file in the <code>ItemGroup<\/code> section where <code>Program.fs<\/code> is. Make sure to add it <em>above<\/em> <code>Program.fs<\/code>:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/cartermp\/5efc9d0d71d9f776ebd972e764c97a04.js\"><\/script><\/p>\n<p>Now, add the following code:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/cartermp\/a924c26397ff5cd9e4b067c6aa7ee90a.js\"><\/script><\/p>\n<p>The first is a <a href=\"https:\/\/docs.microsoft.com\/dotnet\/fsharp\/language-reference\/classes\">class type<\/a> which corresponds to the table schema in the database. The second type is an <a href=\"https:\/\/docs.microsoft.com\/dotnet\/fsharp\/language-reference\/records\">F# Record<\/a>, which will <a href=\"https:\/\/docs.microsoft.com\/dotnet\/fsharp\/language-reference\/options\">optionally<\/a> contain pieces of data that we can use to query the database with.<\/p>\n<p>At the time of writing, Type Providers are not yet available on .NET Core. Once they are, the <code>LunchSpot<\/code> class will no longer be necessary to interact with a SQL database.<\/p>\n<h3>Building the Web API<\/h3>\n<p>Next, let&#8217;s define the shape of the API:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/cartermp\/806ffb9f09bf86ce9777fbf66b188240.js\"><\/script><\/p>\n<p>There&#8217;s a little bit to unpack here. I&#8217;ll start at the bottom.<\/p>\n<p>An HTTP GET will retrieve lunches (more on this later), and an HTTP POST will submit a new lunch to be added to the database. Note that there is no <code>choose<\/code> used here: this is because there is only one route per HTTP action; thus, there is no need for <code>choose<\/code>. Each of the routes are composed with a handler function via the <code>&gt;=&gt;<\/code> operator. Let&#8217;s take a look at them.<\/p>\n<p>The first handler, <code>handleLunchFilter<\/code>, is defined as such:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/cartermp\/9f0467d496f827bbed0392437b61bc50.js\"><\/script><\/p>\n<p>It takes in an <code>HttpFunc<\/code> and an <code>HttpContext<\/code> as its parameters. This is how you &#8220;plug in&#8221; custom functionality in the HTTP pipeline, and it allows the handler to compose via <code>&gt;=&gt;<\/code>.<\/p>\n<p>The body of the handler is quite simple. The first line takes <a href=\"https:\/\/github.com\/dustinmoris\/Giraffe#bindquerystring\">values out of the query string and binds them<\/a> to an instance of the <code>LunchFilter<\/code> type defined in our domain. The second line passes that filter to the data access layer, which will then query the database for the set of <code>LunchSpot<\/code>s. The last line will serialize those into JSON, then send that JSON back as a response. The syntax, <code>&lt;function&gt; input next ctx<\/code> is how you &#8220;align&#8221; your handler with the HTTP pipeline.<\/p>\n<p>The second handler, <code>handleAddLunch<\/code>, is defined as such:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/cartermp\/51e95f0c1c3bd2811da463dcf924b88d.js\"><\/script><\/p>\n<p>Note that the &#8220;shape&#8221; of this handler is the same as <code>handleGetLunches<\/code> &#8211; it takes in an <code>HttpFunc<\/code> and <code>HttpContext<\/code> as its parameters. Because this is a handler in the HTTP pipeline, it must conform to this shape.<\/p>\n<p>If you&#8217;re not familiar with <a href=\"https:\/\/docs.microsoft.com\/dotnet\/fsharp\/language-reference\/computation-expressions\">Computation Expressions<\/a> in F#, don&#8217;t worry! They&#8217;re quite easy to deal with. All this one does is compute the body as a .NET Task.<\/p>\n<p>The <code>let!<\/code> keyword, in this context, is equivalent to saying, &#8220;Compute the Task&lt;&#8216;T&gt; expression on the right-hand side, and give me the T back when it&#8217;s done&#8221;. It&#8217;s non-blocking. The <code>return!<\/code> keyword is shorthand for:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/cartermp\/211f9289a7ea1fcfbc828e05985b5278.js\"><\/script><\/p>\n<p>The <code>return<\/code> keyword wraps the result as a <code>Task&lt;'T&gt;<\/code>. This allows the entire expression to be treated as a <code>Task&lt;'T&gt;<\/code>, which will eventually be unwrapped by a lower level of ASP.NET Core.<\/p>\n<p>In this case, the request has JSON in its body. The handler will deserialize that JSON, add it to the database, and send a response with some nice text in the body. All of this will happen as a <code>Task&lt;'T&gt;<\/code>, and will be scheduled and awaited by ASP.NET under the covers.<\/p>\n<h3>The data access layer<\/h3>\n<p>Finally, I&#8217;ll define some functions for interacting with our database. I&#8217;ll actually use two different approaches: <code>getLunches<\/code> will use the <a href=\"https:\/\/github.com\/schotime\/NPoco\">NPoco ORM<\/a>, and <code>addLunch<\/code> will use <a href=\"https:\/\/github.com\/aspnet\/Microsoft.Data.Sqlite\">Microsoft.Data.Sqlite<\/a> directly. In a real-world application, you would likely not mix technologies like this.\u00a0I&#8217;ve done so here\u00a0to demonstrate that there is already an ecosystem of libraries that you can use for these kinds of tasks with F# and .NET Core 2.0 today. The choice of data access technologies are large, and I recommend that you explore each and choose which works best for you.<\/p>\n<p>First, add the NPoco and Microsoft.Data.Sqlite packages:<\/p>\n<p><code>dotnet add package Microsoft.Data.Sqlite<\/code><\/p>\n<p><code>dotnet add package NPoco<\/code><\/p>\n<p>Next, create a new file called <code>DataAccess.fs<\/code>, and add it to the project file, in between <code>Program.fs<\/code> and <code>LunchTypes.fs<\/code>:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/cartermp\/f53810356fb1cb41cd9e12c0b6a06a59.js\"><\/script><\/p>\n<p>Now, use the following code:<\/p>\n<p><script src=\"https:\/\/gist.github.com\/cartermp\/b50b01dc537722cd8f1a303db82c3670.js\"><\/script><\/p>\n<p>If you&#8217;re developing under the <code>dotnet watch un<\/code> tool, you&#8217;ll need to restart it so that the dependency on NPoco is picked up.<\/p>\n<p>This data access layer is fairly straightforward. <code>getLunches<\/code> calls <code>getLunchFetchingQuery<\/code>, which builds a SQL query based on information in the filter record. The code to do that isn&#8217;t the prettiest in the world (interfacing with a SQL database is rarely pretty), but it&#8217;s flexible and easy to debug. It&#8217;s also worth noting that SQLite does not support Stored Procedures. If you were to use databases like MSSQL, PgSQL, or MySQL, the above SQL expressions would likely be Stored Procedures. The sql query defined above might actually be a Stored Procedure in a different SQL database.<\/p>\n<p>The SQL query is then sent to the database, and the result is deserialized as a set of <code>LunchSpot<\/code>s. When we complete Type Provider support for .NET Core, data access for relational databases via the <a href=\"http:\/\/fsprojects.github.io\/SQLProvider\/\">SqlProvider<\/a> will make these kinds of operations very easy and pleasant to write.<\/p>\n<p>The <code>addLunch<\/code> function uses <code>Microsoft.Data.Sqlite<\/code> directly, mostly for demonstrative purposes. If you&#8217;re familiar with ADO.NET, this code should look very familiar. Note that the <code>|&gt; ignore<\/code> construct is used a lot here. That is because the ADO.NET methods all return a value. Return values are not implicitly discarded in F# and will produce a warning unless you explicitly ignore them.<\/p>\n<h2>Running the app and debugging it<\/h2>\n<p>If you&#8217;ve been using <code>dotnet watch run<\/code>, you should already have a running application bound to port 5000 already. If not, you can use either <code>dotnet run<\/code> or <code>dotnet watch run<\/code> to start the web server. For testing out GETs and POSTS, I recommend using Postman. It&#8217;s free. Postman makes it very easy to define a JSON body for the POST, and it also returns pretty-printed JSON by default.<\/p>\n<p>It&#8217;s also very easy to debug the app in Visual Studio Code. To debug, you&#8217;ll need to do the following:<\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li>Install the C# plugin. It&#8217;s the only way to get the .NET Core debugger right now.<\/li>\n<li>Click the Debugging icon on the right-hand side of Visual Studio Code.<\/li>\n<li>Click the Gear icon at the top, and select &#8220;.NET Core&#8221;.<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-14816\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2017\/09\/Screen-Shot-2017-09-26-at-9.51.47-AM.png\" alt=\"\" width=\"1170\" height=\"326\" srcset=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2017\/09\/Screen-Shot-2017-09-26-at-9.51.47-AM.png 1170w, https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2017\/09\/Screen-Shot-2017-09-26-at-9.51.47-AM-300x84.png 300w, https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2017\/09\/Screen-Shot-2017-09-26-at-9.51.47-AM-768x214.png 768w, https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2017\/09\/Screen-Shot-2017-09-26-at-9.51.47-AM-1024x285.png 1024w\" sizes=\"(max-width: 1170px) 100vw, 1170px\" \/><\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li>Under the &#8220;program&#8221; entry, add the path to the <code>.dll<\/code> for your app. In my case, it&#8217;s &#8220;${workspaceRoot}\/bin\/Debug\/netcoreapp2.0\/GiraffeSample.dll&#8221;.<\/li>\n<li>Press the Play button. When prompted by the error message, press &#8220;Configure Task Runner&#8221;.<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2017\/09\/Screen-Shot-2017-09-26-at-9.55.47-AM.png\"><img decoding=\"async\" width=\"848\" height=\"98\" class=\"alignnone size-medium wp-image-14825\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2017\/09\/Screen-Shot-2017-09-26-at-9.55.47-AM.png\" alt=\"\" srcset=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2017\/09\/Screen-Shot-2017-09-26-at-9.55.47-AM.png 848w, https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2017\/09\/Screen-Shot-2017-09-26-at-9.55.47-AM-300x35.png 300w, https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2017\/09\/Screen-Shot-2017-09-26-at-9.55.47-AM-768x89.png 768w\" sizes=\"(max-width: 848px) 100vw, 848px\" \/><\/a><\/p>\n<ol>\n<li>Select .NET Core<\/li>\n<li>Press the Play button again.<\/li>\n<\/ol>\n<p>Now, you can debug with the .NET Core debugger:<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-14816\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2017\/09\/Screen-Shot-2017-09-26-at-10.01.14-AM.png\" alt=\"\" width=\"1170\" height=\"326\" \/><\/p>\n<h2>Wrapping up<\/h2>\n<p>This post covered quite a lot of concepts! Let&#8217;s quickly summarize:<\/p>\n<ol>\n<li>There are multiple technologies available for building web services with F# on .NET Core today. I used Giraffe for this post.<\/li>\n<li>Giraffe has some functional idioms that differ quite a bit from ASP.NET MVC.<\/li>\n<li>Data access (in this case, with SQLite) is quite easy to do with F# and .NET Core.\u00a0 There are multiple options for access data here.<\/li>\n<li>F# has some powerful features, such as Computation Expressions, that allow you to pack a lot of power into a small amount of code.<\/li>\n<\/ol>\n<p>Lastly, this is all very easy to put together. All you need to do is install two packages on top of the Giraffe template (Microsoft.Data.Sqlite and NPoco), and all pieces of this application are very lightweight in terms of concept count. In general, F# on .NET Core has what I like to call a &#8220;Linear complexity curve&#8221;. What I mean by that is that it&#8217;s easy and straightforward to get small things done, and as the problem space grows, the complexity you must deal with grows linearly. Plugging into the HTTP pipeline to add custom functionality follows a small set of <a href=\"https:\/\/github.com\/dustinmoris\/Giraffe#httphandler\">documented rules<\/a>. Adding a data access layer just means adding a few packages and writing some functions which access the data source with SQL (Note: with a database such as MSSQL, PgSQL, or MySQL, these can be Stored Procedures instead of stringified SQL). Furthermore, F# has additional language features that are flexible in the face of change, easy to extend, and don&#8217;t require much code. It&#8217;s a great fit for building production systems.<\/p>\n<p>In total, this project has the following line of code statistics (including whitespace, formatting, and comments):<\/p>\n<ul>\n<li>Project file: 28 lines<\/li>\n<li>LunchTypes.fs: 16 lines<\/li>\n<li>DataAccess.fs: 86 lines<\/li>\n<li>Program.fs: 77 lines<\/li>\n<\/ul>\n<p>That&#8217;s small enough to easily keep in my head (which is important, because I have trouble keeping a lot in my head), and there&#8217;s no resorting to magic frameworks, either. F# is ready for web services on .NET Core 2.0 today, and it&#8217;s only going to get better. <a href=\"https:\/\/github.com\/cartermp\/GiraffeSample\">Download the sample code<\/a> and play around with it to see what else you can build!<\/p>\n<h2>Further resources<\/h2>\n<ul>\n<li><a href=\"https:\/\/blogs.msdn.microsoft.com\/dotnet\/2017\/05\/31\/why-you-should-use-f\/\">Why you should use F#<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/dustinmoris\/Giraffe\">Giraffe project<\/a><\/li>\n<li><a href=\"https:\/\/compositional-it.com\/blog\/2017\/09-18-safe-web\/index.html\">Functional-First Web APIs in F#<\/a><\/li>\n<li><a href=\"http:\/\/fsharp.org\/\">F# homepage<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/dotnet\/fsharp\/\">Microsoft&#8217;s F# documentation<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Earlier this year, I wrote about an update to the roadmap for F# and .NET Core. I had mentioned that there were a number of things you could build with F# and .NET Core today, such as web services. In this post, I&#8217;ll walk through building a web service with F# and .NET Core 2.0 [&hellip;]<\/p>\n","protected":false},"author":678,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,196,197,636],"tags":[4,9,73],"class_list":["post-14805","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-dotnet-core","category-aspnet","category-fsharp","tag-net","tag-net-core","tag-f"],"acf":[],"blog_post_summary":"<p>Earlier this year, I wrote about an update to the roadmap for F# and .NET Core. I had mentioned that there were a number of things you could build with F# and .NET Core today, such as web services. In this post, I&#8217;ll walk through building a web service with F# and .NET Core 2.0 [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/14805","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/678"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=14805"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/14805\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=14805"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=14805"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=14805"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}