<?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>Forem: Ivo Meißner</title>
    <description>The latest articles on Forem by Ivo Meißner (@ivomeissner).</description>
    <link>https://forem.com/ivomeissner</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%2F374969%2F7320412e-79bd-4ce2-8fed-3317fd7d1329.jpg</url>
      <title>Forem: Ivo Meißner</title>
      <link>https://forem.com/ivomeissner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ivomeissner"/>
    <language>en</language>
    <item>
      <title>Announcing Slicknode Open-Source: GraphQL Framework + Headless CMS</title>
      <dc:creator>Ivo Meißner</dc:creator>
      <pubDate>Wed, 13 Oct 2021 15:59:51 +0000</pubDate>
      <link>https://forem.com/slicknode/announcing-slicknode-open-source-graphql-framework-headless-cms-3if7</link>
      <guid>https://forem.com/slicknode/announcing-slicknode-open-source-graphql-framework-headless-cms-3if7</guid>
      <description>&lt;p&gt;I have big news to share: I am releasing Slicknode, the GraphQL application framework + headless CMS, as &lt;strong&gt;Open-Source-Software&lt;/strong&gt;! &lt;/p&gt;

&lt;p&gt;This gives developers and digital agencies a free, more efficient, and open way for building custom digital solutions that usually require the budget for custom software development or enterprise licenses.&lt;/p&gt;

&lt;p&gt;Watch how Slicknode makes web developers a lot more productive &lt;a href="https://www.youtube.com/embed/W_hEhH8Z7gs"&gt;in this 3 min demo&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Slicknode?
&lt;/h2&gt;

&lt;p&gt;The web has evolved significantly in the last 15 years. We now have AI-powered content delivered to users across the globe, real-time communication with video, VR, and countless SaaS providers that offer functionality for every use-case imaginable. Sadly, a lot of these capabilities are not as accessible to developers as they could be. The development of such solutions happens in silos, in separate companies doing redundant work. Using and combining multiple of those functionalities requires significant integration effort and deep knowledge of the integrated system. Extending a 3rd party SaaS offering is very hard or impossible. You almost always have to create a custom backend to create something innovative. Unfortunate for countless businesses, people, and organizations that could benefit tremendously from such solutions, this is out of budget in a lot of cases. &lt;/p&gt;

&lt;p&gt;Projects either settle for sub-optimal compromises or spend way more than they would like on a custom backend. You could circumvent the development process by using one of the page builders that come with a tempting price tag but have severe limitations and hard vendor lock-in. &lt;/p&gt;

&lt;p&gt;Those barriers inhibit innovation. We see the result of that all over the internet: Boring websites that all look the same and do the same thing. People then spend the majority of their time on the websites of tech giants instead of on the websites of their local stores, communities, and people they see in real life. &lt;/p&gt;

&lt;p&gt;Let's fix this with open-source software! I want to help developers create an internet where the best ideas win, not the biggest budgets. I want to enable every developer to create innovative solutions that can compete at the highest levels. But to accomplish this, we need a new approach for how we build digital solutions. &lt;/p&gt;

&lt;h2&gt;
  
  
  Headless Functionality
&lt;/h2&gt;

&lt;p&gt;We need to free the functionality from the silos of corporations and make them easily accessible to anyone, ready to use, extend and combine. We need to decouple the functionality from the presentation layer. It gives us the flexibility we need to use any frontend framework and create solutions for any device. Headless CMSes have done this successfully in recent years, but they are mostly still limited to content. If we want to combine the functionality of multiple services, we still have to do the integration manually in the frontend, which adds complexity (error + loading states, handling authentication, etc.). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slicknode eliminates this integration effort&lt;/strong&gt; by applying the headless concept to any functionality you could imagine. The workflow becomes extremely simple with a modular architecture: You compose your custom backend with existing modules, 3rd party APIs, and your internal services into a unified data graph. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Need certain functionality in your project?&lt;/strong&gt; &lt;br&gt;
Just install the module - Done! &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if there is no module available for what I need?&lt;/strong&gt; &lt;br&gt;
Simply create a new one in minutes using the flexible building blocks that Slicknode provides and share it with the web developer community. &lt;/p&gt;

&lt;p&gt;This dramatically reduces the amount of knowledge you need to build complex solutions. For example, you don't have to be a Shopify developer anymore to add eCommerce functionality to your website. You can simply install an existing module or embed an API with minimal effort.&lt;/p&gt;

&lt;p&gt;Slicknode brings the power of all the APIs in the world right into your user interfaces. You can mix and match functionality from multiple service providers, extend their functionality with ease, and build solutions on top of the GraphQL API. You can enjoy the freedom to use any tools, programming languages, and frameworks you know and love without giving up control.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Vision
&lt;/h2&gt;

&lt;p&gt;The purpose of Slicknode is to provide a platform that empowers developers to build better solutions in less time. In 10 years, I want to look at the web and think: "There is no way I could have built those solutions with the tools from 10 years ago!" &lt;/p&gt;

&lt;p&gt;I want Slicknode to be the platform where developers can share ideas and solutions to existing and future problems. A collaborative and welcome community where we can help each other build the next generation of the internet. &lt;/p&gt;

&lt;p&gt;I invite all web developers to become a part of this. Share Slicknode far and wide, invite your friends and co-workers and start building great digital solutions. Let's make this the best, most friendly, and welcoming Open-Source community that empowers developers worldwide!&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Do I Start?
&lt;/h2&gt;

&lt;p&gt;The best place to start is &lt;a href="https://slicknode.com/docs/quickstart/"&gt;the quickstart guide&lt;/a&gt; and the &lt;a href="https://github.com/slicknode/slicknode"&gt;Github repository&lt;/a&gt;. Create your first project in minutes and start hacking. I will also be publishing more and more examples in the &lt;a href="https://www.youtube.com/channel/UCKoG7vZ5--WoWn1rbtnC_ZQ"&gt;Slicknode YouTube channel&lt;/a&gt; and on &lt;a href="https://twitter.com/intent/user?screen_name=slicknode"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm looking forward to working with all of you and making the world a better place through collaboration and open-source software!&lt;/p&gt;

&lt;p&gt;Best, &lt;br&gt;
Ivo Meißner &lt;br&gt;
Creator of Slicknode&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>webdev</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
    <item>
      <title>To GraphQL or not to GraphQL? Pros and Cons</title>
      <dc:creator>Ivo Meißner</dc:creator>
      <pubDate>Mon, 13 Sep 2021 15:45:20 +0000</pubDate>
      <link>https://forem.com/ivomeissner/to-graphql-or-not-to-graphql-pros-and-cons-11bl</link>
      <guid>https://forem.com/ivomeissner/to-graphql-or-not-to-graphql-pros-and-cons-11bl</guid>
      <description>&lt;p&gt;So you want to know if GraphQL is a great fit for your project? Using GraphQL can be a consequential decision, for better or worse. If you have never used GraphQL in a complex project, how are you supposed to know if you are going to regret it later or celebrate yourself for making the right call? &lt;/p&gt;

&lt;p&gt;It can be hard to see through all the hype articles like &lt;em&gt;"GraphQL is the successor of REST"&lt;/em&gt; or &lt;em&gt;"GraphQL is overkill for most projects"&lt;/em&gt; and understanding what GraphQL would mean for your particular project. I want to save you some trouble with this post and put everything I have learned about GraphQL in the past years into one blog post that can help you make a more informed decision. &lt;/p&gt;

&lt;p&gt;Can you trust my opinion? Maybe, always make your own judgment! For reference, here are a few things I have worked on in the GraphQL ecosystem: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; I have built thousands of GraphQL APIs in the process of creating &lt;a href="https://slicknode.com"&gt;Slicknode&lt;/a&gt;, a framework and headless CMS to rapidly create GraphQL APIs&lt;/li&gt;
&lt;li&gt;I have written &lt;a href="https://github.com/slicknode/graphql-query-complexity"&gt;graphql-query-complexity&lt;/a&gt; the most popular open-source library to secure GraphQL servers written in NodeJS against DoS attacks. It is also used by some of the big open-source frameworks like TypeGraphQL and NestJS&lt;/li&gt;
&lt;li&gt;I have migrated a 12-year-old codebase to GraphQL &lt;/li&gt;
&lt;li&gt;I have ported a &lt;a href="https://github.com/ivome/graphql-relay-php"&gt;library to create Relay compatible GraphQL APIs&lt;/a&gt; from JavaScript to PHP&lt;/li&gt;
&lt;li&gt;I have removed GraphQL from a service where it turned out to be not a great fit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So keep in mind that I am a huge GraphQL fan, but I'll try my best to talk about the tradeoffs as well. &lt;/p&gt;

&lt;h2&gt;
  
  
  Is GraphQL Just A Hype?
&lt;/h2&gt;

&lt;p&gt;At this point, it is probably safe to say that GraphQL is here to stay. In the years following its open-source release in 2015, it has gained an incredible amount of traction. It has been adopted by a large number of fortune 500 companies, and those applications don't tend to disappear overnight. &lt;/p&gt;

&lt;p&gt;GraphQL has also sparked the interest of investors: Businesses that build products around GraphQL have raised hundreds of millions of dollars in venture capital. &lt;/p&gt;

&lt;p&gt;There are now GraphQL clients and servers in all major programming languages available and the GraphQL library for Javascript alone has currently 5.5 million weekly downloads. The tooling around GraphQL has been a joy to work with and gives you a lot of options to get creative and solve real-world problems. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is GraphQL?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://graphql.org/"&gt;The official website&lt;/a&gt; describes GraphQL as "A query language for your API". The process is explained as "Describe your data ➜ Ask for what you want ➜ Get predictable results". &lt;/p&gt;

&lt;p&gt;I like to think of it as &lt;strong&gt;the SQL for APIs&lt;/strong&gt;. When you work with SQL, you can write your SQL query in a declarative way, describe what data you want to load or change, and then let the SQL server figure out the best way to perform the actual operation. You don't care what is happening under the hood, like which blocks are read from disk, caches, or networks, this is all nicely hidden from you. When there is a new release of your SQL server available, you can safely update the database and profit from all the performance improvements, etc. without having to update a single SQL query in your codebase. If there were new features added, you can use those features in new parts of your application, but you don't have to update existing parts of your application, as the old queries will still work the same. &lt;/p&gt;

&lt;p&gt;This is very similar to how GraphQL works, only for APIs: You write a GraphQL query in a declarative way, send it to your server, and the server figures out the best way to load that data. It is then returned in the exact format that you specified in your query. Now, &lt;strong&gt;if you need different data, you just change the query, NOT the server&lt;/strong&gt;! This gives API consumers unprecedented powers. You can send any valid query to your GraphQL server, and it will on-demand return the correct response. It's like having unlimited REST API endpoints without changing a single line of code in your backend. &lt;/p&gt;

&lt;p&gt;A good analogy: &lt;strong&gt;When REST is like ordering a la carte in a restaurant, GraphQL is the all-you-can-eat buffet&lt;/strong&gt;. You can mix and match any dish that is served at the buffet on a single plate and take as much or as little as you want. With REST, the dish always has the same portion size, you first have to ask the waiter if they could combine multiple dishes, they have to check back with the kitchen and might come back telling you that they don't do that, thinking you are an annoying customer for not respecting their menu. &lt;/p&gt;

&lt;p&gt;Also, when you want to add new capabilities to your GraphQL server, you just add more fields and types to your schema. All the existing GraphQL queries in your client applications keep working without requiring any changes. This enables you to evolve your APIs and client applications independently, but we will look at that in more detail later. &lt;/p&gt;

&lt;p&gt;If you are not that familiar with GraphQL yet, I recommend checking out the &lt;a href="https://graphql.org/learn/"&gt;introduction on the official GraphQL website&lt;/a&gt;, so you can see some GraphQL queries and schema definitions in action. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why GraphQL?
&lt;/h2&gt;

&lt;p&gt;So why was GraphQL created in the first place and what problems was it supposed to solve? &lt;/p&gt;

&lt;p&gt;GraphQL was initially created at Facebook to solve some major challenges with the API communication between the servers and their plethora of client applications for all kinds of device sizes, operating systems, web apps, etc. As you can imagine, evolving APIs at that scale is extremely hard, especially if you are using a REST-style architecture. &lt;/p&gt;

&lt;p&gt;There is &lt;a href="https://www.youtube.com/watch?v=783ccP__No8"&gt;a documentary about GraphQL&lt;/a&gt; where the GraphQL creators and other early adoptors talk about why they created and adopted GraphQL.&lt;/p&gt;

&lt;p&gt;Let's look at the most important reasons in some more detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overfetching
&lt;/h2&gt;

&lt;p&gt;A problem with REST APIs is that you have a predefined response format that is pretty inflexible. One URL always returns the requested resource in its entirety. Sure, there are ways to mitigate that problem like passing the fields to include in the response via parameters, etc., but this is not standardized, therefore needs documentation and it has to be implemented in the backend, which adds unnecessary complexity. &lt;/p&gt;

&lt;p&gt;This can become a problem over time, especially as you evolve your API and add new features or deprecate obsolete data. &lt;/p&gt;

&lt;p&gt;For example: Let's say you want to add a new field to your user object with the current online status to the REST endpoint of the user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET https://example.com/users/2
{
  "username": "ivo"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You could simply add the field to the response, which then becomes:&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;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ivo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isOnline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;This is great and works. However, the problem with this approach is that now the online status is sent to every single client application even if they don't need it. Do this a few times and you end up with bloated, mostly useless responses that you send to every client, consuming their bandwidth and making your application slower over time. &lt;/p&gt;

&lt;h2&gt;
  
  
  Underfetching
&lt;/h2&gt;

&lt;p&gt;Another challenge you might be familiar with when building rich user interfaces is something called underfetching: You don't get all the data you need to display in a single API request and have to call the API again to load related data. This adds additional server roundtrips, increases the latency, and can lead to poor user experience. &lt;/p&gt;

&lt;p&gt;Let's look at a very simple example: Say you want to create the backend for a blog post detail page where you want to display the following data:&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;"post"&lt;/span&gt;&lt;span class="p"&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;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GraphQL is awesome!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GraphQL solves so many problems..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&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;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ivo"&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;span class="nl"&gt;"comments"&lt;/span&gt;&lt;span class="p"&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"100% !!!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&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;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&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;span class="p"&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;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Couldn't agree more"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&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;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Jane"&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;span class="p"&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;span class="p"&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;When you want to implement that with REST, you have to ask a few questions:&lt;br&gt;
Do you include the author in the response data of the post? &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why not put it in a dedicated &lt;code&gt;/user/23&lt;/code&gt; API resource to avoid redundancy and only return a reference in the post response?&lt;/li&gt;
&lt;li&gt;What about comments? Do you return them as well? &lt;/li&gt;
&lt;li&gt;What about the author of the comments?&lt;/li&gt;
&lt;li&gt;Where does it end?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To keep it &lt;a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY&lt;/a&gt; you might implement the response like this:&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;"post"&lt;/span&gt;&lt;span class="p"&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;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GraphQL is awesome!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GraphQL solves so many problems..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/user/1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"comments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/comments?post=345"&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;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;When the client gets this response, it does not contain all the data that we need. We have to make additional requests to fetch the author and the comments, which adds additional latency. We could create a custom API endpoint where we return the data exactly in the shape that we need. But that might add redundancy in our backend and make the API less flexible (a mobile application might not want to load the comments initially).&lt;/p&gt;

&lt;p&gt;GraphQL eliminates this problem by giving frontend developers the ability to request exactly the data that they need on-demand and let the GraphQL server do the heavy lifting of loading (or not loading) references automatically. &lt;/p&gt;

&lt;h2&gt;
  
  
  Feature Deprecation
&lt;/h2&gt;

&lt;p&gt;As your project evolves and requirements change, you might want to deprecate a feature and remove it from your API to not have to maintain obsolete or redundant services. This can be a major challenge with a REST architecture, especially in more complex projects. Do you release a new version for every feature that is removed? How do you make sure a removed feature is not still in use by some client application? When can you shut down the old API versions? &lt;/p&gt;

&lt;p&gt;In a lot of cases, it is easier and cheaper to just keep the old feature in place than to go through the significant engineering effort of implementing a solid migration strategy. The problem is, you are forcing all this useless data through the bandwidth-limited connections of your users, with no easy way out, or you have to maintain multiple versions of your API. &lt;/p&gt;

&lt;p&gt;GraphQL has a built-in way to solve this problem. You can just mark a field as deprecated and add information on how to migrate client applications. This information is available to all client applications in a standardized way, you can run a script in your CI pipeline that automatically checks if deprecated fields are used and migrate your client applications accordingly. As soon as all deprecation notices are fixed in your client applications, you can safely remove the field from your GraphQL API. &lt;/p&gt;

&lt;p&gt;The benefits are obvious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No need to create, run and maintain multiple versions of your API. Just one GraphQL API that evolves with your project over time.&lt;/li&gt;
&lt;li&gt;An automated and self-documenting way to manage feature deprecations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Decoupling Frontend &amp;amp; Backend Development
&lt;/h2&gt;

&lt;p&gt;By introducing GraphQL in a project, you are eliminating an enormous amount of friction by completely decoupling frontend and backend development. Any number of frontend applications can be developed and changed completely independent of the backend. There is no need to create or update a specific REST endpoint for a particular view, the power shifts to the frontend developers as they can just request data on demand. &lt;/p&gt;

&lt;p&gt;To get back to the restaurant analogy: The chefs can just place a new dish on the buffet and users can come mix and match it with anything else they pick up when they fill their plate. There is no coordination needed. Compared to the REST style a-la-carte ordering, changing the menu to combine multiple dishes requires coordination with the chef, and possibly other restaurant staff. &lt;/p&gt;

&lt;p&gt;As an example of what this can mean in practice: In one project I was working on, a team created an entire mobile application without changing anything in the GraphQL backend. &lt;/p&gt;

&lt;h2&gt;
  
  
  The GraphQL Killer-Feature
&lt;/h2&gt;

&lt;p&gt;There is one feature of GraphQL that gets way too little attention and is oftentimes not even mentioned in articles examing the pros and cons of GraphQL. In my opinion, this is &lt;strong&gt;the killer feature that makes GraphQL invaluable&lt;/strong&gt;, especially in larger projects. All the GraphQL advantages that we have looked at so far can somehow be worked around, with some ugly compromises to be fair, but nothing was a show stopper. However, I am not aware of any widely adopted technology that even comes close to how GraphQL solves this particular problem: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Co-Location Of Data Dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's look at an example to illustrate the problem. We have a React component somewhere in a codebase where we display the user name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;UserName&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we want to display the online status next to the username. What sounds like a simple task can quickly escalate into a nightmare. It raises all kinds of questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is that online status even available in the user object? &lt;/li&gt;
&lt;li&gt;How do you know or find out? Is there documentation available?&lt;/li&gt;
&lt;li&gt;If the data is coming from an API, how do you make sure it is included in every single API endpoint that returns the user object for the component?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You need a vast amount of knowledge that is not readily available where you want to implement the feature, and also not necessarily related to the task at hand. For a developer that is new to the codebase, this can be particularly problematic. You might have to identify and change lots of API endpoints and include the online status in all the API responses that include the user object. &lt;/p&gt;

&lt;p&gt;This becomes a complete non-issue with GraphQL APIs because you can co-locate your data dependencies with your frontend components using GraphQL fragments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserNameFragments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
    fragment UserName on User {
      username
      #Just add the online status to the fragment here:
      isOnline
    }
  `&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;UserName&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isOnline&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;online&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;offline&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/span&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You define the data dependencies right in your UI components with GraphQL fragments. The parent components can then include those fragments in their GraphQL queries that load the data, and you have a guarantee that the &lt;code&gt;UserName&lt;/code&gt; component receives the online status, no matter where in your application it is located. &lt;/p&gt;

&lt;p&gt;This makes it incredibly easy to extend your application no matter how complex it is. You don't have to have any knowledge about the rest of the codebase and can confidently implement a feature without leaving the component. With the right tooling, you even get autocomplete functionality, type validation, and documentation in your IDE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance &amp;amp; Security
&lt;/h2&gt;

&lt;p&gt;With great power comes great attack surface. &lt;/p&gt;

&lt;p&gt;By exposing a GraphQL API to the internet, you are giving clients an enormous amount of power that can have big implications with regards to security and performance. Clients have access to all your data and functionality at once, on-demand. This significantly increases your attack surface and can easily be exploited if not considered from the start.&lt;/p&gt;

&lt;p&gt;Let's look at a few problematic queries...&lt;/p&gt;

&lt;p&gt;Load a ridiculous amount of data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LotsOfPosts&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;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100000000&lt;/span&gt;&lt;span class="p"&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;span class="n"&gt;title&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;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;Load deeply nested data that requires millions of DB queries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DeeplyNestedData&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;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&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;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;friends&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;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;friends&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;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;friends&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;span class="n"&gt;name&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;span class="p"&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;span class="p"&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;Launching a brute force attack in a single request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;mutation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BruteForcePassword&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;span class="n"&gt;attempt1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"victim@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;attempt2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"victim@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="c"&gt;# ...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;attempt100000&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"victim@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxxxx"&lt;/span&gt;&lt;span class="p"&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;The problem is that those queries are not prevented by commonly available rate limiters. You can send a single request to a GraphQL server that completely overwhelms the servers. To prevent such queries to GraphQL APIs, I wrote &lt;a href="https://github.com/slicknode/graphql-query-complexity"&gt;graphql-query-complexity&lt;/a&gt;, an extensible open-source library that detects such queries and rejects pathological queries before consuming too many resources on the server. You can assign each field a complexity value, and queries that exceed a threshold will be rejected. In &lt;a href="https://slicknode.com"&gt;Slicknode&lt;/a&gt; this protection is added automatically based on the number of nodes that are being returned. &lt;/p&gt;

&lt;p&gt;Another common approach is to register an allow-list of queries that are permitted and reject all other queries to the API. This might be more granular and secure than dynamic rules, but it limits the flexibility of your GraphQL API and you have to keep your query registry up to date with all your client applications, which requires additional setup and maintenance. &lt;/p&gt;

&lt;p&gt;Optimizing the requests to your internal data stores can be another challenge. The responsibility to optimize the data loading process lies 100% with the GraphQL API and can't easily be offloaded to a CDN or reverse proxy. With a REST API, you have very good control over how many and what database queries are executed, thanks to the limited scope of the REST endpoint. With GraphQL a client can request any number of objects that might have to be loaded from different DB tables. &lt;a href="https://slicknode.com"&gt;Slicknode&lt;/a&gt; automatically combines multiple requested objects into a single database query by analyzing the GraphQL query and generating the SQL query dynamically, but your average ORM is probably not equipped to do that out of the box. &lt;/p&gt;

&lt;p&gt;This is also related to the N+1 problem, where nested queries make the number of database requests explode. If you want to learn more about this problem, I recommend &lt;a href="https://www.youtube.com/watch?v=OQTnXNCDywA"&gt;this video&lt;/a&gt; and checking out &lt;a href="https://github.com/graphql/dataloader"&gt;dataloader&lt;/a&gt;, a library released by Facebook to help with batching queries and solving this problem. &lt;/p&gt;

&lt;h2&gt;
  
  
  Caching vs GraphQL
&lt;/h2&gt;

&lt;p&gt;Caching is always a hard challenge and that can be especially true for GraphQL servers. A lot of the tools we usually rely on don't work well with GraphQL out of the box. &lt;/p&gt;

&lt;p&gt;Take CDNs for example. The most common way to deploy GraphQL APIs is via an HTTP server. You then send your GraphQL requests via a POST request to the API and retrieve your response. The problem is that POST requests are not cached by default in the most common CDNs. You could potentially also send your requests via a GET request, but you will quickly hit the request size limit as GraphQL queries can get huge. If you are using a query allow list, you can send a query ID or hash to the server instead of the full query to get around this limit. &lt;/p&gt;

&lt;p&gt;Cache invalidation can also be more challenging with GraphQL APIs. All the queries are usually served via the same URL, so invalidating resources by URL is off the table. Furthermore, one data object can be included in any number of cached responses. One strategy to solve this is to attach cache tags to responses and then later invalidate responses based on those tags instead of URLs. This is the approach that is used in the &lt;a href="https://slicknode.com"&gt;Slicknode&lt;/a&gt; Cloud to cache GraphQL responses around the globe. &lt;/p&gt;

&lt;p&gt;A great way to add caching to your GraphQL APIs is to add a layer behind the GraphQL API itself and implement it in front of your data sources. Combine this with the dataloader mentioned in "Performance &amp;amp; Security" and you can fully customize the cache behavior. &lt;/p&gt;

&lt;h2&gt;
  
  
  Single Point of Failure
&lt;/h2&gt;

&lt;p&gt;One thing to keep in mind is that your GraphQL API becomes your API Gateway replacement as the way to access all your functionality, data, and services. If the GraphQL API goes down, your entire application is offline. This is not that different from a REST architecture, but good to know that the GraphQL API will be a critical part of your infrastructure and treat it accordingly. &lt;/p&gt;

&lt;h2&gt;
  
  
  Best (and worst) Use-Cases for GraphQL
&lt;/h2&gt;

&lt;p&gt;If you have a hammer, every problem looks like a nail. It is really easy to fall in love with all the benefits that GraphQL provides. It makes your life as a frontend developer so much easier compared to previous technologies. But some types of applications are more suitable for GraphQL than others. I have burnt my fingers too and have removed GraphQL from some parts of an application, while for other applications I would highly recommend it.&lt;/p&gt;

&lt;p&gt;In my experience, the best use-case for GraphQL is the purpose it was originally built for: Providing the data and functionality for rich user interfaces. A central place that contains all your data and functionality in one unified GraphQL API, easily accessible for any number of teams, always up to date, and self-documenting. It dramatically reduces the complexity of your frontend code. Where you previously had to implement lots of API calls with all the complexity that asynchronous functionality entails (loading states, error handling, etc.), you can now simply define your data dependencies and let GraphQL take care of the rest. You can validate all your API calls at build time and implement solutions with end-to-end type safety. Even though GraphQL is awesome to use as a single developer, the bigger your application and team become, the more you'll enjoy working with GraphQL. &lt;/p&gt;

&lt;p&gt;So when should you consider alternatives to GraphQL? I would consider alternatives for applications where you want to physically separate different services. GraphQL is great for combining a lot of functionality in one place. This might be a problem if you want to isolate certain services for example at the network or hardware level and only make them accessible to a subset of services. You might be better off looking at other architectures. &lt;/p&gt;

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

&lt;p&gt;GraphQL is an awesome addition to a developer's toolbelt, especially for powering user interfaces. It is a joy to work with and I am excited to see the GraphQL ecosystem gaining more and more traction. To make it easier for developers to build GraphQL APIs I created &lt;a href="https://slicknode.com"&gt;Slicknode&lt;/a&gt;. It automates all the hard parts and gets you up and running in minutes. Come join the awesome GraphQL community! I also have some pretty big news to share about &lt;a href="https://slicknode.com"&gt;Slicknode&lt;/a&gt; soon, so make sure to &lt;a href="https://twitter.com/intent/user?screen_name=ivomeissner"&gt;follow me on Twitter&lt;/a&gt; and subscribe to the newsletter so you'll be the first to know. &lt;/p&gt;

</description>
      <category>graphql</category>
      <category>architecture</category>
      <category>security</category>
    </item>
    <item>
      <title>How To Build A Media Library With Just 25 Lines of Code - Using GraphQL and Slicknode</title>
      <dc:creator>Ivo Meißner</dc:creator>
      <pubDate>Thu, 15 Apr 2021 12:17:42 +0000</pubDate>
      <link>https://forem.com/slicknode/how-to-build-a-media-library-with-just-25-lines-of-code-using-graphql-and-slicknode-5gn6</link>
      <guid>https://forem.com/slicknode/how-to-build-a-media-library-with-just-25-lines-of-code-using-graphql-and-slicknode-5gn6</guid>
      <description>&lt;p&gt;Our friends from &lt;a href="https://axolist.com/"&gt;AXOLIST&lt;/a&gt; recently asked us to build a custom media library for their Amazon Content Tool. They wanted to give their users the possibility to upload, manage and update images for their products that they sell on the Amazon marketplace. (Those product images that you see when you shop on Amazon.com)&lt;/p&gt;

&lt;p&gt;Background: AXOLIST is a SaaS tool for agencies that help brands sell products on the Amazon marketplace, optimize the content of their product listings for users, search rankings, and ensure compliance.&lt;/p&gt;

&lt;p&gt;Now let's see how we added this feature to their Slicknode backend with just a few lines of code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;To enable this type of functionality, we had to create a solution with the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Since AXOLIST is a SaaS tool, every customer needs to have their own independent media library that &lt;strong&gt;can only be accessed by users that are members of that customer account&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Images need to be organized in a &lt;strong&gt;hierarchical folder structure&lt;/strong&gt; to make it easy to manage large product portfolios.&lt;/li&gt;
&lt;li&gt;Images will be displayed in &lt;strong&gt;multiple resolutions&lt;/strong&gt;: Thumbnails for the listview, and a high-resolution image for a zoomed-in view.&lt;/li&gt;
&lt;li&gt;Users should get a visual warning when they upload an image that has a resolution that is too low for the Amazon marketplace. &lt;/li&gt;
&lt;li&gt;Folders can be &lt;strong&gt;dragged and dropped&lt;/strong&gt; into other folders to quickly (re-)organize the media items in an account.&lt;/li&gt;
&lt;li&gt;Images can be &lt;strong&gt;searched&lt;/strong&gt; within each folder.&lt;/li&gt;
&lt;li&gt;Folders should have &lt;strong&gt;unique names&lt;/strong&gt; within a subfolder. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soft-delete functionality&lt;/strong&gt; should allow admins to restore a folder that might have been accidentally deleted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Creating this from scratch requires a significant amount of time for building API routes, data models, migrations, image processing, authorization, etc. With Slicknode, this becomes a task that is done in 5 minutes. Let's take a look!&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;First, we create the media module using the Slicknode CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;slicknode module create media
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we add the data model to the schema.graphql file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Media_Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&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;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Account_Account&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Media_Directory&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Media_Directory&lt;/span&gt;&lt;span class="p"&gt;!]!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;Media_Directory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Media_Directory&lt;/span&gt;&lt;span class="err"&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;span class="err"&gt;"""&lt;/span&gt;&lt;span class="n"&gt;Date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;was&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deleted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;soft&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="err"&gt;"""&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;deletedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DateTime&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;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Media_Asset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Node&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&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;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Media_Directory&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Account_Account&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&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;With this data model, Slicknode automatically generates the GraphQL API, database tables, and business logic that we need to build our media library. We have the tenant separation to give each account its own media library. The built-in image module of Slicknode takes care of image upload, storage, and thumbnail generation. With the composite unique index, we can ensure that the folder names are unique within each folder and with the relations directive, we create the hierarchic folder structure that scales easily. &lt;/p&gt;

&lt;p&gt;To secure the assets and make them only accessible for users of the account, we add a permission query for the directory type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DirectoryPermission1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&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;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AUTHENTICATED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;operations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CREATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UPDATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;READ&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&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;span class="n"&gt;deletedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;isNull&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&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;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&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;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&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;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&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;span class="n"&gt;eq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$user_id&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;span class="p"&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;span class="p"&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;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;We use the permission query to enable multi-tenancy and only allow users of an account to see their own directories. We can also use the same permission query to hide directories that have the &lt;code&gt;deletedAt&lt;/code&gt; value set. The filters will automatically be applied by the Slicknode query engine across the entire GraphQL API. &lt;/p&gt;

&lt;p&gt;That's it. This is all we have to do to build the backend for our media library. &lt;a href="https://slicknode.com/docs/quickstart/"&gt;Give it a try&lt;/a&gt; for your next project. &lt;/p&gt;

</description>
      <category>graphql</category>
    </item>
    <item>
      <title>Slicknode Content HUB: Headless CMS powered by GraphQL</title>
      <dc:creator>Ivo Meißner</dc:creator>
      <pubDate>Mon, 02 Nov 2020 18:04:06 +0000</pubDate>
      <link>https://forem.com/slicknode/slicknode-content-hub-headless-cms-powered-by-graphql-19g2</link>
      <guid>https://forem.com/slicknode/slicknode-content-hub-headless-cms-powered-by-graphql-19g2</guid>
      <description>&lt;p&gt;We have some exciting news to share: After months of hard work, we just launched the new Slicknode that will allow you to build digital experiences with Slicknode better and faster than ever before. The improvements are so profound that they enable an entirely new class of digital solutions that you can build with Slicknode and pretty much change what kind of product Slicknode is. &lt;/p&gt;

&lt;p&gt;Here are just a few of the highlights: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Global GraphQL CDN:&lt;/strong&gt; Content via the Slicknode API will now be delivered via a global content delivery network that allows you to publish your content to millions of users while at the same time dramatically reducing the latency and response times for API requests around the globe. (In some cases &amp;lt; 20 ms)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internationalization:&lt;/strong&gt; Slicknode now supports localization of your content as a first-class feature that is fully integrated into the query engine, API, and content editing interface. Create digital solutions for global audiences and enter new markets faster. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content Preview:&lt;/strong&gt; There are now two stages for content in your projects, one for editing and previewing drafts and one for the published version. That way, you can make changes and updates to your content without affecting the published version, like agile software development but for content. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content Workflows:&lt;/strong&gt; You can set up custom publishing workflows for your content and collaboratively create content with your team. For example, you can start with a draft version and then move it through your workflow: review &amp;gt; translation &amp;gt; legal &amp;gt; published. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Union Types:&lt;/strong&gt; Slicknode added support for union types. With union types, you can now create extremely flexible content models. For example, you can create a modular page builder that can be used by content editors to create dynamic landing pages without involving IT. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Array Fields:&lt;/strong&gt; We added support for sortable array fields. While you previously had to create one-to-many and many-to-many fields via a relation, you can now create sortable array fields in which the objects can be sorted via drag and drop in the content editor. This enables a lot of new use-cases, especially in combination with union types. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New Console:&lt;/strong&gt; The complete layout and design of the console were updated to improve the editing experience and to support all the new content editing features. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Slicknode now has all the building blocks that you need to create a central hub for all your content. And all those features are 100% backward compatible and are immediately available for all existing projects. &lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://slicknode.com/docs/"&gt;the documentation&lt;/a&gt; for more details about the features and how to add them to your existing projects. &lt;/p&gt;

&lt;h2&gt;
  
  
  New Website
&lt;/h2&gt;

&lt;p&gt;To do the major product release justice, we relaunched a new version of &lt;a href="https://slicknode.com/"&gt;our own website&lt;/a&gt;, which is now powered by Slicknode itself. This allows us to publish more content faster and keep the website up to date. We now have a modular content builder for building pages and creating an interactive experience to learn about our product.&lt;/p&gt;

&lt;p&gt;If you want to build a similar website for your own company, check out our...&lt;/p&gt;

&lt;h2&gt;
  
  
  Next.js Starter Kit
&lt;/h2&gt;

&lt;p&gt;We created a Next.js starter kit that you can use to quickly set up a website with Slicknode, Next.js, static site generation, etc. in a few seconds. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/slicknode/starter-nextjs-blog"&gt;Check it out on Github&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Updated Pricing
&lt;/h2&gt;

&lt;p&gt;With the release of the new Slicknode Content HUB, we also updated and simplified our pricing model. We now have a "Free forever" plan for development, small websites, or experiments, and you can save money by paying annually. Check out &lt;a href="https://slicknode.com/pricing/"&gt;the pricing page&lt;/a&gt; for details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Direction
&lt;/h2&gt;

&lt;p&gt;This launch marks a significant milestone in the history of Slicknode: &lt;a href="https://slicknode.com/blog/graphql-cms-application-framework/"&gt;When we first started building Slicknode&lt;/a&gt;, we set out to create a solution that automates the repetitive work that is still required to create high-quality custom software solutions. We created a general-purpose backend that is up and running in seconds without developers having to worry about setting up infrastructure, databases, running migrations, etc. &lt;/p&gt;

&lt;p&gt;Having such a general-purpose solution allowed us to gather valuable feedback from customers for a wide variety of use-cases and see for which solutions they considered Slicknode. We want to thank all of our customers and users for their valuable ideas and feedback, which helps us make the best decisions about how to improve our platform. &lt;/p&gt;

&lt;p&gt;The one thing that stands out is that most customers are using Slicknode for content-centric applications. It just made sense to focus most of our efforts on adding essential functionality for managing and distributing content, like adding a global CDN, localization support, and custom content workflows. Since Slicknode was initially built for highly complex applications that go way beyond what you would usually use a CMS for, you now have a platform that has a lot more functionality out of the box than a lot of other content management systems on the market today.&lt;/p&gt;

&lt;p&gt;We will continue to improve Slicknode for content management use-cases and would love to hear your feedback and ideas (&lt;a href="https://slicknode.com/slack"&gt;Join us in our Slack channel&lt;/a&gt;).&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>react</category>
      <category>headless</category>
      <category>serverless</category>
    </item>
    <item>
      <title>How To Merge + Extend GraphQL APIs: Slicknode Remote Modules</title>
      <dc:creator>Ivo Meißner</dc:creator>
      <pubDate>Fri, 19 Jun 2020 13:52:17 +0000</pubDate>
      <link>https://forem.com/slicknode/how-to-merge-extend-graphql-apis-slicknode-remote-modules-4d2m</link>
      <guid>https://forem.com/slicknode/how-to-merge-extend-graphql-apis-slicknode-remote-modules-4d2m</guid>
      <description>&lt;p&gt;Slicknode already offers a significant amount of functionality out of the box to build rich applications, however, the reality is that in most organizations and projects there are plenty of IT systems that you want to integrate or extend, both from inside and outside of the organization. &lt;/p&gt;

&lt;p&gt;By using those systems, you don't have to reinvent the wheel, however, you still have to spend a significant amount of time with API integrations. For example: Managing credentials for multiple environments, finding documentation, wrapping / transforming the APIs to work within the context of your application, error handling, etc. &lt;/p&gt;

&lt;p&gt;We wanted to eliminate this integration effort, which is why we created &lt;a href="https://slicknode.com/docs/extensions/remote-modules/"&gt;Slicknode Remote Modules&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Remote Modules
&lt;/h2&gt;

&lt;p&gt;Remote Modules allow you to merge entire GraphQL APIs into your Slicknode GraphQL APIs with just &lt;a href="https://slicknode.com/docs/extensions/remote-modules/"&gt;a few lines of configuration&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The use-cases for this are endless, here are just a few ideas: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the Slicknode CMS as the content layer to your core product GraphQL API. &lt;/li&gt;
&lt;li&gt;Add your Shopify or Magento eCommerce store to the Slicknode GraphQL API and create landing pages or entire communities for better customer engagement and conversions. &lt;/li&gt;
&lt;li&gt;Add customer account information to internal user profile pages.&lt;/li&gt;
&lt;li&gt;Integrate payment providers.&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All you have to do is create a module that points to the remote GraphQL API. Slicknode automatically merges the APIs into one unified data graph, taking care of naming conflicts, data fetching logic, and schema generation.&lt;/p&gt;

&lt;p&gt;With the merged GraphQL APIs, you can then load data from multiple data sources with a single GraphQL query. This dramatically simplifies the frontend implementation as you only need to configure one GraphQL client. You also have all the data right where you need it: In your UI components. &lt;/p&gt;

&lt;h2&gt;
  
  
  Extending GraphQL APIs
&lt;/h2&gt;

&lt;p&gt;With the merged schemas in a Slicknode project, it is then possible to create relationships between objects of completely independent systems. This makes creating custom digital experiences on top of existing systems incredibly easy, fast, and fun.&lt;/p&gt;

&lt;p&gt;For example: Let's assume you have an eCommerce system where you manage all your products, inventory, pricing, etc. &lt;/p&gt;

&lt;p&gt;You then want to create a microsite where you publish rich user testimonials with videos, images, reviews, etc. while at the same time showing the current pricing and product information from the eCommerce system. &lt;/p&gt;

&lt;p&gt;With Slicknode, you can simply extend the types of your eCommerce store using the same &lt;a href="https://slicknode.com/docs/data-modeling/introduction/"&gt;data modeling tools&lt;/a&gt; that you use for internal types: One-to-one, many-to-many, one-to-many &lt;a href="https://slicknode.com/docs/data-modeling/relations/"&gt;relations&lt;/a&gt;, etc. Slicknode automatically provisions the database tables, handles &lt;a href="https://slicknode.com/docs/auth/authorization/"&gt;authorization&lt;/a&gt;, and creates the corresponding resolvers with the data fetching logic. &lt;/p&gt;

&lt;p&gt;Here is what a schema for an extension of the Product type could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;extend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Product&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;span class="n"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Review&lt;/span&gt;&lt;span class="p"&gt;!]!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;relation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Review&lt;/span&gt;&lt;span class="err"&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;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Review&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;implements&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Node&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;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Float&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MARKDOWN&lt;/span&gt;&lt;span class="p"&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;With the &lt;a href="https://slicknode.com/docs/data-modeling/relations/"&gt;relation directive&lt;/a&gt;, we can freely connect types of independent systems. Slicknode automatically creates a Relay compatible relation with &lt;a href="https://slicknode.com/docs/graphql-api/query-api/#pagination"&gt;pagination&lt;/a&gt;, &lt;a href="https://slicknode.com/docs/graphql-api/query-api/#filtering"&gt;filters&lt;/a&gt;, &lt;a href="https://slicknode.com/docs/graphql-api/query-api/#sorting"&gt;sorting&lt;/a&gt; and high-performance data fetching logic. In contrast to other schema stitching solutions, Slicknode optimizes the data resolution automatically and fetches all the data of connected types in a single database query. &lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://slicknode.com/docs/extensions/remote-modules/"&gt;the documentation&lt;/a&gt; to learn how to add other GraphQL APIs to your Slicknode projects. &lt;/p&gt;

</description>
      <category>graphql</category>
      <category>serverless</category>
      <category>cms</category>
      <category>api</category>
    </item>
    <item>
      <title>How to Build GraphQL APIs that Scale, Serverless, in Minutes!</title>
      <dc:creator>Ivo Meißner</dc:creator>
      <pubDate>Mon, 27 Apr 2020 21:21:43 +0000</pubDate>
      <link>https://forem.com/slicknode/how-to-build-graphql-apis-that-scale-serverless-in-minutes-5a3m</link>
      <guid>https://forem.com/slicknode/how-to-build-graphql-apis-that-scale-serverless-in-minutes-5a3m</guid>
      <description>&lt;p&gt;Building high-quality GraphQL APIs is harder than one might think. Building GraphQL APIs that scale is even harder. The flexibility and power of GraphQL comes with its own unique challenges and problems as we have learned the hard way. When we set out to build Slicknode, we wanted to create a platform for building digital solutions in minutes instead of months. &lt;/p&gt;

&lt;p&gt;We are finally here! &lt;br&gt;
It has been months in the making and we are so excited to share the results with the world: &lt;/p&gt;

&lt;p&gt;We got rid of all our servers and we are running 100% serverless! You can now build advanced GraphQL applications in minutes and never have to worry about scalability and backend infrastructure again. &lt;br&gt;
You just define your data model, add the modules, and 3rd party APIs that you need, and Slicknode automatically launches a production-ready GraphQL API, powered by AWS Lambda and AWS Aurora Serverless.&lt;br&gt;
&lt;a href="https://slicknode.com"&gt;Learn more...&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  What's new?
&lt;/h2&gt;

&lt;p&gt;In addition to the massive improvements that come with the infrastructure upgrade, we are also shipping some major new features that enable a whole host of new use-cases and make it even easier to build complex applications and extend Slicknode. We will cover those features in detail&lt;br&gt;
in upcoming blog posts.&lt;/p&gt;

&lt;p&gt;Here are a few highlights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Shareable GraphQL APIs:&lt;/strong&gt; You can now deploy a GraphQL API directly from a git repository. Just clone it to your local machine and run &lt;code&gt;slicknode deploy&lt;/code&gt;. (&lt;a href="https://github.com/slicknode/example-blog-api"&gt;see an example&lt;/a&gt;) 
Collaborate with the open-source community
on a shared backend that can easily be customized (Multi-tenant SaaS-foundation, eCommerce starter, etc.)
This is also great for writing frontend tutorials or for creating demo backends. &lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://slicknode.com/docs/extensions/remote-modules/"&gt;Remote Modules&lt;/a&gt;:&lt;/strong&gt; Add your existing GraphQL APIs or APIs from 3rd party providers to your Slicknode project with 4 lines of configuration. Want to add your 
Salesforce data, the Github API, a Magento store, your existing Wordpress blog, etc. to your Graph? Done in 2 minutes. 
&lt;a href="https://slicknode.com/docs/extensions/remote-modules/"&gt;Mode details&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://slicknode.com/docs/extensions/apollo-federation/"&gt;Apollo Federation Support&lt;/a&gt;:&lt;/strong&gt; Slicknode now has
support for &lt;a href="https://www.apollographql.com/docs/apollo-server/federation/introduction/"&gt;Apollo Federation&lt;/a&gt;. 
If you are using an Apollo Federation architecture in your project, you can add the entire functionality of Slicknode as a microservice to your graph just by &lt;a href="https://slicknode.com/docs/extensions/apollo-federation/"&gt;installing the module&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Always-On Development Environments:&lt;/strong&gt; Create development environments in seconds without hassle. 
The development instances are now always on and don't go to sleep after inactivity any more.
&lt;a href="https://slicknode.com/pricing/"&gt;More details&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://slicknode.com/product/features/"&gt;Learn about all the features&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Relaunch?
&lt;/h2&gt;

&lt;p&gt;Since &lt;a href="https://slicknode.com/blog/graphql-cms-application-framework/"&gt;we launched the first version of Slicknode&lt;/a&gt;, a lot has happened. People have used Slicknode to build all kinds of applications, multi-tenant SaaS products, content management infrastructure, small personal projects, and mission-critical business applications. We have also &lt;a href="https://github.com/slicknode/"&gt;open sourced&lt;/a&gt; some components of the Slicknode platform, &lt;a href="https://www.npmjs.com/package/graphql-query-complexity"&gt;some of which&lt;/a&gt; have been downloaded millions of times and are used in thousands of GraphQL APIs around the globe. &lt;/p&gt;

&lt;p&gt;With feedback from countless current and potential customers, we were able to identify two &lt;br&gt;
main issues that led us to make this major upgrade:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Entry-Level Pricing:&lt;/strong&gt; We wanted to make it free and as easy as possible to get started with Slicknode.
The new serverless platform now only incurs cost when it is used and scales automatically. This is a game-changer and we were able to dramatically reduce the entry-level pricing while also offering free development instances.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Dedicated Infrastructure:&lt;/strong&gt; Enterprise level customers with mission-critical applications need an option to deploy their applications on dedicated infrastructure in their own VPC. 
We can now offer the option to create an entire dedicated cluster per customer with custom limits, on a custom domain with individual configuration. Need to host thousands of 
GraphQL APIs for a SaaS-product at a reasonable cost? No problem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This relaunch also dramatically improves the scalability and reliability&lt;br&gt;
of our platform. All the components that power the customer APIs are managed AWS services and scale on demand: AWS Lambda, AWS Aurora Serverless, AWS API Gateway, etc. &lt;br&gt;
Even on the lowest tier, we can now offer an API with no single point of failure, multiple availability zones, automatic failover, and redundant data replication.&lt;/p&gt;

&lt;h2&gt;
  
  
  We need your Feedback
&lt;/h2&gt;

&lt;p&gt;With the major infrastructure upgrade shipped, we now have more time to focus on new features and improvements. &lt;/p&gt;

&lt;p&gt;That's where we need your feedback. We want to know...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  What projects do you plan to build with Slicknode?&lt;/li&gt;
&lt;li&gt;  What features are you missing?&lt;/li&gt;
&lt;li&gt;  How can we take the Slicknode platform to the next level?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your feedback will shape what Slicknode is going to look like...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://slicknode.com/slack"&gt;Join our community on Slack&lt;/a&gt; or &lt;a href="https://console.slicknode.com/register"&gt;try the new platform&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>graphql</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
