<?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: Ante Barić</title>
    <description>The latest articles on DEV Community by Ante Barić (@capjavert).</description>
    <link>https://dev.to/capjavert</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%2F860995%2F6e23ecb3-c320-4184-a0a5-243dfc820698.jpeg</url>
      <title>DEV Community: Ante Barić</title>
      <link>https://dev.to/capjavert</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/capjavert"/>
    <language>en</language>
    <item>
      <title>How single message broke all our monitoring and dashboards</title>
      <dc:creator>Ante Barić</dc:creator>
      <pubDate>Thu, 02 May 2024 16:22:16 +0000</pubDate>
      <link>https://dev.to/capjavert/how-single-message-broke-all-our-monitoring-and-dashboards-40a6</link>
      <guid>https://dev.to/capjavert/how-single-message-broke-all-our-monitoring-and-dashboards-40a6</guid>
      <description>&lt;p&gt;&lt;strong&gt;So.. this just happened (or depending on when you are reading, it happened some time ago) and while I look at my beautiful dashboards working again I am contemplating, despite all the modern tech, how fragile software can be these days…&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For the last 1.5 years, I have been using &lt;a href="https://axiom.co/"&gt;Axiom&lt;/a&gt; for all of my logs ingestion, querying, and monitoring needs. It is a great product and I never had one issue with it in my time using it. Spoiler alert, even today, when it failed it was actually my fault, but let's see what happened.&lt;/p&gt;

&lt;p&gt;Axiom has a feature called &lt;a href="https://axiom.co/docs/query-data/virtual-fields"&gt;virtual fields&lt;/a&gt; that allows you to compute log properties on the fly from other properties. One use case is parsing JSON payloads in logs and then expanding them with fields from that parsed JSON. For example, if I have the log entry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;event&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;impression&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;jhfdsf334j24j&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;&lt;span class="w"&gt;
&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;I can use the virtual field to extract &lt;code&gt;event&lt;/code&gt; property from that log entry and then filter over it as with any other "real" log field. Virtual fields are (like other queries) created in Axiom Processing Language (&lt;a href="https://axiom.co/docs/apl/introduction"&gt;APL&lt;/a&gt;). It looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;['dataset']
| extend event = iff(isnotnull(parse_json(message)), parse_json(message)["event"], "")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To explain it quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;iff returns first non &lt;code&gt;null&lt;/code&gt; value (value of &lt;code&gt;event&lt;/code&gt; or empty string)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;isnotnull&lt;/code&gt; checks if the value is &lt;code&gt;null&lt;/code&gt;, to avoid parsing fields that are not JSON&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;parse_json&lt;/code&gt; parses value as JSON&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With the above I could query all of my logs in Axiom by event field which was great, up until today. I got an email from Axiom saying that one of my monitors was auto-disabled. This was due to query, that monitor was using, failing multiple times. I opened it to see what was going on and quickly closed it because I was doing something else. A few minutes passed and I noticed one of the dashboards I was using was broken, I refreshed the page thinking it was a temporary error, but it did not help. The error said, "&lt;strong&gt;cannot index value of type string&lt;/strong&gt;".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdhc37mfkxnqxx0elax9.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftdhc37mfkxnqxx0elax9.jpeg" alt="Image of dashboard screen showing errors instead of data." width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since I did not change the dashboard or any setup on my side for weeks and after checking Axiom status page I reported an issue on their Discord server. I quickly got a reply that all systems were green from their end. One thing that Axiom representative said is to try and change the query time to something else eg. query logs from yesterday instead of the last X hours how I had it set up. To my surprise changing it to yesterday made my dashboard work again. At this point, I figured that it must be some specific log entry in some period that is causing an error. I played with &lt;code&gt;FROM&lt;/code&gt; and &lt;code&gt;TO&lt;/code&gt; dates and narrowed it down to the period of &lt;code&gt;1s&lt;/code&gt; containing &lt;code&gt;40&lt;/code&gt; log entries. And yep, you read it right, in millions of logs it was down to 40 entries in the span of less than a second. Now I had to go in and look up which one of them was faulty.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxvtjkqelc538ccef8q9.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxvtjkqelc538ccef8q9.jpeg" alt="Table of log entries showing different messages." width="800" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before continuing try and guess which one of the above was a culprit?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Knowing one of them was a culprit I quickly opened JavaScript console in Chrome, pipped the entries, and executed &lt;code&gt;JSON.parse&lt;/code&gt; on them. All of them returned &lt;code&gt;SyntaxError&lt;/code&gt; except for one entry. It was the &lt;code&gt;"email"&lt;/code&gt; entry. If you parse that string (with double quotes) as JSON you get back a string &lt;code&gt;email&lt;/code&gt; (without double quotes). Which perfectly matched the error from my dashboard saying "&lt;strong&gt;cannot index value of type string&lt;/strong&gt;". My virtual field was trying to extract &lt;code&gt;event&lt;/code&gt; property from string &lt;code&gt;email&lt;/code&gt; , something like that is a no-op. Since I am using those virtual fields in almost all the places it broke literally everything. What a mess right?&lt;/p&gt;

&lt;p&gt;To fix this I had to replace my &lt;code&gt;isnotnull&lt;/code&gt; check with something else since it did not cover the above case. Browsing Axiom docs I found &lt;a href="https://axiom.co/docs/apl/scalar-functions/string-functions#gettype()"&gt;gettype&lt;/a&gt; utility function that returns the type of data passed to it. I also found exact example in their docs that &lt;code&gt;parse_json&lt;/code&gt; can return a &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe40d4h0vzhkbvmagfye9.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe40d4h0vzhkbvmagfye9.jpeg" alt="Examples of parse_json usage for Axiom Processing Language showing the function can return string in certain case." width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By using the above function my fixed virtual field now extracts the value only if the parsed JSON value is a dictionary (or object in JavaScript terms). It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;['dataset']
| extend event = iff(gettype(parse_json(message)) == "dictionary", parse_json(message)["event"], "")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just like that, everything was working again, and he lived happily ever after…&lt;/p&gt;

&lt;p&gt;Thanks for reading! 🙈&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExcXpjdjZnZnNhMmJrMnByYXZjaTVobTExbHYxcGR4d29mODdsZ2QzcSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/XQf2LxzdXBt8yo6NcA/giphy-downsized.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExcXpjdjZnZnNhMmJrMnByYXZjaTVobTExbHYxcGR4d29mODdsZ2QzcSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/XQf2LxzdXBt8yo6NcA/giphy-downsized.gif" alt="Image showing Ron Swanson drinking Whiskey" width="373" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you enjoyed this post I would appreciate the like or share and if you are interested here are some of my other posts/projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://medium.com/@capJavert/doing-100-000-push-ups-this-year-with-the-help-of-siri-605c3c8eb18f"&gt;How I did 100,000 push-ups in a year&lt;/a&gt; 💪&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://javascript.plainenglish.io/integrating-rust-into-next-js-how-to-developer-guide-10e533470d71"&gt;Integrating Rust into Next.js&lt;/a&gt; - How-To Developer Guide&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://get.komfy.app"&gt;Get Komfy App&lt;/a&gt; - Stream your favorite video content from your phone directly to your PC or Mac 📺&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/@capJavert/re-hacking-wordle-114ba75d1344"&gt;How I hacked Wordle&lt;/a&gt; - the most popular game in the world ⌨️&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jawa.sh"&gt;Jawa - Visual scraper&lt;/a&gt; interface - exports to puppeteer script which you can run anywhere and scrape anything 🤖&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>logging</category>
      <category>data</category>
      <category>javascript</category>
      <category>json</category>
    </item>
    <item>
      <title>Integrating Rust into Next.js: How-To Developer Guide</title>
      <dc:creator>Ante Barić</dc:creator>
      <pubDate>Tue, 12 Mar 2024 14:55:25 +0000</pubDate>
      <link>https://dev.to/capjavert/integrating-rust-into-nextjs-how-to-developer-guide-4jo6</link>
      <guid>https://dev.to/capjavert/integrating-rust-into-nextjs-how-to-developer-guide-4jo6</guid>
      <description>&lt;p&gt;&lt;strong&gt;Rust is one of the latest languages that got a lot of spotlight in the developer community. When talking performance it rivals C/C++ but it is also accessible enough to be used for a wide range of tasks and can run on many different platforms. One of those platforms is, of course, the web. In this post we will dive into how you can start using Rust in your web projects and platforms you are already familiar with.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;Web development was caught in the Rust storm and so far it looks like a great fit. Rust entered on a high note with standard JavaScript tooling like bundlers, compilers, test runners, and even runtimes being (re)written in Rust with massive performance gains. As a long-time programmer who worked in production projects with a bunch of different languages like PHP, Python, Objective C, Swift, and JavaScript my goal with learning a new language is always to start writing production code as soon as possible. Don't get me wrong, fundamentals are important but where you see and learn the nuances of the language is solving real problems.&lt;/p&gt;

&lt;p&gt;Recently my focus has been on the backend and APIs so my goal with Rust was to start writing new API endpoints for my projects in Rust instead of the usual JavaScript/Node.js. If you read any of my articles you might already know that I use Vercel to host most of my projects. I like the versatility it provides, allows me to deploy a bunch of different frameworks and mostly forget about the hurdle of managing infrastructure for the apps I am working on and just focus on delivering features. Naturally, I was curious if it is possible to build, deploy, and run Rust code on the Vercel platform and if I can integrate it into my current (mostly) JavaScript-based projects.&lt;/p&gt;

&lt;p&gt;To my delight, there are multiple ways to deploy Rust code on Vercel. We will go through different options and then go into details with the option I chose to go with.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Using WebAssembly (Wasm) at the Edge.&lt;/strong&gt; This allows us to write Rust code which we can then compile into &lt;code&gt;.wasm&lt;/code&gt; binary which we can import as any other package/file into our JavaScript code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using custom Rust runtime.&lt;/strong&gt; Aside from deploying Node.js and frameworks such as Next.js, Vercel supports a range of custom runtimes that allow the deployment of native code compiled from other languages like Go, Python, and also Rust. Some of those runtimes are Vercel-maintained and some, like Rust runtime, are community-maintained. Both work pretty well (I used PHP and Python runtimes before).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using Rust runtime in the Next.js project.&lt;/strong&gt; While using Rust runtime with Vercel is great, a lot of my projects are actually on frameworks like Next.js. To boost the number of projects in which I can use Rust I decided to integrate a template using Rust runtime with Next.js. That way I could gradually implement some features for my projects in Rust. It will also allow me to learn Rust more by using it each day.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We are going to start with a fresh &lt;a href="https://nextjs.org/docs/pages/api-reference/create-next-app"&gt;create-next-app&lt;/a&gt; project to show the modifications needed to make this work. This will also provide you with steps you can take to do it in your project as well. Of course, I also have my template linked on GitHub below.&lt;/p&gt;

&lt;p&gt;When you have your Next.js project up and running we can start to put Rust in the mix. If you were wondering this should all work on Next.js version 12.x, 13.x and 14.x and also with pages or app directory. To make use of custom runtimes we need to add &lt;code&gt;vercel.json&lt;/code&gt; configuration file to our project.&lt;/p&gt;


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


&lt;p&gt;We are also going to run &lt;code&gt;npm install vercel -D&lt;/code&gt; to add &lt;code&gt;vercel&lt;/code&gt; CLI to our dev dependencies. We will use it to run a local server for our Rust API endpoints. What this will do is tell Vercel to deploy any of our &lt;code&gt;.rs&lt;/code&gt; files as serverless API functions with Rust runtime. The next thing is to create top-level &lt;code&gt;api/&lt;/code&gt; directory inside of our project. This differs from &lt;code&gt;pages/api/&lt;/code&gt; directory that you might already have in your Next.js project. If you have any code inside &lt;code&gt;pages/api/&lt;/code&gt; just keep it there as is and proceed to create top-level &lt;code&gt;/api&lt;/code&gt; directory for our Rust runtime functions.&lt;/p&gt;

&lt;p&gt;You will also need to have Rust installed on your local machine. The quickest way is with &lt;a href="https://rustup.rs/"&gt;rustup&lt;/a&gt;, so you can go ahead and install it if you don't have it already. Rust uses &lt;a href="https://github.com/rust-lang/cargo"&gt;cargo&lt;/a&gt; as a package manager and build system. We get everything we need to build and run our Rust code locally with a single command. To enable cargo we need to create &lt;code&gt;Cargo.toml&lt;/code&gt; configuration file in the root of our project.&lt;/p&gt;


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


&lt;p&gt;If you are familiar with package.json it has some similarities. We add some general metadata like name and version, and we then add dependencies we need to build our API endpoints. In Rust dependencies are called "crates" and are hosted on &lt;a href="https://crates.io/"&gt;crates.io&lt;/a&gt; We use &lt;a href="https://tokio.rs/"&gt;tokio&lt;/a&gt; as async runtime, &lt;code&gt;serde_json&lt;/code&gt; for JSON parsing/transform and &lt;code&gt;vercel_runtime&lt;/code&gt; which is Rust equivalent of Vercel or Next.js APIs to manipulate requests and responses. Also, if you are using VSCode you can install &lt;a href="https://rust-analyzer.github.io/"&gt;rust-analyzer&lt;/a&gt; extension which will enable all the Rust language features and give you some more help and context when writing code.&lt;/p&gt;

&lt;p&gt;Next, we are going to create our first Rust API endpoint. We will name it &lt;code&gt;api/crab.rs&lt;/code&gt; as we wrote in our cargo config file.&lt;/p&gt;


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


&lt;p&gt;Now, if you never wrote a line of code in Rust this might not be 100% clear but if you used Vercel or some HTTP server in any language it should be mostly readable. We create a handler function that will be called to respond when API request is made to &lt;code&gt;GET /api/crab&lt;/code&gt;. It responds with &lt;code&gt;200 OK&lt;/code&gt; status code and returns a message in JSON format.&lt;/p&gt;

&lt;p&gt;We are going to quickly test it by running &lt;code&gt;npx vercel dev&lt;/code&gt;. If you created a new project this will prompt you to set up your Vercel project, just follow the prompts to set it up. When it goes through it will say something like "Ready! Available at localhost:3000". If you open &lt;a href="http://localhost:3000/api/crab"&gt;http://localhost:3000/api/crab&lt;/a&gt; in your browser after a few seconds you should see the response.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3hmpxoprw1mm9jwngh2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp3hmpxoprw1mm9jwngh2.png" alt="Browser window with JSON response from our Rust API endpoint." width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Response from our Rust API endpointIf you refresh again you will see the response comes back almost instantly. That is because &lt;code&gt;vercel dev&lt;/code&gt; under the hood used cargo to build and run our Rust file on the fly. This also automatically detects changes so it will only recompile when you change something in the code. So just write code and enjoy. You might have noticed there is a &lt;code&gt;target/&lt;/code&gt; folder in your root directory now, this is the standard output folder for Rust binaries so you want to add it to your &lt;code&gt;.gitignore&lt;/code&gt; file. You can also add those to your &lt;code&gt;.vercelignore&lt;/code&gt; (check the template at the end for reference).&lt;/p&gt;

&lt;p&gt;Now that we have everything up and running let's clean it up a bit and run it with the rest of our Next.js codebase. Rust runtime will take care of running our Rust code when deployed to Vercel but for dev, we will modify or &lt;code&gt;npm run dev&lt;/code&gt; command a bit.&lt;/p&gt;


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


&lt;p&gt;What we do here is that we run Rust API on different port with new &lt;code&gt;dev:rust&lt;/code&gt; script. Then in addition to running &lt;code&gt;next dev&lt;/code&gt; we also add it to our standard dev script. Now we can run everything in a single command that we are used to in Next.js projects.&lt;/p&gt;

&lt;p&gt;Another thing is that we don't want to go to localhost:3001 for our Rust endpoints which will be a different port than the default localhost:3000 for Next.js. We will fix it by adding a rewrite inside our &lt;code&gt;next.config.js&lt;/code&gt;.&lt;/p&gt;


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


&lt;p&gt;We apply rewrite only in development. On Vercel it will all be deployed to the same deployment so no need for a rewrite. Now you can go to &lt;a href="http://localhost:3000/api/crab"&gt;http://localhost:3000/api/crab&lt;/a&gt; again and it will work the same way even though it is running on a different dev server. Adding rewrite to &lt;code&gt;fallback&lt;/code&gt; also makes sure that any of your existing &lt;code&gt;pages/api&lt;/code&gt; endpoints do not get overwritten by Rust API endpoints in development.&lt;/p&gt;

&lt;p&gt;Now that we have everything up and running let's take a look at some common patterns you might need (or would use) in day-to-day API development.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Caching&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Any production-ready API uses some kind of caching. When deploying on Vercel we can use their &lt;a href="https://vercel.com/docs/edge-network/overview"&gt;Edge Network (CDN)&lt;/a&gt; to cache API responses. It works with standard &lt;code&gt;cache-control&lt;/code&gt; headers and &lt;code&gt;s-maxage&lt;/code&gt; directives in response. To cache our API endpoint to 1 hour we can do the following.&lt;/p&gt;


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


&lt;p&gt;&lt;strong&gt;Reading request parameters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vercel_runtime&lt;/code&gt; allows us to read data from incoming requests. Here are some common examples.&lt;/p&gt;


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


&lt;p&gt;&lt;strong&gt;Common utils/libs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With bigger projects, you would probably have a set of utils that are used across different API endpoints. With Rust, we can also register local crates in our Cargo config.&lt;/p&gt;


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


&lt;p&gt;I decided to put all of my shared Rust code inside src/rs directory to separate from other JavaScript files. In this crate I can define functions and macros to be reused in my Rust API endpoints. To use these functions just import them as from any other Rust crate. If you installed &lt;a href="https://rust-analyzer.github.io/"&gt;rust-analyzer&lt;/a&gt; or similar language integration in your IDE just starting to type the function name will allow you to auto-import.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment variables&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can access all of your env variables from a local .env file or your Vercel deployment. I recommend &lt;a href="https://crates.io/crates/dotenv"&gt;dotenv&lt;/a&gt; crate which is nice and easy to use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error handling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You don't want your JSON APIs to crash with ugly unhandled exceptions. Rust has a specific way of &lt;a href="https://doc.rust-lang.org/book/ch09-00-error-handling.html"&gt;handling errors&lt;/a&gt; but to catch or throw structured errors in my API endpoints I added a macro to my utils which I use all around the project.&lt;/p&gt;


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


&lt;p&gt;It accepts message, error, and HTTP status code which then get logged and return a response with the nice error message and status code that was provided. In addition, few macros are available for common cases like throwing generic &lt;code&gt;500&lt;/code&gt; errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Different request methods&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can support different request methods like &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt; and &lt;code&gt;DELETE&lt;/code&gt;. Each API function can handle multiple request methods so let's see how to validate and limit which methods API endpoint accepts. First, we will define a separate function for each of our request methods. For example for &lt;code&gt;POST&lt;/code&gt; method.&lt;/p&gt;


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


&lt;p&gt;Then in our handler, we validate and map correct functions to request methods.&lt;/p&gt;


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


&lt;p&gt;&lt;strong&gt;Communicating with other services&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;API endpoints can communicate with other services over different protocols. Most of the time it is over HTTP and for that, I recommend &lt;a href="https://crates.io/crates/reqwest"&gt;reqwest&lt;/a&gt; crate which works well with other packages we already use. You can see some examples inside my linked template project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cold boot and startup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Deploying serverless comes with a cost. Sometimes your users will hit an endpoint without a prepared instance and will have to experience a cold boot delay. One of the factors affecting cold boots is the size. From my testing compiled serverless functions on Vercel with Rust runtime are smaller than Node.js functions with a similar amount of code but larger than Edge functions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fssmuedk02zpbv23nhdhp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fssmuedk02zpbv23nhdhp.png" alt="Breakdown of serverless function size for Node.js, Rust and Edge runtimes. From worse to best in that order." width="800" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cold boots vary between Node.js and Edge runtimes on VercelAs for cold boot performance I measured it ranges from 500–1000ms. When hitting warm/ready instance performance is great and if your project gets a lot of requests (together with caching) you will not have any issues with your Rust-implemented API endpoints.&lt;/p&gt;

&lt;p&gt;I have been using this setup in some of my projects successfully for the past few months. One of those &lt;a href="https://shareimdb.com/"&gt;https://shareimdb.com/&lt;/a&gt; is fully run on Rust runtime in terms of API and I am using JavaScript/React only for pages needing HTML rendering. The project profited a lot by doing underlying scraping and parsing with Rust instead of Node.js. For example, I would have trouble fitting headless browser runtime in a severless function 50mb limit, but with Rust, it was not an issue since the size was smaller. The most important thing is to pick the right tool for the job. Anyone who worked on any kind of long-term production project will know that the "rewrite everything mindset" is not viable. With that in mind this kind of partial integration and usage of different technologies/languages on a single project is perfect because they can co-exist and if picked correctly can make the project better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issues&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I want to end this by pointing out some issues that I encountered while using Rust in production on Vercel. As said, I have been running this successfully for the last few months but I want to point out some pain points I had and bugs I encountered to hopefully save you some time in decisions and debugging.&lt;/p&gt;

&lt;p&gt;One issue that I noticed is that sometimes &lt;code&gt;vercel dev&lt;/code&gt; running Rust runtime functions would just crash for no obvious reason. For example, when you add specific dependencies through cargo it might require restart of &lt;code&gt;vercel dev&lt;/code&gt;. Sometimes when adding a new file to the cargo config or as a lib I would also need to re-run my dev command or kill node process that is running the server. While this is a community runtime (acknowledged by Vercel) I hope in the future they also add Rust as an official runtime.&lt;/p&gt;

&lt;p&gt;Another bigger issue is that there is a problem with Vercel when deploying dynamic routes with any custom runtime (not just Rust). You can read the details on the &lt;a href="https://github.com/vercel/next.js/issues/56869"&gt;bug report I opened on Vercel GitHub&lt;/a&gt;. There are also some alternatives to how to avoid this inside the ticket.&lt;/p&gt;




&lt;p&gt;All in all, I loved that I was able to add Rust to my existing development stack and projects. &lt;strong&gt;You can take a look at my &lt;a href="https://github.com/capJavert/next-rust"&gt;Next.js + Rust template&lt;/a&gt; created from this blog post for more code and examples. You can also use it as a template for your new projects.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you enjoyed this post I would appreciate the like or share and if you are interested in learning more about this subject here are some links to continue reading.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vercel-community/rust"&gt;Rust runtime for Vercel (community)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vercel.com/docs/functions/runtimes"&gt;Vercel-supported custom runtimes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://doc.rust-lang.org/book/"&gt;Rust Book&lt;/a&gt; - a crucial resource for learning rust fundamentals&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_Wasm"&gt;Web Assembly for Rust&lt;/a&gt; and &lt;a href="https://vercel.com/docs/functions/wasm"&gt;Wasm on Vercel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;My &lt;a href="https://github.com/capJavert/next-rust"&gt;Next.js + Rust template&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And some of my other posts/projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://jawa.sh-"&gt;https://jawa.sh-&lt;/a&gt; Visual scraper interface, exports to puppeteer script which you can run anywhere and scrape anything 🤖&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/@capJavert/doing-100-000-push-ups-this-year-with-the-help-of-siri-605c3c8eb18f%E2%80%8A-%E2%80%8AHow"&gt;https://medium.com/@capJavert/doing-100-000-push-ups-this-year-with-the-help-of-siri-605c3c8eb18f - How&lt;/a&gt; I did 100,000 push-ups in a year 💪&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://get.komfy.app%E2%80%8A-%E2%80%8AStream"&gt;https://get.komfy.app - Stream&lt;/a&gt; your favorite video content from your phone directly to your PC or Mac 📺&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/@capJavert/re-hacking-wordle-114ba75d1344%E2%80%8A-%E2%80%8AHow"&gt;https://medium.com/@capJavert/re-hacking-wordle-114ba75d1344 - How&lt;/a&gt; I hacked the most popular game in the world ⌨️&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rust</category>
      <category>nextjs</category>
      <category>javascript</category>
      <category>vercel</category>
    </item>
    <item>
      <title>Seamless emoji creation on Discord with bots and Vercel</title>
      <dc:creator>Ante Barić</dc:creator>
      <pubDate>Sat, 06 Jan 2024 10:16:55 +0000</pubDate>
      <link>https://dev.to/capjavert/seamless-emoji-creation-on-discord-with-bots-and-vercel-4fdj</link>
      <guid>https://dev.to/capjavert/seamless-emoji-creation-on-discord-with-bots-and-vercel-4fdj</guid>
      <description>&lt;p&gt;&lt;strong&gt;Seamless emoji creation on Discord with bots and Vercel&lt;br&gt;
Photo by Zen Chung from PexelsCustom emojis are a great way to add identity and a sense of fellowship to any Discord server. Users quickly get ideas for new emojis from messages shared in the server but the most common issue is that it takes some work to transfer those ideas and images to emojis. Discord has restrictions on the resolution, type, and size of an image that is required to create an emoji. But, people are lazy, and with those restrictions and additional work required to create them, many cool emojis are left as just ideas…&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have ever been a part of Discord server you will know that many of them have different bots installed to help with various tasks. Bots can send messages to channels, perform moderation, embed remote content like tweets, and also reply and react to commands from users. The last feature, commands, is especially interesting because it allows users to perform advanced and custom actions inside the Discord server. For example, we could develop a command to create emoji from any image.&lt;/p&gt;

&lt;p&gt;Since my (and many other) servers already have a custom bot I decided to try and add a new command that would do just that. The idea sounded great in my head but at first, I was not sure what would take to actually develop it. Manipulating images usually requires some processing power, a dedicated server, and storage. To entertain this idea let's see what would be required for this feature to be added to our server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discord bot (my server already had one but if you want to create your own take a look at &lt;a href="https://discordjs.guide"&gt;https://discordjs.guide&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A way for users to input an image and some data like emoji name&lt;/li&gt;
&lt;li&gt;Server or application capable of processing the image and adjusting it to given Discord restrictions&lt;/li&gt;
&lt;li&gt;Uploading adjusted emoji image to Discord as new emoji&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As mentioned above, my Discord bot is implemented in Node.js with the help of &lt;a href="https://discordjs.guide/"&gt;Discord.js&lt;/a&gt; package. Their guide has an in-depth instructions on how to set up a basic bot, register it for use on Discord, and also some ideas on where and how to deploy it. I won't be going into those details in this blog post but will provide a basic skeleton of it using the above package.&lt;/p&gt;

&lt;p&gt;Once I had my Discord bot up and running the first thing was to solve the handling of user input. Users usually have an image they would like to convert to an emoji so we can start with that. Also, each emoji needs a unique name with which it can be used in messages and reactions, it is an alphanumeric phrase (_ is also allowed) without spaces or special characters. If you speak regex this would match:&lt;/p&gt;


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


&lt;p&gt;Luckily Discord command can accept text and images as input so we can collect all the data needed to create an emoji from our user right from Discord interface. Discord.js exports &lt;a href="https://discordjs.guide/creating-your-bot/slash-commands.html#individual-command-files"&gt;SlashCommandBuilder&lt;/a&gt; class which allows us to define what inputs our command accepts.&lt;/p&gt;


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


&lt;p&gt;What we need now is to handle the above input. The most important thing is the image and its conversion. To convert the image we will use the cool feature of Vercel which is called &lt;a href="https://vercel.com/docs/functions/edge-functions/og-image-generation"&gt;Open Graph (OG) Image Generation&lt;/a&gt;. This feature is available as a standalone package and also inside Next.js framework. Since I used Next.js for my general purpose server and API I decided to add a new API endpoint to handle image adjustment. The above image generation package uses JSX to create images from HTML and CSS markup or even custom React components. So to adjust the image all I needed to do was to render &lt;code&gt;&amp;lt;img /&amp;gt;&lt;/code&gt; tag inside JSX and set &lt;code&gt;style&lt;/code&gt; attribute to correct size and fit values. This is how my request handler looks like:&lt;/p&gt;


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


&lt;p&gt;I also added the &lt;code&gt;fit&lt;/code&gt; param to allow further customization of how image should be fitted to square dimension of the emoji. If the image aspect ratio is 16:9 with &lt;code&gt;fit: cover&lt;/code&gt; we can cut it in the middle and alternatively with &lt;code&gt;fit: contain&lt;/code&gt; we can resize it to fit 1:1 aspect. If you don't use Next.js you should still be able to use &lt;code&gt;@vercel/og&lt;/code&gt; package with your Node.js framework of choice. It is a great way to adjust the image per Discord requirements without using any heavy image processing or requiring additional storage.&lt;/p&gt;

&lt;p&gt;Now that we have our image ready we can connect it with the rest of the data and create a handler for our slash command.&lt;/p&gt;


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


&lt;p&gt;In the above command, we take options from &lt;a href="https://discordjs.guide/creating-your-bot/command-handling.html#receiving-command-interactions"&gt;Interaction&lt;/a&gt; object passed from our slash command. We then take the original image URL from Discord and pass it to our API endpoint together with &lt;code&gt;fit&lt;/code&gt; option. The response of our endpoint (which is an image) is then parsed as &lt;code&gt;ArrayBuffer&lt;/code&gt; and then passed to Discord.js function which registers new emoji in the Discord server that our bot is currently running in. ✅&lt;br&gt;
Here is a sneak peek of how all of this works together inside Discord app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G_wqZRyx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/is98geu53z3x3if1x4og.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G_wqZRyx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/is98geu53z3x3if1x4og.gif" alt="GIF showing usage of created command inside Discord interface" width="600" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Done and done.The above is also a good example of how an image with a wide aspect ratio fits perfectly in the square emoji after conversion. 🙌&lt;/p&gt;




&lt;p&gt;Thats it! This was a pretty cool usage of different services and technologies to create something new and a great example of what is possible with the tools we have available today. If you want to learn more about Discord and the different integrations it offers for developers you can also check out their &lt;a href="https://discord.com/developers/docs/intro"&gt;developer portal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;P.S. More complete code snippet with validation and additional command for removing an emoji &lt;strong&gt;&lt;a href="https://gist.github.com/capJavert/fec7156378e5bc0d95cbf954b2fcb999"&gt;can be found here&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you are interested in programming, tech or want to see some of my other side projects check below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://get.komfy.app%E2%80%8A-%E2%80%8AStream"&gt;https://get.komfy.app - Stream&lt;/a&gt; your favorite video content from your phone directly to your PC or Mac 📺&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/@capJavert/doing-100-000-push-ups-this-year-with-the-help-of-siri-605c3c8eb18f%E2%80%8A-%E2%80%8AHow"&gt;https://medium.com/@capJavert/doing-100-000-push-ups-this-year-with-the-help-of-siri-605c3c8eb18f - How&lt;/a&gt; I did 100,000 push-ups in a year 💪&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jawa.sh-"&gt;https://jawa.sh-&lt;/a&gt; Visual scraper interface, exports to puppeteer script which you can run anywhere and scrape anything 🤖&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/@capJavert/re-hacking-wordle-114ba75d1344%E2%80%8A-%E2%80%8AHow"&gt;https://medium.com/@capJavert/re-hacking-wordle-114ba75d1344 - How&lt;/a&gt; I hacked the most popular game in the world ⌨️&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discord</category>
      <category>vercel</category>
      <category>emoji</category>
      <category>programming</category>
    </item>
    <item>
      <title>Taskly - better way to manage your tasks</title>
      <dc:creator>Ante Barić</dc:creator>
      <pubDate>Thu, 12 May 2022 21:31:36 +0000</pubDate>
      <link>https://dev.to/capjavert/taskly-better-way-to-manage-your-tasks-2d2m</link>
      <guid>https://dev.to/capjavert/taskly-better-way-to-manage-your-tasks-2d2m</guid>
      <description>&lt;p&gt;You can try &lt;strong&gt;Taskly&lt;/strong&gt; for free at &lt;a href="https://taskly.kickass.website/" rel="noopener noreferrer"&gt;taskly.kickass.website&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of My Submission
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Taskly&lt;/strong&gt; is an app to better manage tasks across all of the different task/todo/issue/project platforms. Developers (especially in open source) often use multiple websites like GitHub and Gitlab to work on their projects and contribute to other. There is also a fair share of project management tools that have their own task/todo lists. With Taskly all of those are merged into single interface for quick access and management. When you start using Taskly it will become a central hub for all of your tasks and give you more time to focus on actually doing your job. &lt;/p&gt;

&lt;h3&gt;
  
  
  Infrastructure
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Taskly&lt;/strong&gt; is built as a full fledged web application meant to scale and serve many developers working in open source and beyond. At the core of that is Appwrite which we use as a backend for all of Taskly features. As Appwrite is ready for horizontal/vertical scaling Taskly is also ready to scale as its user base grows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication
&lt;/h3&gt;

&lt;p&gt;As we started building Taskly on Appwrite platform we used the Users module to provide authentication and social features to our users. Users can login with email/password or any of our 3party providers, all of those providers are also available to import/manage tasks from, but more on that later. &lt;/p&gt;

&lt;p&gt;Integrating authentication with our Next.js application was easy through Appwrite Web SDK and our custom &lt;a href="https://github.com/kickassCoderz/taskly/blob/master/services/authService.ts" rel="noopener noreferrer"&gt;Authenication Service&lt;/a&gt;. Authentication Service is our abstraction which allows Taskly to connect to any auth provider and use it seamlessly with other Taskly features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tasks management
&lt;/h3&gt;

&lt;p&gt;The core feature of Taskly is Tasks module. It provides a central list of your tasks with search and filtering methods to quickly organise and find tasks that you need to read, edit or (finally) complete. &lt;/p&gt;

&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbp7re9ktuw7scds7ci9d.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbp7re9ktuw7scds7ci9d.png" alt="Taskly interface"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Core building blocks for the Taskly interface are NextUI components. It is a great (open source) set of primitive UI components that give Taskly a slick look, also, don't worry, we do support &lt;strong&gt;Dark mode (｡▼皿▼)&lt;/strong&gt;.&lt;/p&gt;

&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsxov3j7hrsq9h9rynmk.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwsxov3j7hrsq9h9rynmk.png" alt="Taskly interface with Dark mode"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you first sign into your Taskly account you will be offered to connect any of the 3party apps that you use to manage your tasks like GitHub, Gitlab, Trello... Currently we only support few of them, but check back soon because more providers will be added in the future (this project was built in less than a month so bear with us), also if you wish to collaborate on that give as a ping on &lt;a href="https://github.com/kickassCoderz/taskly/pulls" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. After connecting the provider like GitHub you can select which projects issues you wish to import (we only import the things you choose because you are the Boss) and manage through Taskly.&lt;/p&gt;

&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhenqsnvohvhiitewklj5.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhenqsnvohvhiitewklj5.png" alt="Taskly provider connection interface"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After connecting any of the providers your tasks will just magically start to appear in your Tasks lists. But there is no magic here, just awesome Appwrite Functions doing their thing..&lt;/p&gt;

&lt;p&gt;After that you can create, view, edit, update and delete any of your tasks in single place. There is also a handy link to the original task for your enjoyment! &lt;strong&gt;Taskly is also optimized for mobile.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All of that is running under the hood with our &lt;a href="https://github.com/kickassCoderz/taskly/blob/master/services/dataService.ts" rel="noopener noreferrer"&gt;Data Service&lt;/a&gt; which like Auth Service allows Taskly to interact seamlessly with any 3party data source or API. This particular implementation is of course using Appwrite Web SDK. &lt;/p&gt;

&lt;p&gt;We also used permissions system from Appwrite Documents where we specifically assign permissions to read/write (Document level) tasks to the users owning them. In the future this will allow us to implement users sharing and collaborating on tasks directly through Taskly.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Importing and syncing Tasks
&lt;/h3&gt;

&lt;p&gt;In the previous section we bragged how after connecting services like GitHub and Gitlab to your account your tasks just seamlessly start to appear in the Tasks list. Here we will talk more about how that is achieved. &lt;/p&gt;

&lt;p&gt;Another cool feature Appwrite has are Functions. At Taskly we use them as background job queue. Any time new project is connected to Taskly a new function execution is started in the background. We call it "import job". Import job pulls all of the issues and data from 3party provider to display them inside Taskly interface.&lt;/p&gt;

&lt;p&gt;This gives us few things for free:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;our users do not need to wait on the loading screen for their tasks to import&lt;/li&gt;
&lt;li&gt;they can just continue working and seamlessly their tasks will start appearing as they are being imported through our import job&lt;/li&gt;
&lt;li&gt;we save user bandwidth because Appwrite lets us know in realtime when new tasks are imported&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the import job is done there is of course a possibility that someone creates a new task in your project (a pesky project manager) - we do not want you run into problems by missing a new task assigned to you. That is why we use webhooks to continuously sync new tasks and task updates to Taskly from your connected providers. This means that you can focus on your work and let Taskly handle everything else. &lt;/p&gt;

&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp10te6z1iqzt4qwuy5yg.png" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp10te6z1iqzt4qwuy5yg.png" alt="Import jobs for our currently supported providers"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Another great thing about Appwrite Functions is that you get logs and errors for free so we can monitor our job executions and potential errors for our users.&lt;/p&gt;

&lt;h3&gt;
  
  
  Realtime UI
&lt;/h3&gt;

&lt;p&gt;At Taskly we believe in fast user interfaces. We were impressed how quick the Appwrite Documents API was when fetching data for our application but we went step further. We noticed that there is also a Realtime support in Appwrite using Web Sockets. We went ahead and tried it out and it worked as a charm.&lt;/p&gt;

&lt;p&gt;Basically from the moment you open Taskly we connect to the realtime socket and listen for changes (from webhooks or async import jobs). Any time new document is added, edited or deleted we refetch those and update our local state. &lt;/p&gt;

&lt;p&gt;This also allowed to use more aggressive caching on the client side because we do not need to refetch anything until realtime socket tells us something changed. This automatically makes all of your recent/usual queries instant, Yeeey!!&lt;/p&gt;

&lt;p&gt;We were impressed by how good it worked so we also implemented it at some other parts of our UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search and filter
&lt;/h3&gt;

&lt;p&gt;Listing tasks was fine but we also wanted to add some basic search features to Taskly. As we use Appwrite Documents to store all of the user data we used Indexes and filtering options in Appwrite Web SDK to implement those.&lt;/p&gt;

&lt;p&gt;We support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fulltext search of tasks&lt;/li&gt;
&lt;li&gt;sorting by title, creation date, status&lt;/li&gt;
&lt;li&gt;filtering by task status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With those you can quickly find the relevant tasks. All of the search params are persisted inside the browser URL so until Taskly adds support for "Saved views" (Soon TM) you can for example bookmark the tasks from specific project that are still open.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is next?
&lt;/h3&gt;

&lt;p&gt;You will notice that there is a lot more to &lt;strong&gt;Taskly&lt;/strong&gt; than the features we mentioned above. That is because even though we want to make something great with Taskly we only created it in less then a month for Appwrite Hackathon. This means that it is a work in progress. If you think this is great and wish to help contribute new features to Taskly give as a ping on &lt;a href="https://github.com/kickassCoderz/taskly" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Our submission fits into "Web2 Wizards" category. Taskly is a single page (SPA) web application running with Next.js and React using Appwrite as backend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Link to Code
&lt;/h2&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/kickassCoderz" rel="noopener noreferrer"&gt;
        kickassCoderz
      &lt;/a&gt; / &lt;a href="https://github.com/kickassCoderz/taskly" rel="noopener noreferrer"&gt;
        taskly
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &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;Taskly - better way to manage your tasks&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Taskly&lt;/strong&gt; is an app to better manage tasks across all of the different task/todo/issue/project platforms. Developers (especially in open source) often use multiple websites like GitHub and Gitlab to work on their projects and contribute to other. There is also a fair share of project management tools that have their own task/todo lists. With Taskly all of those are merged into single interface for quick access and management. When you start using Taskly it will become a central hub for all of your tasks and give you more time to focus on actually doing your job.&lt;/p&gt;
&lt;p&gt;Crafted with &lt;a href="https://appwrite.io" rel="nofollow noopener noreferrer"&gt;Appwrite&lt;/a&gt; and &lt;a href="https://nextjs.org/" rel="nofollow noopener noreferrer"&gt;Next.js&lt;/a&gt; ❤️&lt;/p&gt;
&lt;p&gt;Created by &lt;a href="https://github.com/Fazla-GroM" rel="noopener noreferrer"&gt;@Fazla-GroM&lt;/a&gt; and &lt;a href="https://github.com/capJavert" rel="noopener noreferrer"&gt;@capJavert&lt;/a&gt; 🌈&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Development&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This is a &lt;a href="https://nextjs.org/" rel="nofollow noopener noreferrer"&gt;Next.js&lt;/a&gt; project bootstrapped with &lt;a href="https://github.com/vercel/next.js/tree/canary/packages/create-next-app" rel="noopener noreferrer"&gt;&lt;code&gt;create-next-app&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Getting Started&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;First, run the development server:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm run dev
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; or&lt;/span&gt;
yarn dev&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Open &lt;a href="http://localhost:3000" rel="nofollow noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; with your browser to see the result.&lt;/p&gt;
&lt;p&gt;You…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kickassCoderz/taskly" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


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

&lt;p&gt;&lt;strong&gt;Taskly&lt;/strong&gt; is crafted with ❤️:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vercel/next.js/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nextui-org/nextui" rel="noopener noreferrer"&gt;NextUI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/facebook/react/" rel="noopener noreferrer"&gt;React&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/tannerlinsley/react-query" rel="noopener noreferrer"&gt;React Query&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/react-hook-form/react-hook-form" rel="noopener noreferrer"&gt;React Hook Forms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://uiwjs.github.io/react-codemirror/" rel="noopener noreferrer"&gt;React CodeMirror&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Taskly&lt;/strong&gt; is created by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/fazlagrom"&gt;@fazlagrom&lt;/a&gt; - &lt;a href="https://github.com/Fazla-GroM" rel="noopener noreferrer"&gt;Fazla-GroM@github&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/capjavert"&gt;@capjavert&lt;/a&gt; - &lt;a href="https://github.com/capJavert" rel="noopener noreferrer"&gt;capJavert@github&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;part of &lt;a href="https://github.com/kickassCoderz" rel="noopener noreferrer"&gt;Kickass Coderz&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>appwritehack</category>
      <category>productivity</category>
      <category>nextjs</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
