<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Steven</title>
    <description>The latest articles on DEV Community by Steven (@stnguyen90).</description>
    <link>https://dev.to/stnguyen90</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F430188%2F6b731d08-b2e3-4149-94ae-2bd4eb12b240.jpeg</url>
      <title>DEV Community: Steven</title>
      <link>https://dev.to/stnguyen90</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stnguyen90"/>
    <language>en</language>
    <item>
      <title>Announcing Hosting for Flutter Web: deploy your Flutter web apps with Appwrite</title>
      <dc:creator>Steven</dc:creator>
      <pubDate>Thu, 22 May 2025 07:14:44 +0000</pubDate>
      <link>https://dev.to/appwrite/announcing-hosting-for-flutter-web-deploy-your-flutter-web-apps-with-appwrite-10n0</link>
      <guid>https://dev.to/appwrite/announcing-hosting-for-flutter-web-deploy-your-flutter-web-apps-with-appwrite-10n0</guid>
      <description>&lt;p&gt;Appwrite has long been a powerful backend platform for Flutter developers building mobile applications. Today, we’re bringing that same seamless experience to the web. With full support for Flutter in Appwrite Sites, you can now deploy Flutter web apps directly from your Appwrite project. No extra configuration, no added complexity.&lt;/p&gt;

&lt;p&gt;This means you can use your existing Dart and Flutter knowledge to create fast, responsive web apps without needing to learn HTML, CSS, or JavaScript. Build once with Flutter and deploy to mobile, desktop, and web. All from a single codebase, all hosted on Appwrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why native Flutter web support matters
&lt;/h2&gt;

&lt;p&gt;While most web environments are made for Node, Deno, or Bun runtimes, only a few are tailored for the needs of Flutter developers. Appwrite Sites is different. It’s designed with full Flutter web support in mind,  not just as an afterthought. That means native framework detection, optimized build settings, and direct integration with your Appwrite backend products like databases, authentication, storage, and functions.&lt;/p&gt;

&lt;p&gt;More importantly, it eliminates the common friction points of mobile app deployment. You don’t need to pay for developer accounts ($25 for Android, $99/year for Apple), wait days for store approvals, or navigate restrictive platform policies. With web deployment, your app is live the moment you push it.&lt;/p&gt;

&lt;p&gt;And because web apps run anywhere with a browser, you’re no longer limited to iOS or Android. Your Flutter app can be accessed from a desktop, tablet, mobile phone, or even a smart fridge. The web is universal, and Appwrite makes it easy to reach your users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not just for full web apps
&lt;/h2&gt;

&lt;p&gt;Even if you're not targeting the web as your primary platform, &lt;strong&gt;Appwrite Sites still solves real needs for Flutter developers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Many apps include flows that rely on external links, such as email verification, password reset, or payments. These typically direct users to a browser. With Sites, you can now create and host those supporting pages using the same Flutter tooling you're already familiar with.&lt;/p&gt;

&lt;p&gt;Instead of stitching together HTML pages or managing another stack, you can build these "satellite" pages as lightweight Flutter web apps,  and deploy them effortlessly with Appwrite. It's a way you leverage your existing knowledge and a more consistent way to build, with fewer moving parts and one unified codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full Flutter framework support&lt;/strong&gt;: Sites now recognizes and supports Flutter as a framework during setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-detection&lt;/strong&gt;: Flutter web projects are automatically identified.  No manual config required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimized static hosting&lt;/strong&gt;: Deployed like any other static site, but with Flutter-first optimizations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub integration&lt;/strong&gt;: Automatically deploy on every push from your GitHub repository.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works on Cloud and Self-Hosted&lt;/strong&gt;: Whether using Appwrite Cloud or Self-hosting, Sites for Flutter works everywhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  How to get started
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Step 1: Create Flutter Web app
&lt;/h2&gt;

&lt;p&gt;First, you must either create a Flutter Web app or set up the &lt;a href="https://github.com/appwrite/templates-for-sites" rel="noopener noreferrer"&gt;Flutter Web starter template&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Open your terminal, and run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter create my_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case you have an existing Flutter app and want to add web support to it, you need to run the following command in your project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter create &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;--platforms&lt;/span&gt; web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Push this project to a &lt;a href="https://github.com/new" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Create Appwrite project
&lt;/h2&gt;

&lt;p&gt;Head to the &lt;a href="https://cloud.appwrite.io/" rel="noopener noreferrer"&gt;Appwrite Console&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If this is your first time using Appwrite, create an account and create your first project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Create site
&lt;/h2&gt;

&lt;p&gt;Head to the &lt;strong&gt;Sites&lt;/strong&gt; page in your Appwrite project, click on the &lt;strong&gt;Create site&lt;/strong&gt; button, and select &lt;strong&gt;Connect a repository&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Connect your GitHub account and select the repository you intend to deploy.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select the &lt;strong&gt;production branch&lt;/strong&gt; and &lt;strong&gt;root directory&lt;/strong&gt; from your repo.&lt;/li&gt;
&lt;li&gt;Verify that the &lt;strong&gt;correct framework&lt;/strong&gt; is selected. In case an incorrect framework is visible, pick &lt;strong&gt;Flutter Web&lt;/strong&gt; from the drop-down list.&lt;/li&gt;
&lt;li&gt;Confirm the &lt;strong&gt;install command&lt;/strong&gt;, &lt;strong&gt;build command&lt;/strong&gt;, and &lt;strong&gt;output directory&lt;/strong&gt; in the build settings. The default build settings for Flutter Web are:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Install command:&lt;/strong&gt; &lt;code&gt;N/A&lt;/code&gt; (leave empty)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build command:&lt;/strong&gt; &lt;code&gt;flutter build web&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output directory:&lt;/strong&gt; &lt;code&gt;./build/web&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Add any &lt;strong&gt;environment variables&lt;/strong&gt; required by the site.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Click on the &lt;strong&gt;Deploy&lt;/strong&gt; button.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Visit site
&lt;/h2&gt;

&lt;p&gt;After successful deployment, click on the &lt;strong&gt;Visit site&lt;/strong&gt; button.&lt;/p&gt;

&lt;h1&gt;
  
  
  Simplifying development
&lt;/h1&gt;

&lt;p&gt;Sites for Flutter is part of Appwrite’s larger mission to simplify the developer experience. With support for backend and frontend services, including static hosting, databases, functions, and auth, Appwrite is the all-in-one platform to build any application.&lt;/p&gt;

&lt;p&gt;Try it today on &lt;strong&gt;Appwrite Cloud&lt;/strong&gt; or &lt;strong&gt;self-hosted,&lt;/strong&gt; and you can take your Flutter app live in just a few clicks.&lt;/p&gt;

&lt;h1&gt;
  
  
  More resources
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/docs/producst/sites" rel="noopener noreferrer"&gt;Appwrite Sites docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/blog/post/open-source-vercel-alternative" rel="noopener noreferrer"&gt;Appwrite compared to Vercel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/VtDe6hDw91k" rel="noopener noreferrer"&gt;Appwrite Sites product tour&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/0cERQxFjTW4" rel="noopener noreferrer"&gt;Appwrite Sites video announcement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://appwrite.io/discord" rel="noopener noreferrer"&gt;Appwrite Discord server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>flutter</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Building a Location-Based App with Appwrite</title>
      <dc:creator>Steven</dc:creator>
      <pubDate>Tue, 13 May 2025 05:44:16 +0000</pubDate>
      <link>https://dev.to/stnguyen90/building-a-location-based-app-with-appwrite-2l0f</link>
      <guid>https://dev.to/stnguyen90/building-a-location-based-app-with-appwrite-2l0f</guid>
      <description>&lt;p&gt;During my time on the &lt;a href="https://appwrite.io/discord" rel="noopener noreferrer"&gt;Appwrite discord&lt;/a&gt; server, I’ve seen a handful of people ask about how to use Appwrite to create an app using GPS coordinates considering Appwrite doesn’t have &lt;a href="https://github.com/appwrite/appwrite/issues/388" rel="noopener noreferrer"&gt;geo queries&lt;/a&gt; yet. Although I had some ideas for how this could be implemented, I found the opportunity to tackle this problem during the &lt;a href="https://dev.to/devteam/announcing-the-appwrite-hackathon-on-dev-1oc0"&gt;Appwrite Hackathon on Dev&lt;/a&gt; with &lt;a href="https://dev.to/stnguyen90/places-appwrite-and-maps-14kh"&gt;Places&lt;/a&gt;. Read on for details on how Places is designed and architected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69269kml781h2ylvmv22.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F69269kml781h2ylvmv22.png" alt="Use Case Diagram" width="714" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Places has 2 types of users:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Unauthenticated&lt;/li&gt;
&lt;li&gt;Authenticated&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Unauthenticated users should be able to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;View places on the map&lt;/li&gt;
&lt;li&gt;View comments on a place&lt;/li&gt;
&lt;li&gt;View photos on a place&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Authenticated users should be able to do everything unauthenticated users can do as well as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a place&lt;/li&gt;
&lt;li&gt;Add a comment on a place&lt;/li&gt;
&lt;li&gt;Add a photo on a place&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Collections
&lt;/h3&gt;

&lt;p&gt;Given the use cases defined in the Overview, the following Collections are required:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgay00h61zx5d5hcgdjtw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgay00h61zx5d5hcgdjtw.png" alt="Class Diagram" width="339" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: Appwrite’s &lt;a href="https://appwrite.io/docs/products/databases/relationships" rel="noopener noreferrer"&gt;relationship attributes&lt;/a&gt; are experimental and can lead to performance problems. To minimize the number of related documents fetched, we only create one-way many-to-one relationships from Comments and Photos to Places.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Places: Stores the places on the map using latitude and longitude&lt;/li&gt;
&lt;li&gt;Users: Stores the name users publicly since Appwrite’s Users’ data is not publicly accessible&lt;/li&gt;
&lt;li&gt;Comments: Stores comments for a place

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$createdAt&lt;/code&gt;: ISO 8601 formatted timestamp&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;place&lt;/code&gt;: one-way many-to-one relationship with Place&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user&lt;/code&gt;: one-way many-to-one relationship with Users&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;text&lt;/code&gt;: comment text&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Photos: Stores photos metadata for a place

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$createdAt&lt;/code&gt;: ISO 8601 formatted timestamp&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fileId&lt;/code&gt;: $id of the file from the &lt;a href="https://appwrite.io/docs/references/cloud/client-web/storage" rel="noopener noreferrer"&gt;Storage API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;place&lt;/code&gt;: one-way many-to-one relationship with Place&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user&lt;/code&gt;: one-way many-to-one relationship with Users&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;text&lt;/code&gt;: description of photo&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Storage
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fve3u73l3cbrou3fmwzrn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fve3u73l3cbrou3fmwzrn.png" alt="Storage Diagram" width="713" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2 buckets are used for the actual photo files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Photo Uploads: Write only bucket that allows users to submit photos&lt;/li&gt;
&lt;li&gt;Photos: Read only bucket for the photos exposed to users&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Functions
&lt;/h3&gt;

&lt;p&gt;In order to ensure the integrity of the data such that there are no comments for places that don’t exist and a user can’t impersonate another user, the Comments and Photos collections are not publicly writable. Instead, &lt;a href="https://appwrite.io/docs/functions" rel="noopener noreferrer"&gt;Appwrite Functions&lt;/a&gt; validate and auto-populate attributes before creating the document. In addition, event based functions are used for for Users and Photos.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create Comment and Create Photo
&lt;/h4&gt;

&lt;p&gt;Each of these functions accept the following input:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;placeId&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, they:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Validate &lt;code&gt;placeId&lt;/code&gt; exists by fetching for the Place by ID&lt;/li&gt;
&lt;li&gt;Auto populate user using the user ID of the user who executed the function&lt;/li&gt;
&lt;li&gt;Create document in corresponding collection&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Create User
&lt;/h4&gt;

&lt;p&gt;This function triggers when a user creates an account. The only thing the function does is creates a User document using the user ID and name.&lt;/p&gt;

&lt;h4&gt;
  
  
  Process Photo
&lt;/h4&gt;

&lt;p&gt;Because the Storage API only supports files without any other metadata besides name (which is &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/File#instance_properties" rel="noopener noreferrer"&gt;read-only&lt;/a&gt; via JavaScript), a Photos collection is used for the metadata (linking the user and place to the photo). An Appwrite function is used to keep the Photo document and file in sync as well as perform any processing on the photo. The flow for uploading a photo is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create Photo document&lt;/li&gt;
&lt;li&gt;Create File providing the Photo document ID as the custom ID&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Process Photo function, then, triggers and does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Exits if bucket is not the Photo Uploads bucket&lt;/li&gt;
&lt;li&gt;Get user ID from File read permission&lt;/li&gt;
&lt;li&gt;Validate user ID matches the Photo document’s &lt;code&gt;user&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;This ensures the user who uploaded the file is the same as the user who created the document.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Download the uploaded file from Photo Uploads bucket&lt;/li&gt;
&lt;li&gt;Resize the image so photos are not unnecessarily large&lt;/li&gt;
&lt;li&gt;Remove location metadata from the photo to protect user privacy&lt;/li&gt;
&lt;li&gt;Create a new file in Photos bucket&lt;/li&gt;
&lt;li&gt;Update the &lt;code&gt;fileId&lt;/code&gt; of the existing Photos document with the newly created file ID&lt;/li&gt;
&lt;li&gt;Delete file from Photo Uploads bucket to prevent the bucket from getting too large&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Front End
&lt;/h3&gt;

&lt;p&gt;The front end is built with the following libraries:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React&lt;/a&gt; because it’s a widely popular front end library&lt;/li&gt;
&lt;li&gt;TypeScript because the static type checking greatly improves the developer experience by catching errors early and providing informative code completion&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mui.com/" rel="noopener noreferrer"&gt;MUI&lt;/a&gt; because it’s a widely popular UI library and makes it quick and easy to build a nice looking, responsive UI&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://react-leaflet.js.org/" rel="noopener noreferrer"&gt;React Leaflet&lt;/a&gt; because we’re using React and &lt;a href="https://leafletjs.com/" rel="noopener noreferrer"&gt;Leaflet&lt;/a&gt; is an open source mobile friendly maps library with lots of &lt;a href="https://leafletjs.com/plugins.html" rel="noopener noreferrer"&gt;plugins&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Fetching GPS Data
&lt;/h4&gt;

&lt;p&gt;The magic that makes working with the GPS data so easy is the React Leaflet library. When people first came to the discord server asking how to query the data, I thought it was necessary to use trigonometry to calculate the North-South-East-West bounds given a center point and a radius.&lt;/p&gt;

&lt;p&gt;Doing the math was one approach, but I soon learned it was totally unnecessary. It turns out the React Leaflet library exposes a &lt;code&gt;map.getBounds()&lt;/code&gt; function that returns a &lt;a href="https://leafletjs.com/reference.html#latlngbounds" rel="noopener noreferrer"&gt;&lt;code&gt;LatLngBounds&lt;/code&gt; object&lt;/a&gt; containing North-South-East-West bounds of the current view of the map.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;map.getBounds()
{
  "_southWest": {
    "lat": 51.46684144864419,
    "lng": -0.15964508056640628
  },
  "_northEast": {
    "lat": 51.5429188223739,
    "lng": -0.020256042480468753
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, the only thing left to do was to build a query to filter based on these bounds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBounds&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;documentList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listDocuments&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Place&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;Collections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Places&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greater&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Places&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSouth&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lesser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Places&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Latitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getNorth&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greater&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Places&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Longitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getWest&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="nx"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lesser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Places&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Longitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getEast&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Gotchas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Panning East and West
&lt;/h3&gt;

&lt;p&gt;Since the earth is round, if you pan West, you’ll eventually end up back in the same place as you started. However, how does this translate to longitude in the app? It turns out, Leaflet doesn’t reset the longitude and just continues to decrement or increment. For example, if you start at (40.71, -74.01) and go West around the world twice to the same location again, you’ll end up at (40.71, -794.01). This causes problems when viewing places and adding a place.&lt;/p&gt;

&lt;h4&gt;
  
  
  Panning when Viewing a Place
&lt;/h4&gt;

&lt;p&gt;The problem with panning when viewing places is if a place was added at (40.71, -74.01), but the user panned to (40.71, -794.01) they wouldn’t see the place.&lt;/p&gt;

&lt;p&gt;To handle this, if a user pans past a certain point, the map will reset to stay within a certain range. When using 0 and 360 as the range, I noticed a problem where the map appeared to glitch when crossing the boundary. This can be improved by using -180 and 180 as the boundary. Since this boundary is over the Pacific Ocean, without any land, the glitch was much less visible and may not even be experienced if the user doesn’t pan across the Pacific Ocean.&lt;/p&gt;

&lt;h4&gt;
  
  
  Panning when adding a place
&lt;/h4&gt;

&lt;p&gt;The problem with the panning when adding a place is if someone pans to (40.71, -794.01) and adds a place there, when someone views the same location, but at (40.71, -74.01), the place won’t appear.&lt;/p&gt;

&lt;p&gt;To solve this problem, I modified the longitude right before sending it to Appwrite. While the longitude was less than -180, add 360. While the longitude was greater than 180, subtract 360.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As you can see, it’s perfectly possible to create a location-based app with Appwrite even without geo queries. Places effectively showcases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to design related collections&lt;/li&gt;
&lt;li&gt;How to ensure integrity of related data via Appwrite Functions&lt;/li&gt;
&lt;li&gt;How to store and fetch location data&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Although it wasn’t mentioned in this article, Places also makes use of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Realtime API to fetch asynchronously processed data&lt;/li&gt;
&lt;li&gt;Responsive design to build a Progressive Web App&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To see a demo of Places, browse to &lt;a href="https://places.pages.dev" rel="noopener noreferrer"&gt;https://places.pages.dev&lt;/a&gt;. For the full source code, check out &lt;a href="https://github.com/stnguyen90/places" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>appwrite</category>
      <category>react</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Places: Appwrite and Maps</title>
      <dc:creator>Steven</dc:creator>
      <pubDate>Sat, 07 May 2022 07:20:25 +0000</pubDate>
      <link>https://dev.to/stnguyen90/places-appwrite-and-maps-14kh</link>
      <guid>https://dev.to/stnguyen90/places-appwrite-and-maps-14kh</guid>
      <description>&lt;h3&gt;
  
  
  Overview of My Submission
&lt;/h3&gt;

&lt;p&gt;Places is an app that allows users to tag a location on a map and comment and/or upload photos for the location. &lt;/p&gt;

&lt;p&gt;The app is a responsive web app to ensure easy access without the need to download another app. The front end uses React, MUI, React Leaflet, and Redux Toolkit.&lt;/p&gt;

&lt;p&gt;I got the idea for the app after using &lt;a href="https://plug%20share.com/" rel="noopener noreferrer"&gt;Plug Share&lt;/a&gt; and thought it would be useful to have a similar app to provide information about where dog waste bag dispensers were and if they were in stock or not. In addition, it was a good way for me to play around with maps as there have been people on the Appwrite Discord server asking about how to work with location data on Appwrite. As I started building the app, however, I realized I didn't need to narrow the use case to just dog waste dispensers; the app can actually serve as a starting place for any location based app!&lt;/p&gt;

&lt;h3&gt;
  
  
  Submission Category:
&lt;/h3&gt;

&lt;p&gt;Web2 Wizards&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Code
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/stnguyen90" rel="noopener noreferrer"&gt;
        stnguyen90
      &lt;/a&gt; / &lt;a href="https://github.com/stnguyen90/places" rel="noopener noreferrer"&gt;
        places
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Places
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Places&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This app allows users to add comments and photos to locations on a map.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Getting Started&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Appwrite&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;The following steps use the &lt;a href="https://appwrite.io/docs/command-line" rel="nofollow noopener noreferrer"&gt;Appwrite CLI&lt;/a&gt; to set up Appwrite.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create the project via the Appwrite Admin Console
&lt;ul&gt;
&lt;li&gt;ID: places&lt;/li&gt;
&lt;li&gt;Name: Places&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Copy the &lt;code&gt;appwrite.json.default&lt;/code&gt; to &lt;code&gt;appwrite.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Deploy the collections
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;echo a | appwrite deploy collection&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Create an API Key
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;appwrite projects createKey --projectId places --name "Places Functions" --scopes documents.read documents.write files.read files.write&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Take note of the &lt;code&gt;secret&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Deploy the functions
&lt;ol&gt;
&lt;li&gt;Update variables in the &lt;code&gt;appwrite.json&lt;/code&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;APPWRITE_FUNCTION_ENDPOINT&lt;/code&gt; - your HTTPS Appwrite endpoint&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;APPWRITE_FUNCTION_API_KEY&lt;/code&gt; - the &lt;code&gt;secret&lt;/code&gt; from the previous step&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Compile each of the functions in the &lt;code&gt;appwrite-functions&lt;/code&gt; folder:
&lt;ol&gt;
&lt;li&gt;Go into the function folder&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npm i &amp;amp;&amp;amp; npm run build&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Go back up to the folder with &lt;code&gt;appwrite.json&lt;/code&gt; and deploy all the functions:
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;echo a | appwrite deploy function&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Create the storage buckets
&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;appwrite storage createBucket --bucketId photo-uploads --name&lt;/code&gt;…&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/stnguyen90/places" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Additional Resources / Info
&lt;/h3&gt;

&lt;p&gt;A live demo can be accessed &lt;a href="https://places.pages.dev/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Technical details of the app can be found &lt;a href="https://medium.com/@stnguyen90/building-a-location-based-app-with-appwrite-48a2e2b6d4c2" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>appwritehack</category>
      <category>react</category>
      <category>typescript</category>
      <category>leaflet</category>
    </item>
    <item>
      <title>Handling Null JSON Arrays in Go</title>
      <dc:creator>Steven</dc:creator>
      <pubDate>Fri, 10 Jul 2020 21:25:09 +0000</pubDate>
      <link>https://dev.to/stnguyen90/handling-null-json-arrays-in-go-1o52</link>
      <guid>https://dev.to/stnguyen90/handling-null-json-arrays-in-go-1o52</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F10944%2F0%2AziNdAFPl98V9thNL" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F10944%2F0%2AziNdAFPl98V9thNL" alt="Photo by [JESHOOTS.COM](https://unsplash.com/@jeshoots?utm_source=medium&amp;amp;utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the most frustrating things with Go is how it handles empty arrays when encoding JSON. Rather than returning what is traditionally expected, an empty array, it instead returns null. For example, the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Outputs:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"Items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This occurs because of how the &lt;a href="https://golang.org/pkg/encoding/json/#Marshal" rel="noopener noreferrer"&gt;json package&lt;/a&gt; handles nil slices:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Array and slice values encode as JSON arrays, except that []byte encodes as a base64-encoded string, and a &lt;strong&gt;nil slice encodes as the null JSON value&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are some proposals to amend the json package to handle nil slices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/golang/go/issues/37711" rel="noopener noreferrer"&gt;encoding/json &lt;code&gt;nilasempty&lt;/code&gt; to encode nil-slices as &lt;code&gt;[]&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/golang/go/issues/27589" rel="noopener noreferrer"&gt;encoding/json: “nonil” struct tag to marshal nil slices and maps as non-null&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, as of this writing, these proposals have not been accepted. As such, in order to overcome the problem of null arrays, we have to set nil slices to empty slices. See the addition of line 22 in the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Changes the output to:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"Items"&lt;/span&gt;&lt;span class="p"&gt;:[]}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;However, this can become quite tedious to do everywhere there can potentially be a nil slice. Is there a better way to do this? Let’s see!&lt;/p&gt;
&lt;h1&gt;
  
  
  Method 1: Custom Marshaler
&lt;/h1&gt;

&lt;p&gt;According to the &lt;a href="https://golang.org/pkg/encoding/json/#Marshal" rel="noopener noreferrer"&gt;Go json docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Marshal traverses the value v recursively. If an encountered value implements the Marshaler interface and is not a nil pointer, &lt;strong&gt;Marshal calls its MarshalJSON method to produce JSON&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, if we implement the &lt;code&gt;Marshaler&lt;/code&gt; interface:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="c"&gt;// Marshaler is the interface implemented by types that&lt;/span&gt;
&lt;span class="c"&gt;// can marshal themselves into valid JSON.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Marshaler&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;MarshalJSON&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Our &lt;code&gt;MarshalJSON()&lt;/code&gt; will be called when encoding the data. See the additional &lt;code&gt;MarshalJSON()&lt;/code&gt; at line 14:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;This would then output:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"Items"&lt;/span&gt;&lt;span class="p"&gt;:[]}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;Alias&lt;/code&gt; on line 15 is required to prevent an infinite loop when calling &lt;code&gt;json.Marshal()&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Method 2: Dynamic Initialization
&lt;/h1&gt;

&lt;p&gt;Another way to handle nil slices is to use the &lt;a href="https://golang.org/pkg/reflect/" rel="noopener noreferrer"&gt;reflect package&lt;/a&gt; to dynamically inspect every field of a struct; if it’s a nil slice, replace it with an empty slice. See &lt;code&gt;NilSliceToEmptySlice()&lt;/code&gt; on line 15:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;This would then output:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"Items"&lt;/span&gt;&lt;span class="p"&gt;:[]}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Review&lt;br&gt;
&lt;/h1&gt;

&lt;p&gt;The drawback of the custom marshaler is you have to write one for every struct that has slices. Because it’s custom, though, it can target the specific field that might be a nil slice.&lt;/p&gt;

&lt;p&gt;The dynamic initialization approach is definitely slower because every field of the struct needs to be inspected to see if it needs to be replaced. However, this approach works well if you have lots of structs with slices and few places where you call &lt;code&gt;json.Marshal()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Which approach would you use? Let me know in the comments below!&lt;/p&gt;

</description>
      <category>tipsandtricks</category>
      <category>go</category>
      <category>json</category>
    </item>
  </channel>
</rss>
