<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[devgorilla - Medium]]></title>
        <description><![CDATA[https://devgorilla.xyz - Medium]]></description>
        <link>https://medium.com/devgorilla?source=rss----9ecee7b14553---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>devgorilla - Medium</title>
            <link>https://medium.com/devgorilla?source=rss----9ecee7b14553---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 22:03:02 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/devgorilla" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Building a Scalable Delivery Pipeline for Small Teams ]]></title>
            <link>https://medium.com/devgorilla/building-a-scalable-delivery-pipeline-for-small-teams-6865b020b21e?source=rss----9ecee7b14553---4</link>
            <guid isPermaLink="false">https://medium.com/p/6865b020b21e</guid>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[environment]]></category>
            <category><![CDATA[ci-cd-pipeline]]></category>
            <dc:creator><![CDATA[Arpy Vanyan]]></dc:creator>
            <pubDate>Wed, 19 Feb 2025 12:18:02 GMT</pubDate>
            <atom:updated>2025-02-19T12:18:02.805Z</atom:updated>
            <content:encoded><![CDATA[<h3>Introduction</h3><p>A well-structured <strong>delivery pipeline</strong> ensures that software is shipped <strong>smoothly, reliably, and with confidence</strong>. Whether you’re working in a small team or a large enterprise, having a <strong>clear, repeatable</strong> process is critical for delivering high-quality software.</p><p>This article breaks down a <strong>delivery pipeline setup</strong> I implemented for a project, optimizing it for small teams. It includes <strong>staging best practices, automated deployments, package management, and a ticketing system that simplifies releases.</strong></p><p>If you’re setting up a <strong>CI/CD workflow</strong> or refining your software deployment process, this guide is for you! 🚀</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*N73BzoZCpsTqw-GRz-jZlg.png" /></figure><h3>🎯 TL;DR</h3><p>✔️ Always deploy to <strong>staging first</strong> before production.<br>✔️ Use <strong>nightly builds</strong> to test new features early.<br>✔️ Automate <strong>package publishing</strong> and <strong>CI/CD deployments</strong>.<br>✔️ Keep <strong>staging clients on staging APIs</strong> to prevent conflicts.<br>✔️ Use <strong>Jira statuses</strong> like <strong>“Ready for Deploy”</strong> to improve workflow.</p><h3>1️⃣ The Importance of Staging</h3><h3>Why Staging?</h3><p>Before any new feature or fix <strong>goes live</strong>, it must be tested in an environment that closely mimics <strong>production</strong>.</p><p>A <strong>staging environment</strong> serves as a <strong>sandbox for QAs and stakeholders</strong> to validate changes <strong>before</strong> they reach real users.</p><h3>Golden Rule:</h3><blockquote><strong><em>Never</em></strong><em> ship any new code to production if it has not yet been tested and approved for deployment!</em></blockquote><p>But how should the testers access the changes if they exist only on the developer’s local system?</p><p>As the testers should act like end-users and not a part of the dev team, they should be able to access the final products in an environment that replicates the live version and includes all the latest changes that are ready to be tested. That is the staging environment.</p><p>So, the dev team should always deploy the latest finished changes to the staging environment and ask the QA to test them. Normally, the deployment might include some issues and bugs (which doesn’t mean that the dev shouldn’t test everything locally first), which the testers will notice and report.</p><p>When the testers and the PO approve the current state of the staging environment, the team prepares for a release on production.</p><h3>Deployment to Staging</h3><ul><li><strong>Developers</strong> push their latest changes to staging.</li><li><strong>Testers (QA)</strong> validate everything <strong>as end-users would</strong>.</li><li><strong>Product Owners (POs)</strong> approve before release.</li><li><strong>If it’s good, it goes live!</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/537/0*_maZ0_1oC0aFOjMI.png" /></figure><h3>2️⃣ Think of Your Product Like a Pizza 🍕</h3><p>Your product is like a <strong>pizza</strong> — it’s made up of different slices (components), and they all need to come together seamlessly when deployed. In most cases it is like a 3-slice pizza in fact:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/453/0*WE1FurFQAUNosDZU.png" /></figure><p>In this case, a deployment includes:</p><p>1️⃣ <strong>Packages</strong> (code libraries and dependencies)</p><p>2️⃣ <strong>The Server</strong> (backend APIs)</p><p>3️⃣ <strong>The Client</strong> (front-end applications)</p><p>Each of these components <strong>must be properly staged, tested, and released</strong> together for a smooth rollout.</p><h3>3️⃣ Managing Packages Efficiently</h3><p>Most modern development relies on <strong>package management</strong> to handle dependencies. Here’s how to keep it clean:</p><h3>Staging Packages with Nightly Builds 🌙</h3><p>When developing a new feature, testers should have access to <strong>pre-release versions</strong>. A <strong>nightly build</strong> ensures the latest changes are packaged daily.</p><p>📌 <strong>How to publish a nightly build:</strong></p><pre>npm publish --tag nightly</pre><p>✅ <strong>Benefits:</strong></p><ul><li>Allows <strong>early testing</strong> before an official release.</li><li>Ensures integration issues are caught early.</li><li>Automates packaging, reducing manual effort.</li></ul><p><strong>Production packages</strong>, on the other hand, should be versioned properly using <strong>semantic versioning (semver)</strong> for clarity.</p><h3>4️⃣ Deployment Workflow: From Code to Production 🚀</h3><blockquote><em>Note: Remember to set the dependency packages in nightly builds to refer to their nightly versions.</em></blockquote><h3>The Server</h3><ul><li>Runs in cloud or dedicated server, hosting the <strong>backend APIs</strong>.</li><li><strong>New code</strong> is deployed to <strong>staging first</strong> before production.</li><li>The <strong>CI/CD pipeline</strong> automates deployment.</li></ul><h3>The Client</h3><ul><li>Any changes in the front-end must be deployed in sync with the backend.</li><li>If a client instance depends on a <strong>new API</strong>, it must be tested <strong>in staging first</strong> before being moved to production.</li></ul><h3>5️⃣ Streamlining Task Management with Jira 📋</h3><p>As we want the testers to have something already deployed to Staging for them to start testing and avoid doing it locally, we need to have a new state on for the tickets called “Ready for deploy”.</p><p>It would mean the following: <em>“The code was written and reviewed and is ready to be delivered to the testers”</em>.</p><h3>Old Ticket Flow:</h3><p>To Do → In Progress → Code Review → Testing → Done</p><h3>New &amp; Improved Workflow:</h3><p>✅ To Do → In Progress → Code Review → <strong>Ready for Deploy</strong> → Testing → Done</p><p>After the sprint is finished and all the Done tasks are approved, the PO will identify the features that are ready to be delivered to the customers. For this kind of work, we will have separate deployment tasks that would skip the 3d and 4th steps during realization.</p><p>💡 <strong>Why this change?</strong></p><ul><li>Before, <strong>testers had to wait</strong> and guess when developers manually deployed the latest version to staging.</li><li>Now, with <strong>“Ready for Deploy”</strong>, testers know <strong>when a feature is available in staging</strong>.</li><li>This reduces <strong>bottlenecks</strong> and improves <strong>release efficiency</strong>.</li></ul><p>🚀 <strong>Result:</strong> Faster deployments, happier testers, and smoother releases!</p><h3>6️⃣ Final Steps to a Cleaner Pipeline</h3><p>To <strong>fully optimize</strong> the delivery process, these improvements should be implemented:</p><ul><li><strong>[Task Management]</strong> Add a “Ready for Deploy” status in Jira.</li><li><strong>[Automation]</strong> Improve CI/CD scripts to auto-publish nightly builds.</li><li><strong>[Versioning]</strong> Use <strong>semantic versioning</strong> for clarity in releases.</li><li><strong>[CI/CD Improvements]</strong> Automate deployment of <strong>server and client</strong> to both staging and production.</li><li><strong>[Environment Fix]</strong> Ensure all <strong>staging clients use staging APIs</strong> only.</li></ul><p>🚀 <em>By implementing these best practices, small teams can maintain a highly efficient delivery pipeline without unnecessary delays or confusion.</em></p><h3>Conclusion: Why This Works for Small Teams 🏆</h3><p>A <strong>structured</strong> delivery pipeline isn’t just for large teams — -it’s <strong>critical for small teams too!</strong></p><p>By <strong>automating testing and deployments</strong>, keeping environments <strong>clearly separated</strong>, and <strong>simplifying task tracking</strong>, you can:</p><p>✅ <strong>Ship faster</strong><br>✅ <strong>Catch bugs earlier</strong><br>✅ <strong>Reduce deployment stress</strong></p><p>If you’re setting up a <strong>CI/CD process</strong> for your team, <strong>start with these principles</strong> — -they will save you <strong>a ton of headaches</strong> in the long run!</p><p>💬 What challenges have you faced with setting up a delivery pipeline? Let’s discuss in the comments! 🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6865b020b21e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devgorilla/building-a-scalable-delivery-pipeline-for-small-teams-6865b020b21e">Building a Scalable Delivery Pipeline for Small Teams 🚀</a> was originally published in <a href="https://medium.com/devgorilla">devgorilla</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Prototype Chain Explained with a Library System ]]></title>
            <link>https://medium.com/devgorilla/the-prototype-chain-explained-with-a-library-system-493a62cc78dd?source=rss----9ecee7b14553---4</link>
            <guid isPermaLink="false">https://medium.com/p/493a62cc78dd</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[beginner]]></category>
            <category><![CDATA[prototype]]></category>
            <dc:creator><![CDATA[Arpy Vanyan]]></dc:creator>
            <pubDate>Wed, 19 Feb 2025 11:46:16 GMT</pubDate>
            <atom:updated>2025-02-18T17:49:39.120Z</atom:updated>
            <content:encoded><![CDATA[<h3>Ever borrowed a book from a library? Good. You already understand JavaScript Prototypes.</h3><p>Imagine you walk into your <strong>neighborhood library</strong> looking for a rare book on “The Secrets of JavaScript Sorcery.” You ask the librarian, but — oops! — your library doesn’t have it.</p><p>But don’t worry! Instead of sending you home empty-handed, the librarian <strong>calls up the central city library</strong> to check if they have it. If they do, you get your book. If not, the search continues up the chain… maybe to the <strong>National Library Archive</strong>. And if <em>even they</em> don’t have it? Sorry, no book for you.</p><p>This is <strong>exactly</strong> how JavaScript’s prototype chain works! 🚀</p><h3>📌 TL;DR</h3><ul><li>Objects in JavaScript can <strong>inherit properties</strong> from other objects.</li><li>When a property isn’t found in an object, JavaScript <strong>climbs up the prototype chain</strong> to check its prototype.</li><li>Object.create() is like opening a <strong>new library branch</strong> connected to the central library.</li><li>If a property isn’t found anywhere, JavaScript returns undefined.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rHgjfxSM0Ea0v5URsm33ow.jpeg" /><figcaption>Librarian looking for a book all the way up to <strong>National Library Archive</strong></figcaption></figure><h3>🏛 Libraries = JavaScript Objects</h3><p>In JavaScript, <strong>objects can borrow properties and methods</strong> from other objects, just like a library can request books from a bigger library system. Let’s break it down:</p><h3>1️⃣ Local Library (Your Object)</h3><p>Your library has its own <strong>collection</strong> — books it directly owns.</p><pre>const localLibrary = {<br>  specialCollection: [&quot;Ancient Maps&quot;, &quot;Rare Manuscripts&quot;]<br>};<br><br>console.log(localLibrary.specialCollection);  <br>// [&quot;Ancient Maps&quot;, &quot;Rare Manuscripts&quot;]</pre><h3>2️⃣ Central Library (Prototype)</h3><p>But what if your local library doesn’t have a specific book? It asks the <strong>Central Library</strong>, which has a much bigger collection.</p><pre>const centralLibrary = {<br>  lendBook: function() {<br>    console.log(&quot;Here’s your book from the central archive!&quot;);<br>  }<br>};</pre><h3>3️⃣ Connecting Them (Prototype Chain)</h3><p>Now, let’s <strong>link</strong> your local library to the central one using Object.create(). This way, whenever your local library doesn’t have something, it <strong>automatically</strong> looks in the central library!</p><pre>const cityLibrary = Object.create(centralLibrary);<br>cityLibrary.specialCollection = [&quot;Ancient Maps&quot;, &quot;Rare Manuscripts&quot;];<br><br>console.log(cityLibrary.specialCollection);  <br>// [&quot;Ancient Maps&quot;, &quot;Rare Manuscripts&quot;]<br>cityLibrary.lendBook();  <br>// &quot;Here&#39;s your book from the central archive!&quot;</pre><p>Even though lendBook <strong>wasn’t defined</strong> in cityLibrary, it still worked! That’s because JavaScript <strong>climbed up the prototype chain</strong> and found it in the centralLibrary.</p><h3>🛤 The Search Path (Prototype Chain in Action)</h3><p>Let’s add another library: a <strong>small-town library</strong> that borrows from the city library.</p><pre>const smallTownLibrary = Object.create(cityLibrary);<br>console.log(smallTownLibrary.specialCollection);  <br>// [&quot;Ancient Maps&quot;, &quot;Rare Manuscripts&quot;]</pre><p>Boom! Even though smallTownLibrary doesn’t have a specialCollection <strong>directly</strong>, it <strong>inherits it from cityLibrary</strong>, which inherited it from itself.</p><p>And it <strong>can still borrow books from the central library</strong>:</p><pre>smallTownLibrary.lendBook();  <br>// &quot;Here’s your book from the central archive!&quot;</pre><p>🔗 <strong>JavaScript keeps searching up the chain until it finds what it needs — or gives up!</strong></p><h3>❌ What Happens If a Book Doesn’t Exist?</h3><p>Let’s say you ask for a <strong>mystery book that no one owns</strong>:</p><pre>console.log(smallTownLibrary.rareBook);  <br>// undefined</pre><p>JavaScript checks:</p><p>1️⃣ smallTownLibrary → ❌ (Doesn’t have it)<br>2️⃣ cityLibrary → ❌ (Doesn’t have it either)<br>3️⃣ centralLibrary → ❌ (Nope!)<br>4️⃣ <strong>Object.prototype</strong> → ❌ (Last stop—if it&#39;s not here, it doesn’t exist)</p><p>Since no one has it, you get undefined.</p><p>📌 <strong>This is exactly how JavaScript searches for properties in objects.</strong></p><p>💡 <strong>Want an easier way to visualize the Prototype Chain?</strong><br>Here’s what our example looks like behind the scenes:</p><pre>smallTownLibrary  ---&gt;  cityLibrary  ---&gt;  centralLibrary  ---&gt;  Object.prototype  ---&gt;  null</pre><p>Every object in JavaScript follows this chain <strong>all the way up to </strong><strong>Object.prototype</strong>, which is like the <strong>National Library Archive</strong>—the place where common methods like .toString() exist.</p><h3>🎯 Final Thoughts</h3><p>Next time you’re borrowing a book from a library, think about JavaScript’s prototype chain working in the same way. Your local branch (object) might not have a book (property), but it always knows where to look!</p><p>This is what makes JavaScript so <strong>powerful and flexible</strong> — objects can share behavior without copying everything manually.</p><p>Now that you’ve cracked the mystery of <strong>Prototypes</strong>, where should we go next? 🤔</p><p>💡 Thinking about writing an article on <strong>how </strong><strong>new works in JavaScript</strong>? Let me know!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=493a62cc78dd" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devgorilla/the-prototype-chain-explained-with-a-library-system-493a62cc78dd">The Prototype Chain Explained with a Library System 📚</a> was originally published in <a href="https://medium.com/devgorilla">devgorilla</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Simplify Your Logs Management with Grafana’s New Explore Logs App]]></title>
            <link>https://medium.com/devgorilla/simplify-your-logs-management-with-grafanas-new-explore-logs-app-787d82af2bc2?source=rss----9ecee7b14553---4</link>
            <guid isPermaLink="false">https://medium.com/p/787d82af2bc2</guid>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[observability]]></category>
            <category><![CDATA[tech]]></category>
            <category><![CDATA[monitoring]]></category>
            <category><![CDATA[grafana]]></category>
            <dc:creator><![CDATA[Grigor Khachatryan]]></dc:creator>
            <pubDate>Wed, 10 Apr 2024 04:24:44 GMT</pubDate>
            <atom:updated>2024-10-06T17:44:14.020Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*2qU-B7tGuGvlhUx8NT79FA.gif" /></figure><p>As a developer and SRE who regularly works with distributed systems, I’ve often found myself struggling with the complexities of log management. The promise of powerful tools like Grafana Loki is enticing, but the learning curve associated with LogQL, Loki’s query language, has been a constant pain point.</p><p>That’s why I’m excited to share my experience with Explore Logs, a new open-source application from Grafana Labs that provides a much more user-friendly interface for browsing and analyzing logs.</p><h3>Leveraging the Power of Grafana Explore</h3><p>Explore Logs leverages the existing Explore functionality within Grafana, which was originally designed for querying metrics data. By extending Explore to work seamlessly with Loki, Grafana Labs has created a log management experience that feels natural and intuitive, even for those of us who aren’t LogQL experts.</p><p>Under the hood, Explore Logs is still utilizing Loki’s powerful log aggregation and query capabilities, but it abstracts away the complexity of LogQL through a series of intuitive UI components. This allows to focus on the task at hand, rather than having to remember the syntax and structure of a specialized query language.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XGNt8SnKhwltsvlqbR-Nfw.png" /></figure><h3>Key Features That Make a Difference</h3><p>The standout features of Explore Logs for me include:</p><p><strong>Labels:</strong> Explore Logs automatically detects and surfaces the labels associated with log data, making it easy to filter and group logs by these key-value pairs. The visual representations of the log volumes for each label are particularly helpful in identifying the most relevant data.</p><p><strong>Detected Fields:</strong> In addition to labels, Explore Logs also integrates Loki’s ability to automatically extract structured fields from log lines. These detected fields are displayed in a clear, grid-like view, and I can use them to further refine log exploration.</p><p><strong>Pattern Matching:</strong> One of the more advanced features that I’ve found incredibly useful is Explore Logs’ pattern matching capabilities. The application can automatically identify common templates or structures across log lines and present them as “patterns.” I can then leverage these patterns to quickly filter out noise or focus on specific types of log entries, saving me valuable time.</p><p><strong>Search:</strong> For those times when I need a more freeform text search, the simple search bar in Explore Logs has proven to be a game-changer. Being able to perform case-sensitive searches across rendered log lines is a feature I didn’t know I needed until I had it.</p><p><strong>Open in Explore:</strong> If I ever find that I do need the full power of LogQL to accomplish a particular task, Explore Logs includes a seamless integration with Grafana’s Explore UI. I can easily transition to the more advanced interface while preserving current context, ensuring a smooth and efficient workflow.</p><h3>Community Feedback and Concerns</h3><p>While the announcement of Explore Logs has generated excitement, the Grafana community has also voiced some concerns and feedback based on their experiences with existing log management solutions.</p><p>Many users expressed a desire for a simpler, more text-file-like experience when viewing logs, rather than having to learn complex query languages like LogQL. As one user commented, “all I have ever wanted to do, when looking at logs, is see the log from one process, from beginning to end, as a text file.” The ability to easily download log files and analyze them locally using familiar tools was seen as an important missing feature.</p><p>Some users also found the setup and configuration of log aggregation tools like Loki to be overly complex and time-consuming, with confusing documentation. There were concerns about the performance and cost of hosted log management solutions, with one user describing Loki as “incredibly slow” compared to the expense.</p><p>Another common theme was the desire for Explore Logs to more closely emulate the simplicity and ease-of-use of traditional text-based log viewing, without sacrificing the advanced aggregation and analysis capabilities of modern log management platforms. As one user put it, “LogQL is nothing like SQL. Try aggregating and quickly you’ll be asking yourself wtf an instant query is and how is that different.”</p><p>Grafana will need to carefully balance the needs of users who prefer a more traditional log viewing experience with the powerful querying and analysis features required for managing complex, distributed systems. Addressing these community concerns will be crucial to ensuring Explore Logs is a successful addition to the Grafana ecosystem.</p><h3>A More Accessible Log Management Experience</h3><p>As someone who has struggled with log management in the past, I’m thrilled to see Grafana Labs taking steps to make the process more user-friendly and accessible. By combining the power of Grafana and Loki, Explore Logs delivers a log management experience that is tailored to the needs of developers, SREs, and other IT professionals like myself.</p><p>I encourage everyone in the Grafana community to try out Explore Logs and provide feedback to help shape its future development. With the public preview now available, there’s never been a better time to explore the possibilities of this exciting new tool.</p><h4>Like to learn more?</h4><p>Find more in-depth guides on <a href="https://grigorkh.dev/">my website</a>.<br>Follow me on <a href="https://twitter.com/grigorkh">Twitter</a> for updates in AI, DevOps, and tech.<br>Connect on <a href="https://www.linkedin.com/in/grigorkh/">LinkedIn</a> to chat or collaborate!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=787d82af2bc2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devgorilla/simplify-your-logs-management-with-grafanas-new-explore-logs-app-787d82af2bc2">Simplify Your Logs Management with Grafana’s New Explore Logs App</a> was originally published in <a href="https://medium.com/devgorilla">devgorilla</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Removing AWS CDK Cross-Stack Reference]]></title>
            <link>https://medium.com/devgorilla/removing-aws-cdk-cross-stack-reference-527a64a19561?source=rss----9ecee7b14553---4</link>
            <guid isPermaLink="false">https://medium.com/p/527a64a19561</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[coding]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <dc:creator><![CDATA[Grigor Khachatryan]]></dc:creator>
            <pubDate>Thu, 04 Apr 2024 01:30:44 GMT</pubDate>
            <atom:updated>2024-10-06T17:44:43.417Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7_IKspRjStGr4ucMyW7p3A.png" /></figure><p>When building applications on AWS, the Cloud Development Kit (CDK) simplifies the provisioning of resources and their dependencies. However, a common challenge developers face is dealing with cross-stack references. Cross-stack references occur when a resource in one stack (e.g., a S3 bucket in Stack1) is referenced by another stack (Stack2). While AWS CDK facilitates these references for ease of use, they can introduce deployment complexities, particularly when you wish to delete a resource that is being referenced across stacks. This guide will explain how to resolve such issues, focusing on a two-step deployment process to safely remove cross-stack references.</p><h3>Understanding the Problem</h3><p>Suppose you have two stacks, Stack1 and Stack2, where Stack1 includes an S3 bucket, and Stack2 references the bucket&#39;s name (bucket.bucketName). If you decide to remove the S3 bucket from Stack1, you might encounter an error similar to:</p><pre>Export Stack1:ExportsOutputFnGetAtt-****** cannot be deleted as it is in use by Stack1</pre><p>This error occurs because CloudFormation, which underlies CDK deployments, protects against the deletion of resources that are being referenced by other stacks. Directly removing the S3 bucket in Stack1 without addressing the reference in Stack2 would break Stack2, leading to potential application failures.</p><h3>Solution: A Two-Step Deployment Process</h3><p>To safely remove a cross-stack referenced resource, you need to follow a two-step deployment process. This approach ensures that the dependency is cleanly severed before the resource is deleted, avoiding deployment errors and application downtime.</p><h4>Deployment 1: Break the Relationship</h4><p>The first deployment focuses on eliminating the dependency between Stack2 and the S3 bucket in Stack1.</p><ol><li>Update Stack2: Modify Stack2 so that it no longer references the S3 bucket&#39;s name. This might involve switching to a different storage resource (like another S3 bucket or a DynamoDB table) or removing the dependent component altogether.</li><li>Update Stack1: In the Stack1 class, call this.exportValue(this.bucket.bucketName);. This step ensures that the CloudFormation export for the bucket&#39;s name remains available even as you work to decouple the stacks. This is crucial for maintaining stability during the transition period.</li><li>Deploy: Deploy both stacks. This deployment will primarily change Stack2, but it&#39;s a good practice to deploy Stack1 as well to enforce the export.</li></ol><h4>Deployment 2: Remove the Resource</h4><p>Once the reference from Stack2 to the S3 bucket in Stack1 is removed, you can safely delete the bucket.</p><ol><li>Remove the Bucket: Delete the bucket resource from Stack1. Also, remove the exportValue() call you added in the first step.</li><li>Deploy: Deploy Stack1. This deployment removes the S3 bucket, completing the process.</li></ol><h3>Example</h3><p>Here’s a brief example to illustrate the steps above:</p><h4>Before Modification</h4><ul><li>Stack1 contains:</li></ul><pre>const bucket = new s3.Bucket(this, &#39;MyBucket&#39;);</pre><ul><li>Stack2 references Stack1&#39;s bucket:</li></ul><pre>const bucketName = s3.Bucket.fromBucketName(this, &#39;ImportedBucket&#39;, &#39;stack1-bucket-name&#39;);</pre><h4>Deployment 1: Break the Relationship</h4><ul><li>Modify Stack2 to remove the reference to Stack1&#39;s bucket.</li><li>In Stack1, add:</li></ul><pre>this.exportValue(this.bucket.bucketName);</pre><h4>Deployment 2: Remove the Resource</h4><ul><li>Remove the S3 bucket from Stack1 and the exportValue() call.</li><li>Deploy Stack1.</li></ul><p>By following these steps, you can smoothly handle cross-stack reference issues in AWS CDK, ensuring that your deployments are error-free and your infrastructure is easily manageable.</p><p>Here is the link to official documentation: <a href="https://github.com/aws/aws-cdk/tree/main/packages/aws-cdk-lib/core#removing-automatic-cross-stack-references">https://github.com/aws/aws-cdk/tree/main/packages/aws-cdk-lib/core#removing-automatic-cross-stack-references</a></p><h4>Like to learn more?</h4><p>Find more in-depth guides on <a href="https://grigorkh.dev/">my website</a>.<br>Follow me on <a href="https://twitter.com/grigorkh">Twitter</a> for updates in AI, DevOps, and tech.<br>Connect on <a href="https://www.linkedin.com/in/grigorkh/">LinkedIn</a> to chat or collaborate!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=527a64a19561" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devgorilla/removing-aws-cdk-cross-stack-reference-527a64a19561">Removing AWS CDK Cross-Stack Reference</a> was originally published in <a href="https://medium.com/devgorilla">devgorilla</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Resolving Cross-Region Stack References in AWS CDK]]></title>
            <link>https://medium.com/devgorilla/resolving-cross-region-stack-references-in-aws-cdk-01890ef9bb4e?source=rss----9ecee7b14553---4</link>
            <guid isPermaLink="false">https://medium.com/p/01890ef9bb4e</guid>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[tech]]></category>
            <category><![CDATA[tutorial]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[cloud]]></category>
            <dc:creator><![CDATA[Grigor Khachatryan]]></dc:creator>
            <pubDate>Wed, 03 Apr 2024 15:26:17 GMT</pubDate>
            <atom:updated>2024-10-06T17:45:02.348Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>ERROR: Cross-stack references are only supported for stacks deployed to the same environment or between nested stacks and their parent stack. Set crossRegionReferences=true to enable cross-region references.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*e5YMnDmcJHAtj1Zqh1plkQ.png" /><figcaption>CDK Logo</figcaption></figure><p>When working with AWS Cloud Development Kit (CDK), it’s common to encounter situations where resources from different stacks, possibly in different regions, need to reference each other. A typical error message you might come across is:</p><pre>Error: Stack ‘Stack1’ cannot reference {Stack2/KmsKey/Resource[Arn]} <br>in stack ‘Stack2’. Cross-stack references are only supported for stacks <br>deployed to the same environment or between nested stacks and their parent stack. <br>Set crossRegionReferences=true to enable cross-region references.</pre><p>This article explains the issue and provides a straightforward solution to enable cross-region references between stacks in AWS CDK.</p><h4>Understanding the Issue</h4><p>By default, AWS CDK supports references (e.g., outputs, SSM parameters) only between stacks that are deployed within the same AWS region or between nested stacks and their parent stack. This limitation exists to prevent complexities and potential inconsistencies arising from managing resources across different geographic locations.</p><p>However, in a multi-region AWS architecture, you might need to reference resources across regions. For example, a KMS key created in one region might need to be accessed by resources in another region.</p><h4>Solution: Enabling Cross-Region References</h4><p>AWS CDK offers a property crossRegionReferences: true within the stack properties to overcome this limitation. By setting this property to true, you instruct CDK to allow resources in one stack to reference resources in another stack, even if they are in different regions.</p><h4>How to Apply the Solution</h4><p>To implement cross-region references, you need to modify the stack properties in your CDK code. Below is an example that demonstrates how to enable cross-region references for two stacks:</p><p><strong>Define Stack 1 (Primary Stack):</strong><br>This stack is deployed in the primary region and might contain resources that need to be accessed by another stack in a different region.</p><pre>const stack1 = new Stack(app, &#39;Stack1&#39;, {<br>  env: { region: &#39;us-east-1&#39; },<br>  // Other stack properties<br>});</pre><p><strong>Define Stack 2 (Secondary Stack)</strong><br>This stack is deployed in a secondary region and needs to access resources from Stack 1.<br>To enable cross-region references, add crossRegionReferences: true in the stack properties:</p><pre>const stack2 = new Stack(app, &#39;Stack2&#39;, {<br>  env: { region: &#39;eu-west-1&#39; },<br>  crossRegionReferences: true, // Enable cross-region references<br>  // Other stack properties<br>});</pre><p>By setting crossRegionReferences: true in the secondary stack, you enable it to reference resources from the primary stack, regardless of the region. This solution simplifies the management of multi-region architectures in AWS CDK.</p><p>For more detailed information and advanced configurations, refer to the AWS CDK documentation and community discussions, such as those on Stack Overflow.</p><p><a href="https://medium.com/devgorilla/removing-aws-cdk-cross-stack-reference-527a64a19561">Removing AWS CDK Cross-Stack Reference</a></p><h4>Like to learn more?</h4><p>Find more in-depth guides on <a href="https://grigorkh.dev/">my website</a>.<br>Follow me on <a href="https://twitter.com/grigorkh">Twitter</a> for updates in AI, DevOps, and tech.<br>Connect on <a href="https://www.linkedin.com/in/grigorkh/">LinkedIn</a> to chat or collaborate!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=01890ef9bb4e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devgorilla/resolving-cross-region-stack-references-in-aws-cdk-01890ef9bb4e">Resolving Cross-Region Stack References in AWS CDK</a> was originally published in <a href="https://medium.com/devgorilla">devgorilla</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring Localhost and 127.0.0.1: What is the difference?]]></title>
            <link>https://medium.com/devgorilla/exploring-localhost-and-127-0-0-1-what-is-the-difference-c109ffce7f29?source=rss----9ecee7b14553---4</link>
            <guid isPermaLink="false">https://medium.com/p/c109ffce7f29</guid>
            <category><![CDATA[ipv6]]></category>
            <category><![CDATA[network]]></category>
            <category><![CDATA[nodejs]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[Grigor Khachatryan]]></dc:creator>
            <pubDate>Tue, 12 Mar 2024 15:59:09 GMT</pubDate>
            <atom:updated>2024-10-06T17:45:33.273Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/742/1*d4NfONhFVv3n46AJsO0FEA.jpeg" /><figcaption>localhost</figcaption></figure><p><strong>TL;DR:</strong> This article explains the difference between “localhost” and “127.0.0.1” and their significance in networking. “localhost” is a domain name for accessing local network services, while “127.0.0.1” and “::1” are loopback IP addresses for IPv4 and IPv6, respectively, used for device communication. The transition to IPv6, offering a larger address space, is crucial for modern networking. This understanding is key for developers and network professionals working in local and private networks.</p><p>Local networking and development environments often hinge on two pivotal concepts: “localhost” and “127.0.0.1”. Despite their frequent use, the nuanced differences between them are not always clear to users. This article aims to shed light on these fundamental elements, providing clarity and enhancing understanding for developers and network enthusiasts alike.</p><p><strong>Localhost: A Friendly Name for Your Local Machine</strong></p><p>At its core, “localhost” serves as a domain name, offering a user-friendly alias for the IP address of your local computer. It’s a standardized nod to the “local” nature of the access it provides, ensuring that developers can work on network applications without affecting external environments. This term allows for an intuitive reference point, simplifying access to a machine’s network services for development and testing purposes.</p><p><strong>127.0.0.1: The Loopback Address Defined</strong></p><p>On the other hand, “127.0.0.1” represents an IP address, specifically designated for loopback communication within a local machine. It’s part of a broader range reserved exclusively for loopback and internal testing functions. This address facilitates the testing and development of software by directing network traffic back to the local machine, ensuring that applications can be run and tested independently of external network interfaces.</p><p><strong>How Domain Names Resolve to IP Addresses</strong></p><p>Understanding how “localhost” translates to “127.0.0.1” involves a peek into the domain name system (DNS) resolution process. Normally, accessing a website by its domain name requires a query to DNS to find the corresponding IP address. However, “localhost” is an exception; its resolution to “127.0.0.1” or “::1” (for IPv6) bypasses the usual DNS lookup process. This translation is hardcoded into the system’s hosts file, eliminating the need for external resolution and ensuring seamless access to the local machine’s network services.</p><p><strong>Localhost vs. 127.0.0.1: Practical Implications and Use Cases</strong></p><p>While both “localhost” and “127.0.0.1” aim to facilitate local development and testing, their slight distinction lies in their handling and interpretation by the operating system and network software. “localhost” can resolve to either an IPv4 or IPv6 address, offering flexibility with the potential for nuanced behavior in different environments. “127.0.0.1”, being explicitly an IPv4 address, offers predictability and straightforwardness in its role as a loopback address.</p><p><strong>The Significance of Ports in Local Development</strong></p><p>The concept of network ports further complicates the interaction between software and network protocols. Ports serve as endpoints for communication, allowing multiple network applications to coexist on a single device. Understanding the default ports (80 for HTTP and 443 for HTTPS) and the need for explicit port specification in certain scenarios is crucial for efficient local development practices.</p><p><strong>Beyond Local: Private IP Addresses and the World of Networking</strong></p><p>The discussion of local addresses leads naturally into the broader topic of private IP addresses, such as those in the “192.168.x.x” range. These addresses facilitate communication within local area networks (LANs), allowing devices to interact seamlessly in a contained environment. The allocation of these addresses adheres to established standards, ensuring that local networks operate efficiently without external interference.</p><p><strong>The Future: IPv6 and Expanding Address Spaces</strong></p><p>As the digital world continues to evolve, the transition from IPv4 to IPv6 addresses becomes increasingly relevant. The expansive address space offered by IPv6 addresses the limitations of IPv4, promising a future where every device can have a unique address. This evolution underscores the ongoing development of network technologies and the importance of adapting to these changes.</p><p><strong>Conclusion</strong></p><p>The distinctions between “localhost” and “127.0.0.1” highlight the intricacies of network communication and development environments. By understanding these concepts and their practical applications, developers and network professionals can optimize their workflows and contribute to the robustness of digital infrastructure. As technology progresses, the principles of local networking remain fundamental, guiding the development of innovative solutions in an interconnected world.</p><h4>Like to learn more?</h4><p>Find more in-depth guides on <a href="https://grigorkh.dev/">my website</a>.<br>Follow me on <a href="https://twitter.com/grigorkh">Twitter</a> for updates in AI, DevOps, and tech.<br>Connect on <a href="https://www.linkedin.com/in/grigorkh/">LinkedIn</a> to chat or collaborate!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c109ffce7f29" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devgorilla/exploring-localhost-and-127-0-0-1-what-is-the-difference-c109ffce7f29">Exploring Localhost and 127.0.0.1: What is the difference?</a> was originally published in <a href="https://medium.com/devgorilla">devgorilla</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[GraphQL vs REST]]></title>
            <link>https://medium.com/devgorilla/graphql-vs-rest-3a01a8f8ce76?source=rss----9ecee7b14553---4</link>
            <guid isPermaLink="false">https://medium.com/p/3a01a8f8ce76</guid>
            <category><![CDATA[graphql]]></category>
            <category><![CDATA[rest]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[nodejs]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Grigor Khachatryan]]></dc:creator>
            <pubDate>Mon, 30 Jan 2023 03:11:27 GMT</pubDate>
            <atom:updated>2023-01-30T03:11:27.254Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wOVxC97fTI-H2Ug0WF4mjg.png" /></figure><p>GraphQL and REST are two popular API architectures for building web applications. Both have been widely used for building modern applications and have their own advantages and disadvantages. In this article, we will compare and contrast GraphQL and REST, explore the benefits of each, and provide code examples to illustrate the differences.</p><p><strong>What is GraphQL?</strong> GraphQL is a query language for APIs that was developed by Facebook in 2012. It provides a more efficient and flexible alternative to traditional REST APIs by allowing clients to request exactly the data they need, reducing the risk of over-fetching or under-fetching data. GraphQL also includes a type system that defines the data that can be fetched and the operations that can be performed, making it easier for clients and servers to understand the API.</p><p><strong>What is REST?</strong> REST, or Representational State Transfer, is an architectural style for building web services that was first described by Roy Fielding in 2000. REST APIs use HTTP methods (such as GET, POST, PUT, and DELETE) to perform operations on resources. REST APIs typically return all the data associated with a resource, which can result in over-fetching data.</p><p><strong>Code Examples</strong></p><p>Let’s look at a simple code example to see the difference between a GraphQL API and a REST API.</p><p>Here is an example of a simple GraphQL query to retrieve information about a user:</p><pre>query {<br>  user(id: 1) {<br>    name<br>    email<br>  }<br>}</pre><p>And here is an equivalent REST API call to retrieve the same information:</p><pre>GET /users/1</pre><p>As you can see, the GraphQL query allows you to specify exactly what data you want to retrieve, while the REST API call returns all the data associated with the user resource.</p><p><strong>Benefits of GraphQL</strong></p><ol><li>Flexibility: GraphQL allows clients to request exactly the data they need, reducing the risk of over-fetching or under-fetching data. This makes it easier to optimize performance and reduce network overhead.</li><li>Efficient: GraphQL allows clients to fetch multiple resources in a single request, reducing the number of round trips to the server. This can greatly improve performance, especially for mobile devices with slow or unreliable network connections.</li><li>Type System: GraphQL includes a type system that defines the data that can be fetched and the operations that can be performed, making it easier for clients and servers to understand the API.</li><li>Versioning: GraphQL has a built-in versioning system through its schema, which allows for new fields and types to be added without breaking existing clients.</li></ol><p><strong>Benefits of REST</strong></p><ol><li>Simple: REST is a simple and well-established architecture that provides a straightforward way to build APIs.</li><li>Backwards Compatible: REST APIs are typically designed to be backwards compatible, which means that new versions of the API can be introduced without breaking existing clients.</li><li>Widely Adopted: REST is a widely adopted architecture and has a large community of developers and tools that support it.</li><li>Caching: REST APIs can be cached, reducing network overhead and improving performance.</li></ol><p><strong>N+1 Problem</strong></p><p>The n+1 problem is a common issue in REST API design, where multiple API calls are required to retrieve related data. For example, to retrieve information about a user and their posts, you might need to make two separate API calls: one to retrieve the user information and another to retrieve the list of posts.</p><p>In GraphQL, related data can be retrieved in a single API call, avoiding the n+1 problem and improving performance. For example, the following GraphQL query retrieves information about a user and their posts:</p><pre>query {<br>  user(id: 1) {<br>    name<br>    email<br>    posts {<br>      title<br>      body<br>    }<br>  }<br>}</pre><p><strong>Overfetching and Underfetching</strong></p><p>Overfetching occurs when an API returns more data than a client needs, which can result in increased network overhead and slower performance. Underfetching occurs when an API does not return enough data for a client to complete its task, which can result in additional API calls and reduced performance.</p><p>In REST, overfetching and underfetching can be a common issue as the API often returns a fixed set of data for each resource. In GraphQL, the client has control over what data is retrieved, reducing the risk of overfetching or underfetching.</p><p><strong>Backward Compatibility</strong></p><p>Backward compatibility is an important aspect of API design, as it allows for new versions of the API to be introduced without breaking existing clients. REST APIs are typically designed to be backwards compatible, while GraphQL has a built-in versioning system through its schema. This allows for new fields and types to be added without breaking existing clients, making it easier to evolve the API over time.</p><p><strong>Benefits of Schema and Type System</strong></p><p>The schema and type system in GraphQL provide a clear and concise definition of the data that can be fetched and the operations that can be performed. This makes it easier for clients and servers to understand the API and reduces the risk of misunderstandings or errors. In addition, the type system helps to ensure that the data returned from the API is consistent and accurate.</p><p>In conclusion, GraphQL and REST are two popular API architectures that each have their own advantages and disadvantages. GraphQL provides a more efficient and flexible alternative to REST, while REST is a simple and well-established architecture that is widely adopted. Ultimately, the choice between GraphQL and REST will depend on the specific needs of the project and the preferences of the development team.</p><h3>Like to learn?</h3><p>Follow me on <a href="https://twitter.com/grigorkh">twitter</a> where I post all about the latest and greatest AI, DevOps, VR/AR, Technology, and Science! Connect with me on <a href="https://www.linkedin.com/in/grigorkh/">LinkedIn</a> too!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3a01a8f8ce76" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devgorilla/graphql-vs-rest-3a01a8f8ce76">GraphQL vs REST</a> was originally published in <a href="https://medium.com/devgorilla">devgorilla</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Running a GraphQL Endpoint with Serverless — Using Python]]></title>
            <link>https://medium.com/devgorilla/running-a-graphql-endpoint-with-serverless-using-python-77e79f901cc0?source=rss----9ecee7b14553---4</link>
            <guid isPermaLink="false">https://medium.com/p/77e79f901cc0</guid>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[graphql]]></category>
            <category><![CDATA[serverless]]></category>
            <category><![CDATA[lambda]]></category>
            <category><![CDATA[python]]></category>
            <dc:creator><![CDATA[Grigor Khachatryan]]></dc:creator>
            <pubDate>Mon, 30 Jan 2023 02:55:54 GMT</pubDate>
            <atom:updated>2023-01-30T02:55:54.770Z</atom:updated>
            <content:encoded><![CDATA[<h3>Running a GraphQL Endpoint with Serverless — Using Python</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kXEJ9XOl9Dng9KxrQDGvSA.png" /></figure><p>In this article, we’ll demonstrate how to set up a GraphQL endpoint with Serverless on AWS Lambda, using Python. We’ll also show how to deploy the endpoint using Continuous Integration and Deployment (CI/CD) pipelines with GitHub Actions.</p><p><strong>Setting up the Apollo Server</strong></p><p>To set up the Apollo Server, we’ll use the graphene-python library, which provides a simple way to create GraphQL APIs in Python. First, create a new directory for the project and navigate into it:</p><pre>mkdir graphql-serverless<br>cd graphql-serverless</pre><p>Next, create a new virtual environment and activate it:</p><pre>python -m venv venv<br>source venv/bin/activate</pre><p>Install the required dependencies by running the following command:</p><pre>pip install graphene Flask</pre><p>This installs the graphene and Flask libraries.</p><p>Next, create a new file named handler.py in the graphql-serverless directory with the following code:</p><pre>import graphene<br>import flask<br>from flask import Flask<br>from flask_graphql import GraphQLView<br><br>class Query(graphene.ObjectType):<br>    hello = graphene.String(description=&#39;A simple greeting&#39;)<br><br>    def resolve_hello(self, info):<br>        return &#39;Hello, Serverless!&#39;<br><br>app = Flask(__name__)<br>app.add_url_rule(<br>    &#39;/graphql&#39;,<br>    view_func=GraphQLView.as_view(<br>        &#39;graphql&#39;,<br>        schema=graphene.Schema(query=Query),<br>        graphiql=True<br>    )<br>)<br><br>def graphql_handler(event, context):<br>    return flask.Response(app(flask.request.environ, context.respond))</pre><p>This sets up the Apollo Server with a single query named hello that returns the string &#39;Hello, Serverless!&#39;.</p><p><strong>Setting up the Serverless Function</strong></p><p>Next, we’ll set up the Serverless function to host the Apollo Server. First, install the serverless framework by running the following command:</p><pre>npm install -g serverless</pre><p>Create a new Serverless service by running the following command:</p><pre>serverless create --template aws-python3</pre><p>This creates a new Serverless service with the required configuration files.</p><p>Replace the contents of serverless.yml with the following code:</p><pre>service: graphql-serverless<br><br>framework:<br>  name: flask<br><br>provider:<br>  name: aws<br>  runtime: python3.8<br><br>functions:<br>  graphql:<br>    handler: handler.graphql_handler<br>    events:<br>      - http:<br>          path: graphql<br>          method: post<br><br>plugins:<br>  - serverless-flask-binary</pre><p>This configures a single Serverless function named graphql that will be triggered by a HTTP POST request to the /graphql endpoint. It also includes the serverless-flask-binary plugin, which is required for Flask to work on AWS Lambda.</p><p><strong>Deploying the Serverless</strong></p><p>To deploy the Serverless endpoint, simply run the following command:</p><pre>serverless deploy</pre><p>This will compile the Serverless function and deploy it to AWS Lambda. Once the deployment is complete, the command will output the endpoint URL, which you can use to access the GraphQL API.</p><p><strong>Setting up the CI/CD Pipeline</strong></p><p>Finally, we’ll set up a CI/CD pipeline to automate the deployment process using GitHub Actions. First, create a new repository on GitHub for the project and push the code to it.</p><p>Next, navigate to the Actions tab in the repository and create a new workflow. Replace the contents of main.yml with the following code:</p><pre>name: Deploy<br><br>on:<br>  push:<br>    branches:<br>      - main<br><br>env:<br>  AWS_REGION: us-west-2<br><br>jobs:<br>  deploy:<br>    runs-on: ubuntu-latest<br><br>    steps:<br>    - name: Checkout code<br>      uses: actions/checkout@v2<br><br>    - name: Set up Python environment<br>      uses: actions/setup-python@v2<br>      with:<br>        python-version: 3.8<br><br>    - name: Install dependencies<br>      run: |<br>        python -m venv venv<br>        source venv/bin/activate<br>        pip install -r requirements.txt<br><br>    - name: Deploy to AWS Lambda<br>      uses: aws-actions/configure-aws-credentials@v1<br>      with:<br>        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}<br>        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}<br>        aws-region: ${{ env.AWS_REGION }}<br><br>    - name: Deploy with Serverless<br>      run: |<br>        npx serverless deploy --aws-profile default</pre><p>This workflow is triggered whenever a push is made to the main branch. It sets up the Python environment, installs the required dependencies, and deploys the Serverless endpoint using the serverless framework.</p><p>You’ll also need to add your AWS credentials as secrets in the repository. To do this, navigate to the repository’s Settings tab, select Secrets, and add two new secrets named AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY with your AWS credentials.</p><p>With the CI/CD pipeline set up, every time you make changes to the code and push them to the main branch, the pipeline will automatically deploy the changes to AWS Lambda.</p><p><strong>Conclusion</strong></p><p>In this article, we demonstrated how to run a GraphQL endpoint with Serverless on AWS Lambda using Python. We covered the basics of setting up an Apollo Server, deploying it as a Serverless function, and automating the deployment process using a CI/CD pipeline with GitHub Actions.</p><p>The combination of GraphQL and Serverless provides a powerful platform for building and deploying modern web applications, allowing you to take advantage of the scalability and cost-effectiveness of AWS Lambda while keeping the development process simple and streamlined.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=77e79f901cc0" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devgorilla/running-a-graphql-endpoint-with-serverless-using-python-77e79f901cc0">Running a GraphQL Endpoint with Serverless — Using Python</a> was originally published in <a href="https://medium.com/devgorilla">devgorilla</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Running a GraphQL endpoint with Serverless]]></title>
            <link>https://medium.com/devgorilla/running-a-graphql-endpoint-with-serverless-3fbe98e21394?source=rss----9ecee7b14553---4</link>
            <guid isPermaLink="false">https://medium.com/p/3fbe98e21394</guid>
            <category><![CDATA[nodejs]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[serverless]]></category>
            <category><![CDATA[graphql]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[Grigor Khachatryan]]></dc:creator>
            <pubDate>Mon, 30 Jan 2023 02:40:19 GMT</pubDate>
            <atom:updated>2023-01-30T02:53:13.060Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bRWMbpDBU82gxW-nMNU4Zw.png" /></figure><h4>GraphQL?</h4><p>In case you are not familiar with it, <a href="http://graphql.org/">GraphQL</a> is a data query language created by Facebook. GraphQL allows the client to select ad-hoc data. This differentiates it from REST API’s that expose pre-set data structures.</p><p><a href="https://medium.com/devgorilla/what-is-graphql-f0902a959e4">What is GraphQL?</a></p><h4>Serverless?</h4><p>Serverless pattern encourages development focus on well-defined units of business logic, without premature optimization decisions related to how this logic is deployed or scaled.</p><p><a href="https://medium.com/devgorilla/what-is-serverless-12daeadb6ff5">What is Serverless?</a></p><h4>Code</h4><p><strong>Setting up the Serverless Framework</strong></p><p>Before we start, make sure you have Node.js and npm installed on your machine. You can check this by running the following commands:</p><pre>node -v<br>npm -v</pre><p>Next, install the Serverless Framework globally:</p><pre>npm install -g serverless</pre><p>Now that we have the Serverless Framework installed, let’s create a new Serverless project:</p><pre>serverless create --template aws-nodejs --path graphql-serverless</pre><p>This will create a new Serverless project using the AWS Node.js template in a directory named graphql-serverless.</p><p><strong>Installing the Required Libraries</strong></p><p>To run a GraphQL endpoint, we need to install the following libraries:</p><pre>npm install apollo-server-lambda graphql</pre><p>apollo-server-lambda is a library that makes it easy to run an Apollo GraphQL server on AWS Lambda. graphql is the library that provides the GraphQL implementation.</p><p><strong>Writing the GraphQL Schema</strong></p><p>The next step is to write the GraphQL schema. This schema defines the types and the operations that can be performed on these types.</p><p>Create a schema.js file in the graphql-serverless directory with the following code:</p><pre>const { gql } = require(&quot;apollo-server-lambda&quot;);<br><br>const typeDefs = gql`<br>  type Query {<br>    hello: String<br>  }<br>`;<br><br>module.exports = typeDefs;</pre><p>This is a simple schema that defines a single operation hello that returns a string.</p><p><strong>Writing the GraphQL Resolvers</strong></p><p>Next, we need to write the resolvers. Resolvers are the functions that implement the operations defined in the schema.</p><p>Create a resolvers.js file in the graphql-serverless directory with the following code:</p><pre>const resolvers = {<br>  Query: {<br>    hello: (_, __, context) =&gt; {<br>      return &quot;Hello, Serverless!&quot;;<br>    },<br>  },<br>};<br><br>module.exports = resolvers;</pre><p>This resolver implements the hello operation from the schema and returns the string &quot;Hello, Serverless!&quot;.</p><p><strong>Setting up the Apollo Server</strong></p><p>Finally, we need to set up the Apollo Server.</p><p>Create a handler.js file in the graphql-serverless directory with the following code:</p><pre>const { ApolloServer } = require(&quot;apollo-server-lambda&quot;);<br>const typeDefs = require(&quot;./schema&quot;);<br>const resolvers = require(&quot;./resolvers&quot;);<br><br>const server = new ApolloServer({<br>  typeDefs,<br>  resolvers,<br>});<br><br>exports.graphqlHandler = server.createHandler();</pre><p>This sets up the Apollo Server using the typeDefs and resolvers from the previous sections.</p><p><strong>Configuring the Serverless Function</strong></p><p>Now that we have the GraphQL endpoint set up, we need to configure the Serverless function to run it.</p><p>Update the serverless.yml file in the graphql-serverless directory with the following code:</p><pre>service: graphql-serverless<br>provider:<br>  name: aws<br>  runtime: nodejs12.x<br><br>functions:<br>  graphql:<br>    handler: handler.graphqlHandler<br>    events:<br>      - http:<br>          path: graphql<br>          method: post<br><br>plugins:<br> - serverless-apollo-middleware</pre><p>This configures a single Serverless function named `graphql` that will be triggered by a HTTP POST request to the `/graphql` endpoint. It also includes the `serverless-apollo-middleware` plugin, which is required for the Apollo Server to work on AWS Lambda.</p><p><strong>Deploying the Serverless Function</strong></p><p>The final step is to deploy the Serverless function to AWS. Run the following command in the `graphql-serverless` directory:</p><pre>serverless deploy</pre><p>This will deploy the function to AWS and return the URL of the GraphQL endpoint.</p><p><strong>Testing the GraphQL Endpoint</strong></p><p>You can use a tool like <a href="https://insomnia.rest/">Insomnia</a> or <a href="https://www.postman.com/">Postman</a> to test the GraphQL endpoint.</p><p>Create a new POST request to the URL of the GraphQL endpoint with the following query in the request body:</p><pre>query {<br>  hello<br>}</pre><p>Send the request and you should receive the following response:</p><pre>{<br>  &quot;data&quot;: {<br>    &quot;hello&quot;: &quot;Hello, Serverless!&quot;<br>  }<br>}</pre><p><strong>Continuous Integration and Deployment (CI/CD) using GitHub Actions</strong></p><p>To automate the deployment process, we can set up a CI/CD pipeline using GitHub Actions. GitHub Actions allows you to automate your workflow by creating custom actions that run whenever a specific event occurs in your GitHub repository.</p><p>Create a new file named .github/workflows/deploy.yml in your GitHub repository with the following code:</p><pre>name: Deploy<br><br>on:<br>  push:<br>    branches:<br>      - main<br><br>env:<br>  AWS_REGION: us-east-1<br>  AWS_PROFILE: default<br><br>jobs:<br>  deploy:<br>    runs-on: ubuntu-latest<br><br>    steps:<br>      - name: Checkout code<br>        uses: actions/checkout@v2<br><br>      - name: Configure AWS credentials<br>        uses: aws-actions/configure-aws-credentials@v1<br>        with:<br>          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}<br>          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}<br>          aws-region: ${{ env.AWS_REGION }}<br><br>      - name: Deploy to AWS<br>        uses: anothrNick/serverless-action@v1<br>        with:<br>          command: deploy</pre><p>This action is triggered whenever a push is made to the main branch of the GitHub repository. It uses the anothrNick/serverless-action action to deploy the Serverless function to AWS.</p><p>Make sure to replace AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in the code above with the actual values from your AWS account. You can store these values as secrets in your GitHub repository.</p><p>Conclusion</p><p>In this article, we showed how to run a GraphQL endpoint with Serverless on AWS Lambda. We covered the basics of setting up an Apollo Server and deploying it as a Serverless function. We also showed how to automate the deployment process using GitHub Actions, allowing for a seamless CI/CD pipeline.</p><p>By using Serverless, you can take advantage of the scalability and cost-effectiveness of AWS Lambda while keeping the development process simple and streamlined. The combination of GraphQL and Serverless provides a powerful platform for building and deploying modern web applications.</p><p>With the code and steps outlined in this article, you should be able to get started with running a GraphQL endpoint with Serverless and continue building upon this foundation for your own projects.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3fbe98e21394" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devgorilla/running-a-graphql-endpoint-with-serverless-3fbe98e21394">Running a GraphQL endpoint with Serverless</a> was originally published in <a href="https://medium.com/devgorilla">devgorilla</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[GraphQL Basics]]></title>
            <link>https://medium.com/devgorilla/graphql-basics-66a38e4d0d48?source=rss----9ecee7b14553---4</link>
            <guid isPermaLink="false">https://medium.com/p/66a38e4d0d48</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[nodejs]]></category>
            <category><![CDATA[graphql]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[technology]]></category>
            <dc:creator><![CDATA[Grigor Khachatryan]]></dc:creator>
            <pubDate>Sun, 29 Jan 2023 05:11:35 GMT</pubDate>
            <atom:updated>2023-01-29T05:11:35.743Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wfMUtlW5d55WKbQQ2ou0Qw.png" /></figure><p>GraphQL is a query language for your API that was developed and open-sourced by Facebook in 2015. More about the “What is GraphQL”:</p><p><a href="https://medium.com/devgorilla/what-is-graphql-f0902a959e4">What is GraphQL?</a></p><p>The core building block of a GraphQL schema is the “type system”. A type system defines the types of data that can be queried and the fields that can be requested for each type. The GraphQL type system includes built-in scalar types (e.g. Int, String, Boolean), as well as custom types that can be defined by the developer.</p><p>The type system consists of three main types: scalars, objects, and enums.</p><p>Scalars are the most basic type in GraphQL, and include built-in types such as Int, Float, String, Boolean, and ID. These types represent the most basic pieces of data that can be queried or manipulated in a GraphQL API.</p><p>Object types are used to represent complex data structures, and are composed of fields that are either scalars or other object types. For example, a Book object type might have fields for the title, author, and reviews.</p><p>Enums are used to represent a fixed set of possible values, such as a BookStatus enumeration with values of &quot;AVAILABLE&quot;, &quot;CHECKED_OUT&quot;, and &quot;ON_HOLD&quot;.</p><p>In addition to these types, GraphQL also has several type modifiers that can be used to further describe the data:</p><ul><li>Non-Null: ensures that a field cannot be null.</li><li>List: allows for a field to contain a list of items, such as an array of books.</li><li>Input: used to define input types for mutations.</li></ul><p>GraphQL also allows for the creation of custom scalar types to represent specific types of data that are not covered by the built-in scalars.</p><p>The GraphQL type system is also used to define relationships between different types of data. This can be achieved through the use of interfaces, unions, and fields.</p><p>Interfaces define a common set of fields that multiple types must implement. For example, a Node interface might have an id field that all types that implement it must also have.</p><p>Unions allow for multiple types to be returned from a single field. For example, a search field that returns either a Book or an Author type.</p><p>Finally, fields in GraphQL can also be used to describe relationships between types. For example, the author field in the Book type would be used to describe the relationship between a Book and its Author.</p><h3>Schemas</h3><p>A GraphQL schema is a blueprint for your API. It defines the types of data that can be queried, the fields that can be requested for each type, and the relationships between types. A GraphQL schema is defined using the GraphQL schema language, which is a simple language for describing the structure of a GraphQL API.</p><p>Here is an example of a simple GraphQL schema that defines a `Book` type with `title` and `author` fields:</p><pre>type Book {<br>  title: String<br>  author: String<br>}</pre><p>This schema defines a single type, “Book”, with two fields, “title” and “author”, both of which are of type “String”.</p><h3>Built-in Scalar types</h3><p>GraphQL has several built-in scalar types: Int, Float, String, Boolean, and ID. These types are used to define the fields of your types and can be used in the arguments of your queries and mutations.</p><p>Here is an example of a query that requests the “title” and “author” fields of a “Book” type:</p><pre>query {<br>  book(id: 1) {<br>    title<br>    author<br>  }<br>}</pre><p>In this example, the “book” field is of type “Book” and accepts an “id” argument, which is of type “ID”. The fields “title” and “author” are both of type “String”.</p><h3>Type definitions</h3><p>In GraphQL, you can define your own types using the “type” keyword. A type definition defines a new type and its fields.</p><p>Here is an example of a type definition for a “Person” type with “name” and “age” fields:</p><pre>type Person {<br>  name: String<br>  age: Int<br>}</pre><h3>Type modifiers</h3><p>GraphQL allows you to modify the type of a field with the following modifiers:</p><ul><li>! denotes a non-nullable field. This means that the field must always return a value.</li><li>[] denotes a list of the type. This means that the field will return an array of the specified type.</li></ul><p>Here is an example of a type definition that includes type modifiers:</p><pre>type Query {<br>  books: [Book!]!<br>  person(id: ID!): Person!<br>}</pre><p>In this example, the “books” field is a non-nullable list of non-nullable “Book” types, and the “person” field is a non-nullable “Person” type that takes a non-nullable “id” argument of type “ID”.</p><h3>Input arguments</h3><p>In GraphQL, you can pass arguments to your fields to specify additional information about the data you are requesting. These are called input arguments. Input arguments are defined using the “input” keyword.</p><p>Here is an example of a query that uses an input argument to filter a list of books by their author:</p><pre>query {<br>  books(filter: { author: &quot;George Orwell&quot; }) {<br>    title<br>  }<br>}</pre><p>In this example, the “books” field accepts an input argument called “filter” of type “BookFilterInput”. The “BookFilterInput” type is defined as:</p><pre>input BookFilterInput {<br>  author: String<br>}</pre><h3>Input types</h3><p>Input types are similar to regular types, but they are used specifically for input arguments. They are defined using the “input” keyword.</p><p>Here is an example of an input type for a “CreateBook” mutation:</p><pre>input CreateBookInput {<br>  title: String!<br>  author: String!<br>}</pre><p>In this example, the “CreateBookInput” type has two fields, “title” and “author”, both of which are non-nullable strings.</p><h3>Custom Scalars</h3><p>In addition to the built-in scalar types, GraphQL allows you to define your own custom scalar types. Custom scalar types can be used to represent more specific types of data, such as a date or a URL.</p><p>Here is an example of a custom scalar type called “Date”:</p><pre>scalar Date</pre><p>To use this custom scalar type, you need to specify a custom scalar resolver. Scalar resolvers are functions that define how to parse and serialize custom scalars.</p><h3>Interfaces</h3><p>Interfaces in GraphQL allow you to define a set of fields that multiple types can implement. This allows you to specify that certain types have a certain set of fields without having to repeat the fields on each type.</p><p>Here is an example of an interface called “Node” that defines a “id” field:</p><pre>interface Node {<br>  id: ID!<br>}</pre><p>You can then have multiple types implement this interface:</p><pre>type Book implements Node {<br>  id: ID!<br>  title: String<br>  author: String<br>}<br><br>type Person implements Node {<br>  id: ID!<br>  name: String<br>  age: Int<br>}</pre><p>In this example, both “Book” and “Person” types implement the “Node” interface and have a non-nullable “id” field of type “ID”.</p><h3>Unions</h3><p>Unions in GraphQL allow you to represent multiple types as a single type. This allows you to return multiple types in the same field.</p><p>Here is an example of a union type called “SearchResult” that can represent either a “Book” or a “Person”:</p><pre>union SearchResult = Book | Person</pre><p>You can then use this union type in a query:</p><pre>query {<br>  search(query: &quot;George Orwell&quot;) {<br>    ... on Book {<br>      title<br>    }<br>    ... on Person {<br>      name<br>    }<br>  }<br>}</pre><p>In this example, the “search” field returns a “SearchResult” union type that can be either a “Book” or a “Person” type. To access the fields of the specific type, the query uses the “…” syntax to specify the type.</p><h3>Enums</h3><p>Enums in GraphQL allow you to define a set of predefined values for a field. This allows you to specify that a field can only have certain values.</p><p>Here is an example of an enum type called “BookGenre”:</p><pre>enum BookGenre {<br>  SCI_FI<br>  FANTASY<br>  ROMANCE<br>  MYSTERY<br>}</pre><p>You can then use this enum type in a type definition:</p><pre>type Book {<br>  title: String<br>  author: String<br>  genre: BookGenre<br>}</pre><p>In this example, the “genre” field of the “Book” type can only have the predefined values of “SCI_FI”, “FANTASY”, “ROMANCE”, and “MYSTERY”.</p><h3>Queries</h3><p>Queries are used to retrieve data from a GraphQL server. They are similar to GET requests in REST APIs. A query consists of a set of fields that you want to retrieve, along with any arguments and nested fields.</p><p>Here is an example of a query that retrieves the title and author of a book:</p><pre>query {<br>  book(id: 1) {<br>    title<br>    author<br>  }<br>}</pre><p>This query asks for the “book” field with an “id” argument of 1, and then requests the “title” and “author” fields of the returned “book” object.</p><p>The power of GraphQL lies in its ability to retrieve multiple resources in a single query. For example, you can retrieve information about a book and its author in a single request:</p><pre>query {<br>  book(id: 1) {<br>    title<br>    author {<br>      name<br>      bio<br>    }<br>  }<br>}</pre><p>This query retrieves the title of the book, along with the name and bio of the book’s author. This is a powerful feature that can reduce the number of requests needed to retrieve the data needed for a specific use case.</p><h3>Mutations</h3><p>Mutations are used to create, update, or delete data on a GraphQL server. They are similar to POST, PUT, and DELETE requests in REST APIs. A mutation consists of a set of fields that you want to modify, along with any arguments and nested fields.</p><p>Here is an example of a mutation that creates a new book:</p><pre>mutation {<br>  createBook(input: {<br>    title: &quot;The Hobbit&quot;<br>    author: &quot;J.R.R. Tolkien&quot;<br>    genre: FANTASY<br>  }) {<br>    title<br>    author<br>    genre<br>  }<br>}</pre><p>This mutation calls the “createBook” field with an “input” argument that contains the fields for the new book. The mutation then returns the title, author, and genre of the newly created book.</p><h3>Subscriptions</h3><p>Subscriptions are used to receive real-time updates from a GraphQL server. They are similar to WebSocket connections in REST APIs. A subscription consists of a set of fields that you want to subscribe to, along with any arguments and nested fields.</p><p>Here is an example of a subscription that listens for updates on a book:</p><pre>subscription {<br>  bookUpdates(id: 1) {<br>    title<br>    author<br>    genre<br>  }<br>}</pre><p>This subscription calls the “bookUpdates” field with an “id” argument of 1, and then requests the title, author, and genre fields of the returned book object. The server will then push any updates on the book with the specified id to the client.</p><h3>Short Comparison with REST API</h3><p>REST APIs are based on the HTTP protocol, and use different endpoints for different resources. A client must send multiple requests to different endpoints to retrieve all the data needed for a specific use case. This can lead to over-fetching or under-fetching of data and can make the client code more complex.</p><p>On the other hand, GraphQL allows you to retrieve multiple resources in a single request, with the ability to specify exactly what data is needed. This can reduce the number of requests needed to retrieve the data needed for a specific use case, leading to more efficient and user-friendly data-driven applications.</p><p>In REST API, for example, if you want to retrieve the details of a book, its author and its reviews, you would have to make multiple requests to different endpoints like:</p><pre>GET /books/1<br>GET /authors/2<br>GET /reviews?bookId=1</pre><p>In contrast, in GraphQL, you can retrieve all the same information in a single request:</p><pre>query {<br>  book(id: 1) {<br>    title<br>    author {<br>      name<br>      bio<br>    }<br>    reviews {<br>      text<br>      rating<br>    }<br>  }<br>}</pre><p>This not only reduces the number of requests needed but also makes the client code simpler as all the data needed is available in a single response.</p><p>Another advantage of GraphQL over REST is that it allows for more flexibility in the shape of the returned data. In REST, the shape of the returned data is determined by the endpoint being called, whereas in GraphQL, the shape of the returned data is determined by the client’s request. This allows the client to retrieve only the data it needs, and not have to filter through unnecessary data.</p><p>In summary, GraphQL provides a more efficient and flexible way of retrieving data, allowing for more user-friendly data-driven applications. It allows the client to specify exactly what data is needed, reducing the number of requests needed and making the client code simpler.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=66a38e4d0d48" width="1" height="1" alt=""><hr><p><a href="https://medium.com/devgorilla/graphql-basics-66a38e4d0d48">GraphQL Basics</a> was originally published in <a href="https://medium.com/devgorilla">devgorilla</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>