<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Daniel Reis's Blog]]></title><description><![CDATA[.NET, Azure and Serverless technologies is most of what you're gonna find here. Welcome!]]></description><link>https://blog.danielreis.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 22 Apr 2026 12:15:39 GMT</lastBuildDate><atom:link href="https://blog.danielreis.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Add authorization to your Azure Functions with Static Web Apps]]></title><description><![CDATA[Recently, the Azure Static Web Apps team released some changes to allow us to better configure our app. Although this came with some breaking changes, we are now able to simplify our routes' authorization config! I've been waiting for this for a whil...]]></description><link>https://blog.danielreis.dev/add-authorization-to-your-azure-functions-with-static-web-apps</link><guid isPermaLink="true">https://blog.danielreis.dev/add-authorization-to-your-azure-functions-with-static-web-apps</guid><category><![CDATA[Azure]]></category><category><![CDATA[JAMstack]]></category><category><![CDATA[serverless]]></category><dc:creator><![CDATA[Daniel Reis]]></dc:creator><pubDate>Thu, 25 Feb 2021 05:32:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1614231129458/o8AXxdpni.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Recently, the Azure Static Web Apps team released some changes to allow us to better configure our app. Although this came with some breaking changes, we are now able to simplify our routes' authorization config! I've been waiting for this for a while, I created <a target="_blank" href="https://github.com/Azure/static-web-apps/issues/132">an issue</a> about this on August last year.</p>
<p>If you need any guidance on creating a Static Web App with functions, you can check out my other blog post: <a target="_blank" href="https://blog.danielreis.dev/using-function-proxies-with-azure-static-web-apps">Using function proxies with Azure Static Web Apps</a></p>
<h2 id="how-it-worked-before">How it worked before</h2>
<p>Previously, to add authorization to your SWA, you had to create a file named <em>routes.json</em> in the root of your app's build artifact folder. That generally changes from framework to framework,  <a target="_blank" href="https://docs.microsoft.com/en-us/azure/static-web-apps/routes#location">but this is well documented</a>. On the file, you can define routes that are authorized based on a user role. The default roles in a Static Web App are <code>anonymous</code> (Someone who is not logged in) and <code>authenticated</code> (Someone who is logged in through any of the identity providers). This is how a <em>routes.json</em> file with authorization rules generally looks like:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"routes"</span>: [
    {
      <span class="hljs-attr">"route"</span>: <span class="hljs-string">"/*"</span>,
      <span class="hljs-attr">"serve"</span>: <span class="hljs-string">"/index.html"</span>,
      <span class="hljs-attr">"statusCode"</span>: <span class="hljs-number">200</span>,
      <span class="hljs-attr">"allowedRoles"</span>: [<span class="hljs-string">"authenticated"</span>]
    }
  ]
}
</code></pre>
<p>The file above says that to access <strong>any</strong> page, you have to be logged on. You can specify which routes require an user to be authenticated so you could, for example, allow any user to access your app's front page, but to access the user panel he would have to be logged on.</p>
<h2 id="how-it-works-now">How it works now</h2>
<p>The <code>routes</code> part of the file is mainly the same, with some fields renamed. The main breaking change is that there's a new file named <em>staticwebapp.config.json</em>. It has the same capabilities of the <em>routes.json</em> and more:</p>
<ul>
<li>You can now define HTTP methods on your route definitions. Before, if you wanted to allow unauthenticated <em>GET</em> requests but require authentication for <em>POST</em> or <em>PUT</em>, you had to define a different route for the <em>POST</em> and <em>PUT</em> routes. Now, you can use the same route and specify the HTTP methods on the <code>methods</code> field. Here's an example:<pre><code class="lang-json">{
  <span class="hljs-attr">"routes"</span>: [
    {
      <span class="hljs-attr">"route"</span>: <span class="hljs-string">"/api/*"</span>,
      <span class="hljs-attr">"methods"</span>: [<span class="hljs-string">"POST"</span>, <span class="hljs-string">"PUT"</span>],
      <span class="hljs-attr">"allowedRoles"</span>: [<span class="hljs-string">"authenticated"</span>]
    }
  ]
}
</code></pre>
The JSON above says that every route starting with <code>/api</code> <strong>and</strong> the method is <em>POST</em> or <em>PUT</em> should only be called by users with the <code>authenticated</code> role.</li>
</ul>
<blockquote>
<p><strong>NOTE:</strong> The <code>methods</code> field works on the <em>routes.json</em> file, but if you're starting a new application or modifying your routes file to use the new features, you should consider switching to the new file, since the old one is deprecated.</p>
</blockquote>
<h2 id="custom-roles">Custom roles</h2>
<p>Azure Static Web Apps allow you to create custom roles to your users. Currently this is only possible when inviting users through the portal and it requires you to specify the Auth provider, email address, the apps's domain (for some reason) and the expiration (in hours, max 7 days), as well as the role name, of course. As far as I know, there's no way to do this outside the portal, but hopefully this will change in the future. You can invite an user to your app by going on your Static Web App resource, going on the <strong>Role management</strong> tab and clicking <strong>Invite</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1614230395012/eaqrNZ1QR.png" alt="create invitation link.png" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>Now that the configuration files allow you to define which HTTP method you want your route definition to run, you can specify which of your HTTP methods will have authorization rules. There are more features that came with the new <em>staticwebapp.config.json</em> file, some of them are really interesting! But I decided to focus this blog post on the authorization and HTTP methods part. You can read more about the new file <a target="_blank" href="https://docs.microsoft.com/en-us/azure/static-web-apps/configuration">here</a>. If you have any questions or feedback, let me know!</p>
]]></content:encoded></item><item><title><![CDATA[Using function proxies with Azure Static Web Apps]]></title><description><![CDATA[Azure Static Web Apps is a service that provides you with a way to serve static content with an Azure Functions backend API. It's currently in preview, but it already looks promising, giving you a variety of useful features to build a web app. You ca...]]></description><link>https://blog.danielreis.dev/using-function-proxies-with-azure-static-web-apps</link><guid isPermaLink="true">https://blog.danielreis.dev/using-function-proxies-with-azure-static-web-apps</guid><category><![CDATA[Azure]]></category><category><![CDATA[C#]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[dotnetcore]]></category><dc:creator><![CDATA[Daniel Reis]]></dc:creator><pubDate>Fri, 19 Feb 2021 03:57:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1613706982325/WIxiwJOtK.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://azure.microsoft.com/en-us/services/app-service/static/">Azure Static Web Apps</a> is a service that provides you with a way to serve static content with an Azure Functions backend API. It's currently in preview, but it already looks promising, giving you a variety of useful features to build a web app. You can pull your code directly from GitHub, then Azure will add a GitHub Actions workflow to build and deploy to Azure Static Web Apps. It truly is a great service, and as of the day of writing this blog post, it's completely free, since it's on preview. You can read about all of Azure Static Web Apps features <a target="_blank" href="https://docs.microsoft.com/en-us/azure/static-web-apps/overview#key-features">here</a>.</p>
<p>The integrated API is a nice way to not worry about things like CORS, since it will be hosted on the same domain as the website on the <code>/api</code> route. However, it currently imposes some limitations on what you can do with your function app:</p>
<ul>
<li>Not every language is supported. You can only create your function app on JavaScript, C# and Python. This will probably be fixed in the future, as there's no good reason to not support other languages IMO.</li>
<li>You can only add HTTP triggers. This one probably is going to remain this way, since it's purpose is to process requests from the frontend, but maybe I'm wrong. Input and output bindings works normally.</li>
<li>Logs are only available through Application Insights. This means that you can't really troubleshoot the resource without creating an Application Insights resource along with your Static Web App. I'm not sure if this means that you cannot add other log providers through DI, but I'll investigate further later.</li>
</ul>
<p>With that in mind, being limited to only HTTP triggers is not so bad, as you can use the Static Web App's function app as a proxy to other services using <strong>function proxies</strong>.</p>
<h2 id="function-proxies">Function Proxies</h2>
<p>Azure Function Proxies allow you to specify routes that will be implemented by another resource, with the option to override the HTTP method, the query string or the request headers. It's a pretty good tool for breaking a big service into smaller parts in a serverless architecture.</p>
<p>To add a proxy to your function app, you just need to define a <code>proxies.json</code> file on your project (Don't forget to copy the file to the build output!) and configure it according to your needs. This is how a proxies file look like:</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"$schema"</span>: <span class="hljs-string">"http://json.schemastore.org/proxies"</span>,
    <span class="hljs-attr">"proxies"</span>: {
        <span class="hljs-attr">"&lt;proxy-name&gt;"</span>: {
            <span class="hljs-attr">"matchCondition"</span>: {
                <span class="hljs-attr">"route"</span>: <span class="hljs-string">"/api/todo"</span>
            },
            <span class="hljs-attr">"backendUri"</span>: <span class="hljs-string">"%service-url%/api/todo"</span>,
            <span class="hljs-attr">"requestOverrides"</span>: {
                <span class="hljs-attr">"backend.request.querystring.&lt;querystring-name&gt;"</span>: <span class="hljs-string">"example-value"</span>,
                <span class="hljs-attr">"backend.request.header.&lt;header-name&gt;"</span>: <span class="hljs-string">"example-value"</span>,
            },
            <span class="hljs-attr">"responseOverrides"</span>: {
                <span class="hljs-attr">"response.body"</span>: {
                    <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Hello, world!"</span>
                },
                <span class="hljs-attr">"response.statusCode"</span>: <span class="hljs-string">"418"</span>
            }
        }
    }
}
</code></pre>
<p>The example above does some things that are worth explaining, we're doing the following:</p>
<ul>
<li>Creating a proxy with the name <code>&lt;proxy-name&gt;</code> that will be triggered when the app receives a request on the <code>/api/todo</code> route. You can also specify HTTP methods on the match condition.</li>
<li>Setting the <code>backendUri</code> to the service that implements our functionality. This is what will be called when the request matches the condition defined. <code>%service-url%</code> is the syntax used for configuration (your <code>local.settings.json</code> file or your environment variables).</li>
<li>Overriding the request's <code>&lt;header-name&gt;</code> header and <code>&lt;querystring-name&gt;</code> query string key with the value 'example-value'.</li>
<li>Overriding the response's body and status code.</li>
</ul>
<p>There are more things that can be configured in your proxies file, you can read more about it <a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-proxies#modify-requests-responses">here</a>.</p>
<h2 id="function-proxies-on-swas">Function Proxies on SWAs</h2>
<p>Since SWA allows us to use its function app as a proxy, I made a static app that calls two other function apps through function proxies. This is how our services will communicate:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613698087781/h5q44syBO.png" alt="azf-prx-swa.png" /></p>
<p>The code for this blog post is available on this GitHub repository:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/danielreis-dev/function-proxies-on-static-web-apps">https://github.com/danielreis-dev/function-proxies-on-static-web-apps</a></div>
<h3 id="catalog-servicehttpsgithubcomdanielreis-devfunction-proxies-on-static-web-appstreemastercatalog"><a target="_blank" href="https://github.com/danielreis-dev/function-proxies-on-static-web-apps/tree/master/catalog">Catalog Service</a></h3>
<p>This function app has one HTTP function that returns an array of catalog items. You can page the results by changing the <code>index</code> value on the query string.</p>
<h3 id="orders-servicehttpsgithubcomdanielreis-devfunction-proxies-on-static-web-appstreemasterorders"><a target="_blank" href="https://github.com/danielreis-dev/function-proxies-on-static-web-apps/tree/master/orders">Orders Service</a></h3>
<p>This function app also has one HTTP function that return an order creation result. If you send any order item on the request, you'll receive a 200 OK with an order ID and a status. If you send an empty array, you'll receive a 400 BAD REQUEST.</p>
<h3 id="swa-frontendhttpsgithubcomdanielreis-devfunction-proxies-on-static-web-appstreemasterapp"><a target="_blank" href="https://github.com/danielreis-dev/function-proxies-on-static-web-apps/tree/master/app">SWA Frontend</a></h3>
<p>This is a Blazor WebAssembly app that allows you to browse through catalog items and add them to an in-memory shopping cart. After that, you can finish your shopping by creating an order. It also has a <code>routes.json</code> configured to serve the same file (<code>index.html</code>) on every route, this is required and you can read more about it  <a target="_blank" href="https://docs.microsoft.com/en-us/azure/static-web-apps/deploy-blazor#fallback-route">here</a>.</p>
<h3 id="swa-backendhttpsgithubcomdanielreis-devfunction-proxies-on-static-web-appstreemasterbff"><a target="_blank" href="https://github.com/danielreis-dev/function-proxies-on-static-web-apps/tree/master/bff">SWA Backend</a></h3>
<p>This is a simple function app that includes a <a target="_blank" href="https://github.com/danielreis-dev/function-proxies-on-static-web-apps/blob/master/bff/proxies.json"><code>proxies.json</code></a> file that maps to the two other function apps' <code>backendUri</code> using environment variables (<code>%CONNECTIONSTRINGS__CATALOG%</code> and <code>%CONNECTIONSTRINGS__ORDERS%</code>). Both proxies override the query string's <code>code</code> value to include the function app's function key that is required for authentication in production, we'll see how to set these values later on, but they're not required in your development environment.</p>
<blockquote>
<p><strong>NOTE</strong>: Currently, you can't add configuration settings on a SWA that doesn't have any functions in it, so I also included a dummy HTTP function to allow configuration in production. I believe that it should be a valid scenario to only have proxies on your backend function app, so I created an <a target="_blank" href="https://github.com/Azure/static-web-apps/issues/289">issue</a> on the Static Web App's GitHub repository. I'll update this post with any info they provide me.</p>
</blockquote>
<p>On the  <a target="_blank" href="https://github.com/danielreis-dev/function-proxies-on-static-web-apps/blob/master/bff/local.settings.json"><code>local.settings.json</code></a> file, there are two <strong>important</strong> settings that are worth explaining:</p>
<pre><code>    "AZURE_FUNCTION_PROXY_DISABLE_LOCAL_CALL": <span class="hljs-keyword">true</span>,
    "SERVICE__CATALOG__KEY": "catalog_key" ,
    "SERVICE__ORDERS__KEY": "orders_key"
  },
  "Host": {
    "CORS": "*"
</code></pre><ul>
<li><code>AZURE_FUNCTION_PROXY_DISABLE_LOCAL_CALL</code>: For some reason, when calling your proxy in development gives an error saying that a recursive call was detected, even though it's correctly configured to call another function app listening in another port. Setting this variable to <code>true</code> fixes the problem.</li>
<li><code>CORS:*</code>: Since we're running this app locally, you'll receive an error if this setting is not present. That's because the Blazor app is running on a different port than the Backend function app. It will work correctly on production.</li>
</ul>
<h2 id="running-the-application">Running the application</h2>
<p>To make testing easier, I've added a <code>tye.yaml</code> file that spins up all four services with one command. It also gives us a nice dashboard with logs and other useful info about the running services. If you never heard about  <a target="_blank" href="https://github.com/dotnet/tye">Tye</a>, you should really check it out, it's a wonderful tool that helps a lot with the development of microservices, but all you need to know for now is how to install the tool (<code>dotnet tool install -g Microsoft.Tye --version "0.6.0-alpha.21070.5"</code>) and run it (<code>tye run</code>).</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">my-store</span>
<span class="hljs-attr">services:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">frontend</span>
  <span class="hljs-attr">project:</span> <span class="hljs-string">app/MyStore.App.csproj</span>
  <span class="hljs-attr">bindings:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">protocol:</span> <span class="hljs-string">http</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">bff</span>
  <span class="hljs-attr">azureFunction:</span> <span class="hljs-string">bff/</span>
  <span class="hljs-attr">bindings:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">protocol:</span> <span class="hljs-string">http</span>
    <span class="hljs-attr">port:</span> <span class="hljs-number">7070</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">catalog</span>
  <span class="hljs-attr">azureFunction:</span> <span class="hljs-string">catalog/</span>
  <span class="hljs-attr">bindings:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">protocol:</span> <span class="hljs-string">http</span>
      <span class="hljs-attr">connectionString:</span> <span class="hljs-string">${protocol}://${host}:${port}</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">orders</span>
  <span class="hljs-attr">azureFunction:</span> <span class="hljs-string">orders/</span>
  <span class="hljs-attr">bindings:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">protocol:</span> <span class="hljs-string">http</span>
      <span class="hljs-attr">connectionString:</span> <span class="hljs-string">${protocol}://${host}:${port}</span>
</code></pre>
<p>The YAML file configures the SWA backend app to always run on the port 7070 and assign the other three services random ports. It also sets the environment variables required for the SWA backend to call the Orders and Catalog service, that happens through the <code>connectionString</code> binding defined on the file. When running the command <code>tye run</code>, you should see the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613700895681/XtzaDw-_6.png" alt="tye run" /></p>
<p>The dashboard is hosted on <code>http://localhost:8000</code>, it should list you all four services:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613701058509/ZpdG-hWvp.png" alt="tye dashboard" /></p>
<p>Finally, when you access the frontend app, you should be able to add items to your card and finish your order!</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.loom.com/share/8fd432ec3aa943258aa280950c55ba61">https://www.loom.com/share/8fd432ec3aa943258aa280950c55ba61</a></div>
<blockquote>
<p><strong>NOTE</strong>: For some reason, requests going through the proxy always take <strong>at least</strong> two seconds. Do not panic, as this does not seem to be happening in production.</p>
</blockquote>
<h2 id="creating-and-configuring-your-azure-static-web-app">Creating and configuring your Azure Static Web App</h2>
<p>Now that you've seen the app in action, it's time to deploy it to production and configure it. If you need instructions on how to create an Azure Static Web App, check out this Microsoft <a target="_blank" href="https://docs.microsoft.com/en-us/azure/static-web-apps/get-started-portal">article</a>.</p>
<p>Now we need to configure our SWA function app and add our function keys and URLs. You can get the function key for each function app running the following commands on the <a target="_blank" href="https://docs.microsoft.com/en-us/cli/azure/">Azure CLI</a> :</p>
<pre><code class="lang-shell">az functionapp function keys list -g &lt;ResourceGroupName&gt; -n &lt;CatalogFunctionAppName&gt; --function-name get-catalog
</code></pre>
<pre><code class="lang-shell">az functionapp function keys list -g &lt;ResourceGroupName&gt; -n &lt;OrdersFunctionAppName&gt; --function-name create-order
</code></pre>
<p>These should be added in the Configuration section as <code>SERVICE__CATALOG__KEY</code> and <code>SERVICE__ORDERS__KEY</code>, respectively. As for the URLs, they should be add as <code>CONNECTIONSTRINGS__CATALOG</code> and <code>CONNECTIONSTRINGS__ORDERS</code>. You can get them using the following command:</p>
<pre><code class="lang-shell">az functionapp config hostname list -g &lt;ResourceGroupName&gt; --webapp-name &lt;FunctionAppName&gt;
</code></pre>
<p>After all that, your should be up and running, and your Configuration section should be looking like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1613704182443/iCXs8218W.png" alt="swa configuration section" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>I hope you found this post useful. Static Web Apps have amazing potential and I'm hopeful the service will only get better, if you have any questions or feedback, please let me know in the comments!</p>
]]></content:encoded></item><item><title><![CDATA[I've decided to create a blog]]></title><description><![CDATA[Hi, this is my first blog post. Ever.
Creating a blog has been a wish of mine for quite some time, and I've finally decided to go through with it. This is mostly because I research a lot of stuff, and I always thought it would be a good idea to store...]]></description><link>https://blog.danielreis.dev/my-first-blog-post</link><guid isPermaLink="true">https://blog.danielreis.dev/my-first-blog-post</guid><category><![CDATA[introduction]]></category><dc:creator><![CDATA[Daniel Reis]]></dc:creator><pubDate>Sun, 14 Feb 2021 20:57:03 GMT</pubDate><content:encoded><![CDATA[<p>Hi, this is my first blog post. Ever.</p>
<p>Creating a blog has been a wish of mine for quite some time, and I've finally decided to go through with it. This is mostly because I research a lot of stuff, and I always thought it would be a good idea to store some of the things I learn in some place. It would be a plus if someone finds the things I post here useful, but I'm already glad that I started.</p>
<h2 id="what-can-you-expect-here">What can you expect here</h2>
<p>I spend most of my time with on Microsoft technologies, such as C#, Azure and such. I'm particularly interested in serverless technologies, specially Azure Functions, so hopefully I'll be posting a lot of that here. I'm also starting to get into IoT, but I don't think I'll be posting about that so soon, maybe in the future! I also plan to post about stuff that I have to google a lot to solve, like troubleshooting errors, weird behaviors and such, this is mostly for me, really, but maybe it will help you too.</p>
<h2 id="about-me">About me</h2>
<p>My name is Daniel, as you probably noticed from this website's name. I've been coding since mid 2016 and I'm passionate about it ever since. I'm always interested in learning new things, and I'm hopeful that this blog will make me learn things faster. I love to talk about technology, even though I'm not an expert in any specific area. </p>
<p>I'm not really used to write so much English, since I'm Brazilian, but I think (and hope) I can do a good job expressing myself. If you can't understand a word I'm saying, please let me know, I'm really trying to improve here.</p>
<p>I hope this is a good introduction, if you have any tips or feedback, tell me in the comments or something. Bye!</p>
]]></content:encoded></item></channel></rss>