<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: TheGuildBot</title>
    <description>The latest articles on DEV Community by TheGuildBot (@theguild_).</description>
    <link>https://dev.to/theguild_</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%2F671966%2Fdb54b8e2-d3ac-4a20-87b1-fb08f11b24c4.png</url>
      <title>DEV Community: TheGuildBot</title>
      <link>https://dev.to/theguild_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/theguild_"/>
    <language>en</language>
    <item>
      <title>Understanding the Differences Between GraphQL and REST API Gateways</title>
      <dc:creator>TheGuildBot</dc:creator>
      <pubDate>Tue, 03 Dec 2024 14:45:31 +0000</pubDate>
      <link>https://dev.to/the-guild/understanding-the-differences-between-graphql-and-rest-api-gateways-2apo</link>
      <guid>https://dev.to/the-guild/understanding-the-differences-between-graphql-and-rest-api-gateways-2apo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was published on Tuesday, December 3, 2024 by &lt;a href="https://github.com/saihaj" rel="noopener noreferrer"&gt;Saihajpreet Singh&lt;/a&gt; @ &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;API gateways serve as crucial intermediaries between clients and backend services, but GraphQL and&lt;br&gt;
REST gateways handle this responsibility quite differently. While a GraphQL gateway can be&lt;br&gt;
considered a superset of REST gateway functionality, each has its distinct characteristics and use&lt;br&gt;
cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Differences
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Request Processing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;REST API Gateway&lt;/strong&gt;: Handles traditional HTTP requests with fixed endpoints. Each endpoint
typically serves a specific purpose and returns a predefined data structure. The gateway routes
these requests to appropriate microservices based on URL patterns.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;GraphQL Gateway&lt;/strong&gt;: Processes queries written in the GraphQL query language, typically through a
single endpoint. It can understand complex queries requesting specific fields and relationships,
making it more flexible in handling varied data requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Data Aggregation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;REST Gateway&lt;/strong&gt;: Often requires multiple endpoints to gather related data, leading to potential
over-fetching or under-fetching of data. The gateway might need to make several internal calls to
different services to compose a complete response.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;GraphQL Gateway&lt;/strong&gt;: Excels at data aggregation by allowing clients to specify exactly what data
they need in a single request. The gateway can efficiently collect data from multiple services
based on the query structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Features and Capabilities
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Caching
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;REST Gateway&lt;/strong&gt;: Implements straightforward HTTP caching mechanisms. Responses can be cached
based on URLs and HTTP methods.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;GraphQL Gateway&lt;/strong&gt;: Requires more sophisticated caching strategies due to the dynamic nature of
queries. Often implements field-level caching and needs to consider query complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;REST Gateway&lt;/strong&gt;: Security is typically implemented at the endpoint level with traditional
authentication and authorization mechanisms.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;GraphQL Gateway&lt;/strong&gt;: Provides more granular security controls, allowing permissions to be set at
the field level. Can implement query complexity analysis to prevent abuse.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Schema Management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;REST Gateway&lt;/strong&gt;: No built-in schema management. API documentation typically relies on external
tools like Swagger/OpenAPI.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;GraphQL Gateway&lt;/strong&gt;: Schema management can be as straightforward as maintaining schema definitions
in code and versioning them with Git. Teams can choose between simple code-first approaches or
leverage specialized tools like GraphQL Hive for more advanced schema registry and validation
features. This flexibility allows teams to scale their schema management practices as their needs
grow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Service Integration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;REST Gateway&lt;/strong&gt;: No built-in way to integrate with other protocols.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;GraphQL Gateway&lt;/strong&gt;: A GraphQL gateway like
&lt;a href="https://the-guild.dev/graphql/hive/docs/gateway?utm_source=the_guild&amp;amp;utm_medium=blog&amp;amp;utm_campaign=understanding-the-differences-between-graphql-and-rest-api-gateways" rel="noopener noreferrer"&gt;Hive Gateway&lt;/a&gt;
unifies multiple protocols
(&lt;a href="https://the-guild.dev/graphql/mesh/v1/source-handlers/openapi?utm_source=the_guild&amp;amp;utm_medium=blog&amp;amp;utm_campaign=understanding-the-differences-between-graphql-and-rest-api-gateways" rel="noopener noreferrer"&gt;REST&lt;/a&gt;,
&lt;a href="https://the-guild.dev/graphql/mesh/v1/source-handlers/grpc?utm_source=the_guild&amp;amp;utm_medium=blog&amp;amp;utm_campaign=understanding-the-differences-between-graphql-and-rest-api-gateways" rel="noopener noreferrer"&gt;gRPC&lt;/a&gt;,
&lt;a href="https://the-guild.dev/graphql/mesh/v1/source-handlers/soap?utm_source=the_guild&amp;amp;utm_medium=blog&amp;amp;utm_campaign=understanding-the-differences-between-graphql-and-rest-api-gateways" rel="noopener noreferrer"&gt;SOAP&lt;/a&gt;
&amp;amp;
&lt;a href="https://the-guild.dev/graphql/mesh/v1/source-handlers?utm_source=the_guild&amp;amp;utm_medium=blog&amp;amp;utm_campaign=understanding-the-differences-between-graphql-and-rest-api-gateways" rel="noopener noreferrer"&gt;many more&lt;/a&gt;)
into a consistent interface using tools like
&lt;a href="https://the-guild.dev/graphql/mesh?utm_source=the_guild&amp;amp;utm_medium=blog&amp;amp;utm_campaign=understanding-the-differences-between-graphql-and-rest-api-gateways" rel="noopener noreferrer"&gt;GraphQL Mesh&lt;/a&gt;,
while supporting federation capabilities that let teams independently develop and deploy subgraphs
as part of a unified supergraph. Learn more about Federation
&lt;a href="https://the-guild.dev/graphql/hive/federation?utm_source=the_guild&amp;amp;utm_medium=blog&amp;amp;utm_campaign=understanding-the-differences-between-graphql-and-rest-api-gateways" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;GraphQL gateways represent the future of API architecture for several compelling reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Enhanced Developer Experience&lt;/strong&gt;: GraphQL's intuitive query language and self-documenting nature
significantly improve developer productivity.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Integration&lt;/strong&gt;: Easily integrate legacy services and offer a unified query experience.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Optimal Performance&lt;/strong&gt;: By allowing clients to request exactly what they need, GraphQL
eliminates the over-fetching and under-fetching problems common with REST APIs.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Future-Proof Architecture&lt;/strong&gt;: GraphQL's flexible schema system makes it easier to evolve your
API over time without breaking existing clients.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Better Resource Utilization&lt;/strong&gt;: The ability to combine multiple data requirements into a single
request reduces server load and network overhead.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Strong Ecosystem&lt;/strong&gt;: The GraphQL ecosystem offers excellent tools for monitoring, testing, and
managing your API gateway.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;While REST API gateways have served us well, GraphQL gateways offer superior capabilities for modern&lt;br&gt;
applications. Their ability to handle complex data requirements efficiently, combined with excellent&lt;br&gt;
developer experience and powerful tools, makes them the recommended choice for new API gateway&lt;br&gt;
implementations. Organizations can start simple with basic schema management in Git and gradually&lt;br&gt;
adopt more sophisticated tools like Hive as their needs evolve.&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>graphqlhive</category>
    </item>
    <item>
      <title>Extending your GraphQL service: Federation or Schema Stitching</title>
      <dc:creator>TheGuildBot</dc:creator>
      <pubDate>Thu, 21 Nov 2024 14:16:40 +0000</pubDate>
      <link>https://dev.to/the-guild/extending-your-graphql-service-federation-or-schema-stitching-dkp</link>
      <guid>https://dev.to/the-guild/extending-your-graphql-service-federation-or-schema-stitching-dkp</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was published on Monday, November 18, 2024 by &lt;a href="https://www.linkedin.com/in/emily-y-goodwin/" rel="noopener noreferrer"&gt;Emily Goodwin&lt;/a&gt; @ &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you're looking to extend your GraphQL service into separated services, you've likely come across&lt;br&gt;
two key terms: schema stitching and federation. Even if these concepts are new to you, don't&lt;br&gt;
worry—this post will introduce you to both approaches and help you understand their role in&lt;br&gt;
enhancing your GraphQL infrastructure.&lt;/p&gt;

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

&lt;p&gt;Let's start with a brief overview of GraphQL: it's a query language and runtime for APIs that work&lt;br&gt;
with your existing data. GraphQL delivers precisely the data you need—no more, no less—and allows&lt;br&gt;
APIs to evolve over time.&lt;/p&gt;

&lt;p&gt;However as GraphQL gained widespread adoption, many companies faced growing pains with their&lt;br&gt;
implementations. As their graphs grew, they began to face the challenges typical of monolithic&lt;br&gt;
systems. These large graphs blurred the lines between distinct business domains, which is where&lt;br&gt;
separating GraphQL services becomes beneficial.&lt;/p&gt;

&lt;p&gt;There are several reasons why you might want to split your GraphQL service into smaller, separate&lt;br&gt;
services:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separate Business Domains&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In most applications, data is already organized by business domains. For instance, the data and&lt;br&gt;
logic behind a &lt;code&gt;Users&lt;/code&gt; service are distinct from that of an &lt;code&gt;Orders&lt;/code&gt; service. Separating your&lt;br&gt;
GraphQL services allows you to maintain this natural separation, making it easier to manage,&lt;br&gt;
develop, and scale each domain individually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scaling Requirements&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As your GraphQL service grows, maintaining a single, monolithic system can lead to complexity and&lt;br&gt;
performance issues. Different parts of the system may have varying scaling needs—for example,&lt;br&gt;
user-related queries might need to handle more traffic than order-related ones. Splitting services&lt;br&gt;
by domain allows each one to scale independently based on demand, improving both performance and&lt;br&gt;
resource efficiency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Simpler Ownership and Maintenance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Having distinct GraphQL schemas and resolvers for different services enables parallel development by&lt;br&gt;
different teams. It also simplifies ownership and accountability, as each service can be managed and&lt;br&gt;
maintained independently. Smaller, focused services are easier to understand, test, and deploy,&lt;br&gt;
making long-term maintenance less burdensome compared to a single, complex monolith.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the Solution?
&lt;/h2&gt;

&lt;p&gt;The solution may seem straightforward: separate the different domains and information into different&lt;br&gt;
schemas. But what happens when domains or information are related?&lt;/p&gt;

&lt;p&gt;This is where schema stitching or federation comes into play. These approaches allow definitions to&lt;br&gt;
relate data between different schemas.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://the-guild.dev/graphql/stitching/docs" rel="noopener noreferrer"&gt;Schema Stitching&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Schema stitching takes many smaller services’ schemas and stitches them together to make a larger&lt;br&gt;
schema. This larger schema is used by a proxy service, the gateway, to delegate different parts of&lt;br&gt;
the query to different subschema services.&lt;/p&gt;

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

&lt;p&gt;There are three main approaches to schema stitching:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://the-guild.dev/graphql/stitching/docs/approaches/schema-extensions" rel="noopener noreferrer"&gt;Schema Extension&lt;/a&gt; (Gateway-Level Configuration)
&lt;/h4&gt;

&lt;p&gt;Schema extension uses schema delegation to take different subschemas and extend them at the gateway&lt;br&gt;
level.&lt;/p&gt;

&lt;p&gt;Say you had a type, &lt;code&gt;book&lt;/code&gt; and a type &lt;code&gt;author&lt;/code&gt; in different schemas and services. At the gateway&lt;br&gt;
level you can extend the type &lt;code&gt;book&lt;/code&gt; with a new field &lt;code&gt;author&lt;/code&gt; that delegates to the &lt;code&gt;author&lt;/code&gt;&lt;br&gt;
service.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://the-guild.dev/graphql/stitching/docs/approaches/type-merging" rel="noopener noreferrer"&gt;Type Merging&lt;/a&gt; (Gateway-Level Configuration)
&lt;/h4&gt;

&lt;p&gt;Type merging allows for partial definitions of a type to exist in any subschema which are all merged&lt;br&gt;
into a unified type at the gateway.&lt;/p&gt;

&lt;p&gt;This is useful if you have different standalone GraphQL APIs and you need to configure those at the&lt;br&gt;
gateway level.&lt;/p&gt;

&lt;p&gt;Lets consider a situation where you needed a type &lt;code&gt;author&lt;/code&gt; but had two different services. In the&lt;br&gt;
first service you would have the fields &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; . In the second service you would have the&lt;br&gt;
fields &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt;. In the gateway it would merge the &lt;code&gt;author&lt;/code&gt; type to contain all the&lt;br&gt;
fields &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, and &lt;code&gt;name&lt;/code&gt;. When you built a query it would go to the service that&lt;br&gt;
declared the type.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://the-guild.dev/graphql/stitching/docs/approaches/stitching-directives" rel="noopener noreferrer"&gt;Stitching Directives&lt;/a&gt; (Service Level Configuration)
&lt;/h4&gt;

&lt;p&gt;Similar to Federation, schema stitching allows for directives-based approach of schema stitching.&lt;br&gt;
This allows you to configure your merging at the service level versus the gateway level.&lt;/p&gt;

&lt;p&gt;In this example you would use the &lt;code&gt;@merge&lt;/code&gt; directive and &lt;code&gt;@key&lt;/code&gt; directive with a selectionSet to&lt;br&gt;
explain how to merge the schemas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Federation
&lt;/h2&gt;

&lt;p&gt;Federation lets you use directives to combine multiple APIs into a single federated graph.&lt;/p&gt;

&lt;p&gt;When a user makes a request, it goes through the router. Based on the directives, the router&lt;br&gt;
orchestrates and distributes the request across the APIs and returns a unified response.&lt;/p&gt;

&lt;p&gt;This router needs a supergraph as a map to route to the different subgraphs, this supergraph can be&lt;br&gt;
created by paid applications like GraphOS or free services such as The Guild’s own&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/hive" rel="noopener noreferrer"&gt;Hive&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Federation introduces the concept of Entities which are federated types that exist across multiple&lt;br&gt;
subgraphs.&lt;/p&gt;

&lt;p&gt;Here is a comparison of Federation-Compatible Gateway Implementations:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://the-guild.dev/graphql/hive/federation-gateway-audit" rel="noopener noreferrer"&gt;https://the-guild.dev/graphql/hive/federation-gateway-audit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more information on Federation and The Guild's support, please see here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://the-guild.dev/graphql/hive/federation" rel="noopener noreferrer"&gt;https://the-guild.dev/graphql/hive/federation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is the Overall Difference?
&lt;/h2&gt;

&lt;p&gt;Schema stitching merges multiple schemas into a single unified schema by directly combining them. In&lt;br&gt;
this setup, the gateway executes the requests by resolving data from multiple services, often&lt;br&gt;
relying on custom logic to determine how to fetch and combine the data from different schemas.&lt;/p&gt;

&lt;p&gt;Federation allows each subgraph to manage part of the unified schema independently. The central&lt;br&gt;
gateway composes these subgraphs into a unified graph, and relationships between services are&lt;br&gt;
handled through federation directives like &lt;code&gt;@key&lt;/code&gt;, &lt;code&gt;@provides&lt;/code&gt;, and &lt;code&gt;@extends&lt;/code&gt;. The gateway uses&lt;br&gt;
these directives to predetermine how data is fetched and merged across services.&lt;/p&gt;

&lt;p&gt;This structure enables static checks, ensuring predictable behavior of the gateway in production. By&lt;br&gt;
using tools like Hive CLI or Apollo Studio to create the supergraph, you can validate the schema&lt;br&gt;
ahead of time, preventing conflicts before the supergraph is deployed. Additionally, these tools&lt;br&gt;
provide insight into how the gateway will execute queries, giving you confidence in its behavior&lt;br&gt;
after deployment.&lt;/p&gt;

&lt;p&gt;The Guild’s products are compatible with both Federation and Schema Stitching.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which One Is Better for Your Use Case?
&lt;/h2&gt;

&lt;p&gt;This is a question only you can answer, but let’s look at common questions you should ask to&lt;br&gt;
determine which approach is better for your use case.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Schema Stitching&lt;/th&gt;
&lt;th&gt;Federation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Customizability&lt;/td&gt;
&lt;td&gt;More&lt;/td&gt;
&lt;td&gt;Less&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;Less&lt;/td&gt;
&lt;td&gt;More&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collaboration&lt;/td&gt;
&lt;td&gt;Less&lt;/td&gt;
&lt;td&gt;More&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GraphQL Knowledge Required for subschema/graphlet teams&lt;/td&gt;
&lt;td&gt;Less&lt;/td&gt;
&lt;td&gt;More&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GraphQL Knowledge Required for Gateway team&lt;/td&gt;
&lt;td&gt;More&lt;/td&gt;
&lt;td&gt;Less&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;What is the overall GraphQL knowledge for the teams involved?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Federation requires more over knowledge of GraphQL from all teams involved as they need to work&lt;br&gt;
together to make the federated schema work as expected. Schema Stitching requires less knowledge&lt;br&gt;
from subschema teams but more knowledge from the team owning the gateway as the stitching logic can&lt;br&gt;
become complex as the number of services grow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is your organizational structure?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have teams across organizations who need to collaborate, it may be better to use Apollo&lt;br&gt;
Federation as it supports more collaboration on the schema so teams need to work together and&lt;br&gt;
understand what each other is doing with their schema.&lt;/p&gt;

&lt;p&gt;If you want to minimize the need for teams to collaborate closely, schema stitching might be a good&lt;br&gt;
choice. With schema stitching, the gateway "magically" combines the services for the teams managing&lt;br&gt;
subschemas. The gateway handles most of the stitching process, so subschema teams don't need to&lt;br&gt;
worry about how their schemas are integrated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How fast do you need to build your solution?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Schema Stitching is usually a faster approach for smaller or simpler projects since it is straight&lt;br&gt;
forward. You can combine schemas quickly without much additional infrastructure but it takes longer&lt;br&gt;
to develop as the overall service grows.&lt;/p&gt;

&lt;p&gt;Federation takes a bit longer to set up as it requires multiple subgraphs, a gateway, and a&lt;br&gt;
registry. As the services grow, Federation can speed up development for teams since each team&lt;br&gt;
independently manages their service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How customizable does your implementation of the gateway need to be?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Schema stitching allows for a deeper customization of schemas, resolvers, and transformations since&lt;br&gt;
you have full control over how each service is combined.&lt;/p&gt;

&lt;p&gt;Federation is more suited for scalability and team collaboration. Customization is more structured&lt;br&gt;
through federation directives.&lt;/p&gt;

&lt;p&gt;If you would like to talk to an expert in regards to your GraphQL implementation, feel free to get&lt;br&gt;
in touch with The Guild &lt;a href="https://the-guild.dev/#get-in-touch" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>graphqltools</category>
      <category>schemastitching</category>
      <category>federation</category>
    </item>
    <item>
      <title>GraphQL Response Caching with Envelop</title>
      <dc:creator>TheGuildBot</dc:creator>
      <pubDate>Fri, 15 Nov 2024 11:53:58 +0000</pubDate>
      <link>https://dev.to/the-guild/graphql-response-caching-with-envelop-2c4o</link>
      <guid>https://dev.to/the-guild/graphql-response-caching-with-envelop-2c4o</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was published on Thursday, August 19, 2021 by &lt;a href="https://twitter.com/n1rual" rel="noopener noreferrer"&gt;Laurin Quast&lt;/a&gt; @ &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A Brief Introduction to Caching
&lt;/h2&gt;

&lt;p&gt;Huge GraphQL query operations can slow down your server as deeply nested selection sets can cause a&lt;br&gt;
lot of subsequent database reads or calls to other remote services. Tools like &lt;code&gt;DataLoader&lt;/code&gt; can&lt;br&gt;
reduce the amount of concurrent and subsequent requests via batching and caching during the&lt;br&gt;
execution of a single GraphQL operation. Features like &lt;code&gt;@defer&lt;/code&gt; and &lt;code&gt;@stream&lt;/code&gt; can help with&lt;br&gt;
streaming slow-to-retrieve result partials to the clients progressively. However, for subsequent&lt;br&gt;
requests we hit the same bottle-neck over and over again.&lt;/p&gt;

&lt;p&gt;What if we don't need to go through the execution phase at all for subsequent requests that execute&lt;br&gt;
the same query operation with the same variables?&lt;/p&gt;

&lt;p&gt;A common practice for reducing slow requests is to leverage caching. There are many types of caching&lt;br&gt;
available. E.g. We could cache the whole HTTP responses based on the POST body of the request or an&lt;br&gt;
in memory cache within our GraphQL field resolver business logic in order to hit slow services less&lt;br&gt;
frequently.&lt;/p&gt;

&lt;p&gt;Having a cache comes with the drawback of requiring some kind of cache invalidation mechanism.&lt;br&gt;
Expiring the cache via a TTL (time to live) is a widespread practice, but can result in hitting the&lt;br&gt;
cache too often or too scarcely. Another popular strategy is to incorporate cache invalidation logic&lt;br&gt;
into the business logic. Writing such logic can potentially become too verbose and hard to maintain.&lt;br&gt;
Other systems might use database write log observers for invalidating entities based on updated&lt;br&gt;
database rows.&lt;/p&gt;

&lt;p&gt;In a strict REST API environment, caching entities is significantly easier, as each endpoint&lt;br&gt;
represents one resource, and thus a &lt;code&gt;GET&lt;/code&gt; method can be cached and a &lt;code&gt;PATCH&lt;/code&gt; method can be used for&lt;br&gt;
automatically invalidating the cache for the corresponding &lt;code&gt;GET&lt;/code&gt; request, which is described via the&lt;br&gt;
HTTP path (&lt;code&gt;/api/user/12&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;With GraphQL such things become much harder and complicated. First, we usually only have a single&lt;br&gt;
HTTP endpoint &lt;code&gt;/graphql&lt;/code&gt; that only accepts &lt;code&gt;POST&lt;/code&gt; requests. A query operation execution result could&lt;br&gt;
contain many different types of entities, thus, we need different strategies for caching GraphQL&lt;br&gt;
APIs.&lt;/p&gt;

&lt;p&gt;SaaS services like FastQL and GraphCDN started popping providing proxies for your existing GraphQL&lt;br&gt;
API, that magically add response based caching. But how does this even work?&lt;/p&gt;
&lt;h2&gt;
  
  
  How Does GraphQL Response Caching Work?
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Caching Query Operations
&lt;/h3&gt;

&lt;p&gt;In order to cache a GraphQL execution result (response) we need to build an identifier based on the&lt;br&gt;
input that can be used to identify whether a response can be served from the cache or must be&lt;br&gt;
executed and then stored within the cache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: GraphQL Query Operation&lt;/strong&gt;&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;UserProfileQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&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="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="nv"&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;__typename&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;repositories&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;friends&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;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;__typename&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;login&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;&lt;strong&gt;Example: GraphQL Variables&lt;/strong&gt;&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&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;Usually those inputs are the Query operation document and the variables for such an operation&lt;br&gt;
document.&lt;/p&gt;

&lt;p&gt;Thus, a response cache can store the execution result under a cache key that is built from those&lt;br&gt;
inputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OperationCacheKey (e.g. SHA1) = hash(GraphQLOperationString, Stringify(GraphQLVariables))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under some circumstances it is also required to cache based on the request initiator. E.g. a user&lt;br&gt;
requesting his profile should not receive the cached profile of another user. In such a scenario,&lt;br&gt;
building the operation cache key should also include a partial that uniquely identifies the&lt;br&gt;
requestor. This could be a user ID extracted from an authorization token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OperationCacheKey (e.g. SHA1) = hash(GraphQLOperationString, Stringify(GraphQLVariables), RequestorId)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows us to identify recurring operations with the same variables and serve it from the cache&lt;br&gt;
for subsequent requests. If we can serve a response from the cache we don't need to parse the&lt;br&gt;
GraphQL operation document and furthermore can skip the expensive execution phase. That will result&lt;br&gt;
in significant speed improvements.&lt;/p&gt;

&lt;p&gt;But in order to make our cache smart we still need a suitable cache invalidation mechanism.&lt;/p&gt;
&lt;h3&gt;
  
  
  Invalidating Cached GraphQL Query Operations
&lt;/h3&gt;

&lt;p&gt;Let's take a look at a possible execution result for the GraphQL operation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: GraphQL Execution Result&lt;/strong&gt;&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;"data"&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;"user"&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;"__typename"&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"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"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;"login"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dotan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"repositories"&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="s2"&gt;"codegen"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"friends"&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;"__typename"&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"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"login"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"urigo"&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;"__typename"&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"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"login"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n1ru4l"&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;Many frontend frameworks cache GraphQL operation results in a normalized cache. The identifier for&lt;br&gt;
storing the single entities of a GraphQL operation result within the cache is usually the &lt;code&gt;id&lt;/code&gt; field&lt;br&gt;
of object types for schemas that use global unique IDs or a compound of the &lt;code&gt;__typename&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt;&lt;br&gt;
field for schemas that use non-global ID fields.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: Normalized GraphQL Client Cache&lt;/strong&gt;&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;"User:1"&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;"__typename"&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"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"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;"login"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dotan"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"repositories"&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="s2"&gt;"codegen"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"friends"&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="s2"&gt;"$$ref:User:2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$$ref:User:3"&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;"User: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="nl"&gt;"__typename"&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"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"login"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"urigo"&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;"User:3"&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;"__typename"&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"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"login"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n1ru4l"&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;Interestingly, the same strategy for constructing cache keys on the client can also be used on the&lt;br&gt;
backend for tracking which GraphQL operations contain which entities. That allows invalidating&lt;br&gt;
GraphQL query operation results based on entity IDs.&lt;/p&gt;

&lt;p&gt;For the execution result entity IDS that could be used for invalidating the operation are the&lt;br&gt;
following: &lt;code&gt;User:1&lt;/code&gt;, &lt;code&gt;User:2&lt;/code&gt; and &lt;code&gt;User:3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And also keep a register that maps entities to operation cache keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Entity   List of Operation cache keys that reference a entity

User:1   OperationCacheKey1, OperationCacheKey2, ...
User:2   OperationCacheKey2, OperationCacheKey3, ...
User:3   OperationCacheKey3, OperationCacheKey1, ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows us to keep track of which GraphQL operations must be invalidated once a certain entity&lt;br&gt;
becomes stale.&lt;/p&gt;

&lt;p&gt;The remaining question is, how can we track an entity becoming stale?&lt;/p&gt;

&lt;p&gt;As mentioned before, listening to a database write log is a possible option - but the implementation&lt;br&gt;
is very specific and differs based on the chosen database type. Time to live is also a possible, but&lt;br&gt;
a very inaccurate solution.&lt;/p&gt;

&lt;p&gt;Another solution is to add invalidation logic within our GraphQL mutation resolver. By the GraphQL&lt;br&gt;
Specification mutations are meant to modify our GraphQL graph.&lt;/p&gt;

&lt;p&gt;A common pattern when sending mutations from clients is to select and return affected/mutated&lt;br&gt;
entities with the selection set.&lt;/p&gt;

&lt;p&gt;For our example from above the following could be a possible mutation for adding a new repository to&lt;br&gt;
the repositories field on the user entity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example: GraphQL Mutation&lt;/strong&gt;&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;RepositoryAddMutation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$userId&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="nv"&gt;$repositoryName&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;repositoryAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;repositoryName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$repositoryName&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;user&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="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;repositories&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;&lt;strong&gt;Example: GraphQL Mutation Execution Result&lt;/strong&gt;&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;"data"&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;"repositoryAdd"&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;"user"&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;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"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;"repositories"&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="s2"&gt;"codegen"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"envelop"&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;Similar to how we build entity identifiers from the execution result of query operations for&lt;br&gt;
identifying what entities are referenced in which operations, we can extract the entity identifiers&lt;br&gt;
from the mutation operation result for invalidating affected operations.&lt;/p&gt;

&lt;p&gt;In this specific case all operations that select &lt;code&gt;User:1&lt;/code&gt; should be invalidated.&lt;/p&gt;

&lt;p&gt;Such an implementation makes the assumption that all mutations by default select affected entities&lt;br&gt;
and, furthermore, all mutations of underlying entities are done through the GraphQL gateway via&lt;br&gt;
mutations. In a scenario where we have actors that are not GraphQL services or services that operate&lt;br&gt;
directly on the database, we can use this approach in a hybrid model with other methods such as&lt;br&gt;
listening to database write logs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Envelop Response Cache
&lt;/h2&gt;

&lt;p&gt;The Envelop response cache plugin now provides primitives and a reference in memory store&lt;br&gt;
implementation for adopting such a cache with all the features mentioned above with any GraphQL&lt;br&gt;
server.&lt;/p&gt;

&lt;p&gt;The goal of the response cache plugin is to educate how such mechanisms are implemented and&lt;br&gt;
furthermore give developers the building blocks for constructing their own global cache with their&lt;br&gt;
cloud provider of choice.&lt;/p&gt;

&lt;p&gt;Adding a response cache to an existing envelop GraphQL server setup is as easy as adding the plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;envelop&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@envelop/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useResponseCache&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@envelop/response-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getEnveloped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;envelop&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other plugins ...&lt;/span&gt;
    &lt;span class="nf"&gt;useResponseCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need to imperatively invalidate you can do that by providing the cache to the plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;envelop&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@envelop/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createInMemoryCache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useResponseCache&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@envelop/response-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;emitter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./event-emitter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createInMemoryCache&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;invalidate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;entity&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;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;typename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getEnveloped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;envelop&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other plugins ...&lt;/span&gt;
    &lt;span class="nf"&gt;useResponseCache&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The caching behavior can be fully customized. A TTL can be provided global or more granular per type&lt;br&gt;
or schema coordinate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;envelop&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@envelop/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useResponseCache&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@envelop/response-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getEnveloped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;envelop&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other plugins ...&lt;/span&gt;
    &lt;span class="nf"&gt;useResponseCache&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="c1"&gt;// cache operations for 1 hour by default&lt;/span&gt;
      &lt;span class="na"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;ttlPerType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// cache operation containing Stock object type for 500ms&lt;/span&gt;
        &lt;span class="na"&gt;Stock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;ttlPerSchemaCoordinate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// cache operation containing Query.rocketCoordinates selection for 100ms&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Query.rocketCoordinates&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="c1"&gt;// never cache responses that include a RefreshToken object type.&lt;/span&gt;
      &lt;span class="na"&gt;ignoredTypes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RefreshToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Need to cache based on the user? No problem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;envelop&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@envelop/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useResponseCache&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@envelop/response-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getEnveloped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;envelop&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other plugins ...&lt;/span&gt;
    &lt;span class="nf"&gt;useResponseCache&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="c1"&gt;// context is the GraphQL context that would be used for execution&lt;/span&gt;
      &lt;span class="na"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;context&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;context&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="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="c1"&gt;// never serve cache for admin users&lt;/span&gt;
      &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;context&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;context&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="nf"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&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="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't want to automatically invalidate based on mutations? Also, configurable!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;envelop&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@envelop/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useResponseCache&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@envelop/response-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getEnveloped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;envelop&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other plugins ...&lt;/span&gt;
    &lt;span class="nf"&gt;useResponseCache&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="c1"&gt;// some might prefer invalidating only based on a database write log&lt;/span&gt;
      &lt;span class="na"&gt;invalidateViaMutation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want a global cache on Redis? Build a cache that implements the &lt;code&gt;Cache&lt;/code&gt; interface and share it with&lt;br&gt;
the community!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/** set a cache response */&lt;/span&gt;
  &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="cm"&gt;/** id/hash of the operation */&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="cm"&gt;/** the result that should be cached */&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExecutionResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="cm"&gt;/** array of entity records that were collected during execution */&lt;/span&gt;
    &lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Iterable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CacheEntityRecord&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="cm"&gt;/** how long the operation should be cached */&lt;/span&gt;
    &lt;span class="na"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;PromiseOrValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="cm"&gt;/** get a cached response */&lt;/span&gt;
  &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;PromiseOrValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Maybe&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ExecutionResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
  &lt;span class="cm"&gt;/** invalidate operations via typename or id */&lt;/span&gt;
  &lt;span class="nf"&gt;invalidate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Iterable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CacheEntityRecord&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;PromiseOrValue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More information about all possible configuration options can be found on&lt;br&gt;
&lt;a href="https://envelop.dev/plugins/use-response-cache" rel="noopener noreferrer"&gt;the response cache docs on the Plugin Hub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Next?
&lt;/h2&gt;

&lt;p&gt;We are excited to explore new directions and make enterprise solutions accessible for all kinds of&lt;br&gt;
developers.&lt;/p&gt;

&lt;p&gt;What if the response cache could be used as a proxy on edge cloud functions distributed around the&lt;br&gt;
world, which would allow using envelop as a http proxy to your existing GraphQL server? This is&lt;br&gt;
something we would love to explore more (or even see contributions and projects from other&lt;br&gt;
open-source developers).&lt;/p&gt;

&lt;p&gt;We also want to make other practices such as rate limits based on operation cost calculation as used&lt;br&gt;
by huge corporations like Shopify available as envelop plugins.&lt;/p&gt;

&lt;p&gt;Do you have any ideas, want to contribute or report issues? Start a GitHub discussion/issue or&lt;br&gt;
contact us via the chat!&lt;/p&gt;

</description>
      <category>graphql</category>
    </item>
    <item>
      <title>How to write GraphQL resolvers effectively</title>
      <dc:creator>TheGuildBot</dc:creator>
      <pubDate>Mon, 04 Nov 2024 13:05:23 +0000</pubDate>
      <link>https://dev.to/the-guild/how-to-write-graphql-resolvers-effectively-4031</link>
      <guid>https://dev.to/the-guild/how-to-write-graphql-resolvers-effectively-4031</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was published on Monday, November 4, 2024 by &lt;a href="https://twitter.com/eddeee888" rel="noopener noreferrer"&gt;Eddy Nguyen&lt;/a&gt; @ &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Resolvers are the fundamental building blocks of a GraphQL server. To build a robust and scalable&lt;br&gt;
GraphQL server, we must understand how to write GraphQL resolvers effectively. In this blog post, we&lt;br&gt;
will explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  how resolvers work&lt;/li&gt;
&lt;li&gt;  concepts such as resolver map, resolver chain, defer resolve and mappers&lt;/li&gt;
&lt;li&gt;  tools and best practices&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Glossary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Resolver map&lt;/strong&gt;: An object containing resolvers that match the types and fields in the GraphQL
schema.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Resolver chain&lt;/strong&gt;: The order of resolvers execution when the GraphQL server handles a request.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Mapper&lt;/strong&gt;: The shape of the data returned by a resolver to become the &lt;code&gt;parent&lt;/code&gt; parameter of the
next resolver in the resolver chain.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Defer resolve&lt;/strong&gt;: A technique to avoid unnecessary resolver execution of a field early in the
resolver chain.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What Are Resolvers?
&lt;/h2&gt;

&lt;p&gt;In a GraphQL server, a resolver is a function that "resolves" a value which means doing arbitrary&lt;br&gt;
combination of logic to return a value. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  returning a value statically&lt;/li&gt;
&lt;li&gt;  fetching data from a database or an external API to return a value&lt;/li&gt;
&lt;li&gt;  executing a complex business logic to return a value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each field in a GraphQL schema has an optional corresponding resolver function. When a client&lt;br&gt;
queries a field, the server executes the resolver function to resolve the field.&lt;/p&gt;

&lt;p&gt;Given this example schema:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```graphql filename="src/graphql/schema.graphql"&lt;br&gt;
type Query {&lt;br&gt;
  movie(id: ID!): Movie&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;type Movie {&lt;br&gt;
  id: ID!&lt;br&gt;
  name: String!&lt;br&gt;
  actors: [Actor!]!&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;type Actor {&lt;br&gt;
  id: ID!&lt;br&gt;
  stageName: String!&lt;br&gt;
}&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


We can write a **resolver map** like this:



```ts filename="src/graphql/resolvers.ts"
const resolvers = {
  Query: {
    movie: () =&amp;gt; {} // `Query.movie` resolver
  },
  Movie: {
    id: () =&amp;gt; {}, // `Movie.id` resolver
    name: () =&amp;gt; {}, // `Movie.name` resolver
    actors: () =&amp;gt; {} // `Movie.actors` resolver
  },
  Actor: {
    id: () =&amp;gt; {}, // `Actor.id` resolver
    stageName: () =&amp;gt; {} // `Actor.stageName` resolver
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We will discuss how the code flows through resolvers when the server handles a request in the next&lt;br&gt;
section.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code Flow and Resolver Chain
&lt;/h2&gt;

&lt;p&gt;Using the same schema, we may send a query like this:&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;Movie&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;movie&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="s2"&gt;"1"&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="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;actors&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="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;stageName&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;Once the server receives this query, it starts at &lt;code&gt;Query.movie&lt;/code&gt; resolver, and since it returns a&lt;br&gt;
nullable &lt;code&gt;Movie&lt;/code&gt; object type, two scenarios can happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If &lt;code&gt;Query.movie&lt;/code&gt; resolver returns &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;, the code flow stops here, and the server
returns &lt;code&gt;movie: null&lt;/code&gt; to the client.&lt;/li&gt;
&lt;li&gt;  If &lt;code&gt;Query.movie&lt;/code&gt; resolver returns anything else (e.g. objects, class instances, number, non-null
falsy values, etc.), the code flow continues. Whatever being returned - usually called
&lt;strong&gt;mapper&lt;/strong&gt; - will be the first argument of the Movie resolvers i.e. &lt;code&gt;Movie.id&lt;/code&gt; and &lt;code&gt;Movie.name&lt;/code&gt;
resolvers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This process repeats itself until a GraphQL scalar field needs to be resolved. The order of the&lt;br&gt;
resolvers execution is called the &lt;strong&gt;resolver chain&lt;/strong&gt;. For the example request, the resolver chain&lt;br&gt;
may look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
  A[Query.movie] --&amp;gt; B(Movie.id)
  A[Query.movie] --&amp;gt; C(Movie.name)
  A[Query.movie] --&amp;gt; D(Movie.actors)
  D --&amp;gt; E(Actor.id)
  D --&amp;gt; F(Actor.stageName)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;
  There are four positonal arguments of a resolver function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;parent&lt;/code&gt;: the value returned by the parent resolver.

&lt;ul&gt;
&lt;li&gt;  For root-level resolvers like &lt;code&gt;Query.movie&lt;/code&gt;, &lt;code&gt;parent&lt;/code&gt; is always &lt;code&gt;undefined&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  For other object-type resolvers like &lt;code&gt;Movie.id&lt;/code&gt; and &lt;code&gt;Movie.name&lt;/code&gt;, &lt;code&gt;parent&lt;/code&gt; is the value returned by parent resolvers like &lt;code&gt;Query.movie&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;args&lt;/code&gt;: this is the arguments passed by client operations. In our example query, &lt;code&gt;Query.movie&lt;/code&gt; resolver would receive &lt;code&gt;{ id: "1" }&lt;/code&gt; as &lt;code&gt;args&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;context&lt;/code&gt;: An object passed through the resolver chain. It is useful for passing information between resolvers, such as authentication information, database connection, etc.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;info&lt;/code&gt;: An object containing information about the operation, such as operation AST, path to the resolver, etc.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We must return a value that can be handled by the scalars. In our example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;Movie.id&lt;/code&gt; and &lt;code&gt;Actor.id&lt;/code&gt; resolvers must return a non-nullable value that can be coerced into the
&lt;code&gt;ID&lt;/code&gt; scalar i.e. &lt;code&gt;string&lt;/code&gt; or &lt;code&gt;number&lt;/code&gt; values.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Movie.name&lt;/code&gt; and &lt;code&gt;Actor.stageName&lt;/code&gt; resolver must return a non-nullable value that can be coerced
into the &lt;code&gt;String&lt;/code&gt; scalar i.e. &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;boolean&lt;/code&gt; or &lt;code&gt;number&lt;/code&gt; values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br&gt;
  You can learn about GraphQL Scalar, including native Scalar and coercion concept, in this guide&lt;br&gt;
  &lt;a href="https://the-guild.dev/blog/the-complete-graphql-scalar-guide" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;It is important to remember that we will encounter runtime errors if the resolver returns unexpected&lt;br&gt;
values. Some common scenarios are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  a resolver returns &lt;code&gt;null&lt;/code&gt; to a non-nullable field&lt;/li&gt;
&lt;li&gt;  a resolver returns a value that cannot be coerced into the expected scalar type&lt;/li&gt;
&lt;li&gt;  a resolver returns a non-array value to an array field, such as &lt;code&gt;Movie.actors&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How to Implement Resolvers
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Implementing Resolvers - Or Not
&lt;/h3&gt;

&lt;p&gt;If an empty resolver map is provided to the GraphQL server, the server still tries to handle&lt;br&gt;
incoming requests. However, it will return &lt;code&gt;null&lt;/code&gt; for every root-level field in the schema. This&lt;br&gt;
means if a root-level field like &lt;code&gt;Query.movie&lt;/code&gt;'s return type is non-nullable, we will encounter&lt;br&gt;
runtime error.&lt;/p&gt;

&lt;p&gt;If object type resolvers are omitted, the server will try to return the property of the same name&lt;br&gt;
from &lt;code&gt;parent&lt;/code&gt;. Here's what &lt;code&gt;Movie&lt;/code&gt; resolvers may look like if they are omitted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolvers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="c1"&gt;// 👈 Empty `Movie` resolvers object,&lt;/span&gt;
  &lt;span class="na"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 👈 or undefined/omitted `Movie` resolvers object...&lt;/span&gt;

  &lt;span class="c1"&gt;// 👇 ...are the equivalent of the following `Movie` resolvers:&lt;/span&gt;
  &lt;span class="na"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;actors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actors&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;This means if &lt;code&gt;Query.movie&lt;/code&gt; resolver returns an object with &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;actors&lt;/code&gt; properties,&lt;br&gt;
we can omit the &lt;code&gt;Movie&lt;/code&gt; and &lt;code&gt;Actor&lt;/code&gt; resolvers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolvers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Harry Potter and the Half-Blood Prince&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;actors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;stageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Daniel Radcliffe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;stageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Emma Watson&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;stageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rupert Grint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// 💡 `Movie` and `Actor` resolvers are omitted here but it still works,&lt;/span&gt;
  &lt;span class="c1"&gt;// Thanks to default resolvers!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this very simple example where we are returning static values, this will work. However, in a&lt;br&gt;
real-world scenario where we may fetch data from a database or an external API, we must consider the&lt;br&gt;
response data shape, and the app performance. We will try to simlulate a real-world scenario in the&lt;br&gt;
next section.&lt;/p&gt;
&lt;h3&gt;
  
  
  Implementing Resolvers for Real-World Scenarios
&lt;/h3&gt;

&lt;p&gt;Below is an object this can be used as an in-memory database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;movies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Movies table&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;movieName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Harry Potter and the Half-Blood Prince&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;actors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Actors table&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;stageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Daniel Radcliffe&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="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;stageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Emma Watson&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="s1"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;stageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Rupert Grint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;movies_actors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Table containing movie-actor relationship&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Movie ID&lt;/span&gt;
      &lt;span class="na"&gt;actorIds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&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="s1"&gt;2&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="s1"&gt;3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We usually pass database connection through context, so we might update &lt;code&gt;Query.movie&lt;/code&gt; to look like&lt;br&gt;
this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolvers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;movies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// 🔄 Database access counter: (1)&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;movie&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="kc"&gt;null&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;movieName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;actors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;movies_actors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nx"&gt;actorIds&lt;/span&gt; &lt;span class="c1"&gt;// 🔄 (2)&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actorId&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;actorId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;// 🔄 (3), 🔄 (4), 🔄 (5)&lt;/span&gt;
          &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;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;This works, however, there are a few issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We are accessing the database 5 times every time &lt;code&gt;Query.movie&lt;/code&gt; runs (Counted using 🔄 emoji in the
previous code snippet). Even if the client may not request for &lt;code&gt;actors&lt;/code&gt; field, this still happens.
So, we are making unnecessary database calls. This is called &lt;strong&gt;eager resolve&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;  We are mapping &lt;code&gt;movie.movieName&lt;/code&gt; in the return statement. This is fine here, but our schema may
scale to have multiple fields returning &lt;code&gt;Movie&lt;/code&gt;, and we may have to repeat the same mapping logic
in multiple resolvers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To improve this implementation, we can use &lt;strong&gt;mappers&lt;/strong&gt; and &lt;strong&gt;defer resolve&lt;/strong&gt; to avoid unnecessary&lt;br&gt;
database calls and reduce code duplication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MovieMapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// 1.&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="na"&gt;movieName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ActorMapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="c1"&gt;// 2.&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resolvers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt; &lt;span class="p"&gt;}):&lt;/span&gt; &lt;span class="nx"&gt;MovieMapper&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;movies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;movie&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="kc"&gt;null&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt; &lt;span class="c1"&gt;// 3.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;Movie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MovieMapper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;movieName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 4.&lt;/span&gt;
    &lt;span class="na"&gt;actors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MovieMapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt; &lt;span class="p"&gt;}):&lt;/span&gt; &lt;span class="nx"&gt;ActorMapper&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;movies_actors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;actorIds&lt;/span&gt; &lt;span class="c1"&gt;// 5.&lt;/span&gt;
    &lt;span class="c1"&gt;// 6.&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;Actor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActorMapper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// 7.&lt;/span&gt;
    &lt;span class="na"&gt;stageName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ActorMapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;stageName&lt;/span&gt; &lt;span class="c1"&gt;// 8.&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;ol&gt;
&lt;li&gt; We define a &lt;code&gt;MovieMapper&lt;/code&gt; type to represent the shape of the object returned by &lt;code&gt;Query.movie&lt;/code&gt;
resolver.&lt;/li&gt;
&lt;li&gt; Similarly, we define &lt;code&gt;ActorMapper&lt;/code&gt; to be returned wherever &lt;code&gt;Actor&lt;/code&gt; type is expected. Note that in
this example, &lt;code&gt;ActorMapper&lt;/code&gt; is a &lt;code&gt;string&lt;/code&gt; representing the ID of an actor in this case, instead
of an object.&lt;/li&gt;
&lt;li&gt; The &lt;code&gt;MovieMapper&lt;/code&gt; is returned by &lt;code&gt;Query.movie&lt;/code&gt; resolver, and it becomes the &lt;code&gt;parent&lt;/code&gt; of &lt;code&gt;Movie&lt;/code&gt;
resolvers in (4) and (5).&lt;/li&gt;
&lt;li&gt; Since &lt;code&gt;MovieMapper&lt;/code&gt; has &lt;code&gt;movieName&lt;/code&gt; property, but the GraphQL type expects String scalar for
&lt;code&gt;name&lt;/code&gt; instead. So, we need to return the mapper's &lt;code&gt;movieName&lt;/code&gt; to the schema's &lt;code&gt;Movie.name&lt;/code&gt;
field.&lt;/li&gt;
&lt;li&gt; &lt;code&gt;MovieMapper&lt;/code&gt; doesn't have &lt;code&gt;actors&lt;/code&gt; property, so we must find all the related actors from the
database. Here, we expect an array of &lt;code&gt;ActorMapper&lt;/code&gt; (i.e. an array of &lt;code&gt;string&lt;/code&gt;) to be returned,
which is the &lt;code&gt;actorIds&lt;/code&gt; array in the database. This just means the &lt;code&gt;parent&lt;/code&gt; of each &lt;code&gt;Actor&lt;/code&gt;
resolver is a string in (7) and (8)&lt;/li&gt;
&lt;li&gt; We can skip implementing &lt;code&gt;Movie.id&lt;/code&gt; resolver because by default it passes &lt;code&gt;MovieMapper.id&lt;/code&gt;
property safely.&lt;/li&gt;
&lt;li&gt; Because each &lt;code&gt;ActorMapper&lt;/code&gt; is the ID of an actor, we return the &lt;code&gt;parent&lt;/code&gt; instead of &lt;code&gt;parent.id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; Similarly, we use &lt;code&gt;parent&lt;/code&gt; as the ID of the actor to fetch the actor's &lt;code&gt;stageName&lt;/code&gt; from the
database.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;br&gt;
  By using &lt;strong&gt;mappers&lt;/strong&gt; and &lt;strong&gt;defer resolve&lt;/strong&gt; techniques, we avoid unnecessary database calls and&lt;br&gt;
  reduce code duplication. The next time we need to write a resolver that returns &lt;code&gt;Movie&lt;/code&gt;, &lt;code&gt;Actor&lt;/code&gt;&lt;br&gt;
  objects, we can simply return the corresponding mapper objects.&lt;br&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing Resolvers with Mappers and Defer Resolve Best Practices
&lt;/h3&gt;

&lt;p&gt;We saw the benefits of using mappers and defer resolve in the previous section. Here are some&lt;br&gt;
TypeScript best practices to keep in mind when implementing these techniques, failing to enforce&lt;br&gt;
them may result in runtime errors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Mappers MUST be correctly typed as the return type of a resolver and the parent type of the next
resolver.&lt;/li&gt;
&lt;li&gt;  Object resolvers MUST be implemented if the expected schema field does not exist in the mapper or,
the mapper's field cannot be coerced into the expected schema type of the same name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At a small scale, it is easy to keep track of the types and mappers. However, as our schema grows,&lt;br&gt;
it becomes harder to maintain the typing and remembering which resolvers to implement. This is where&lt;br&gt;
tools like &lt;a href="https://the-guild.dev/graphql/codegen" rel="noopener noreferrer"&gt;GraphQL Code Generator&lt;/a&gt; and&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/@eddeee888/gcg-typescript-resolver-files" rel="noopener noreferrer"&gt;Server Preset&lt;/a&gt; can be used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  GraphQL Code Generator: generates TypeScript types for the resolvers, focusing on correct
nullability, array and types.&lt;/li&gt;
&lt;li&gt;  Server Preset: generates and wires up resolvers conveniently, and runs analysis to suggests
resolvers that require implementation, reducing the risk of runtime errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get started, install the required packages:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```sh npm2yarn&lt;br&gt;
npm i -D @graphql-codegen/cli &lt;a class="mentioned-user" href="https://dev.to/eddeee888"&gt;@eddeee888&lt;/a&gt;/gcg-typescript-resolver-files&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Next, create a `codegen.ts` file at the root of your project:



```ts filename="codegen.ts"
import { defineConfig } from '@eddeee888/gcg-typescript-resolver-files'
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
  schema: 'src/graphql/schema.graphql',
  generates: {
    'src/graphql': defineConfig({
      resolverGeneration: 'minimal'
    })
  }
}
export default config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then, add mappers into &lt;code&gt;schema.mappers.ts&lt;/code&gt; file, in the same directory as &lt;code&gt;schema.graphql&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```ts filename="src/graphql/schema.mappers.ts"&lt;br&gt;
type MovieMapper = {&lt;br&gt;
  id: string&lt;br&gt;
  movieName: string&lt;br&gt;
}&lt;br&gt;
type ActorMapper = string&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


&amp;lt;Callout type="info" emoji="💡"&amp;gt;
  Server Preset automatically detects and wires up mappers if they follow the convention:

  1.  The mappers are declared in a file in the same directory as the schema source file, and has the file name ending with `.mappers.ts` segment instead of the schema source file's extension. For example:
      *   If your schema file is `schema.graphql`, the mappers file is `schema.mappers.ts`.
      *   If your schema file is `schema.graphql.ts`, the mappers file is `schema.graphql.mappers.ts`.
  2.  The mapper type names are in the format of `&amp;lt;TypeName&amp;gt;Mapper` where `&amp;lt;TypeName&amp;gt;` is the GraphQL schema name. For example:
      *   If the schema type is `Movie`, then the mapper type is `MovieMapper`.
&amp;lt;/Callout&amp;gt;

Finally, run codegen to generate resolvers:



```sh npm2yarn
npm run graphql-codegen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We will see generated resolver files in &lt;code&gt;src/graphql&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```ts filename="src/graphql/resolvers/Query/movie.ts"&lt;br&gt;
import type { QueryResolvers } from './../../types.generated'&lt;/p&gt;

&lt;p&gt;export const movie: NonNullable = async (_parent, _arg, _ctx) =&amp;gt; {&lt;br&gt;
  /* Implement Query.movie resolver logic here */&lt;br&gt;
}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;




```ts filename="src/graphql/resolvers/Movie.ts"
import type { MovieResolvers } from './../types.generated'

export const Movie: MovieResolvers = {
  /* Implement Movie resolver logic here */
  actors: async (_parent, _arg, _ctx) =&amp;gt; {
    /* Movie.actors resolver is required because Movie.actors exists but MovieMapper.actors does not */
  },
  name: async (_parent, _arg, _ctx) =&amp;gt; {
    /* Movie.name resolver is required because Movie.name exists but MovieMapper.name does not */
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;```ts filename="src/graphql/resolvers/Actor.ts"&lt;br&gt;
import type { ActorResolvers } from './../types.generated'&lt;/p&gt;

&lt;p&gt;export const Actor: ActorResolvers = {&lt;br&gt;
  /* Implement Actor resolver logic here &lt;em&gt;/&lt;br&gt;
  id: async (_parent, _arg, _ctx) =&amp;gt; {&lt;br&gt;
    /&lt;/em&gt; Actor.id resolver is required because Actor.id exists but ActorMapper.id does not &lt;em&gt;/&lt;br&gt;
  },&lt;br&gt;
  stageName: async (_parent, _arg, _ctx) =&amp;gt; {&lt;br&gt;
    /&lt;/em&gt; Actor.stageName resolver is required because Actor.stageName exists but ActorMapper.stageName does not */&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


By providing mappers, codegen is smart enough to understand that we want to defer resolve, and we
need to write logic for `Movie.actors`, `Movie.name`, `Actor.id` and `Actor.stageName` resolvers to
ensure we don't encounter runtime errors.

&amp;lt;Callout type="info" emoji="💡"&amp;gt;
  Learn how to set up GraphQL Code Generator and Server Preset for GraphQL Yoga and Apollo Server in
  this guide
  [here](https://the-guild.dev/graphql/codegen/docs/guides/graphql-server-apollo-yoga-with-server-preset).
&amp;lt;/Callout&amp;gt;

## Summary

In this article, we have explored how resolvers work in a GraphQL server resolver code flow and
**resolver chain**, and how to write resolvers effectively using **mappers** and **defer resolve**
techniques. Finally, we add GraphQL Code Generator and Server Preset to automatically generate
resolvers and their types to ensure strong type-safety and reduce runtime errors.

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

&lt;/div&gt;

</description>
      <category>graphql</category>
      <category>codegen</category>
      <category>node</category>
      <category>server</category>
    </item>
    <item>
      <title>The Guild acquires Stellate</title>
      <dc:creator>TheGuildBot</dc:creator>
      <pubDate>Tue, 10 Sep 2024 14:56:06 +0000</pubDate>
      <link>https://dev.to/the-guild/the-guild-acquires-stellate-1l6j</link>
      <guid>https://dev.to/the-guild/the-guild-acquires-stellate-1l6j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was published on Tuesday, September 10, 2024 by &lt;a href="https://twitter.com/UriGoldshtein" rel="noopener noreferrer"&gt;Uri Goldshtein&lt;/a&gt; @ &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Today we are very pleased to announce that we have acquired&lt;br&gt;
&lt;a href="https://stellate.co/?utm_source=theguild&amp;amp;utm_medium=blog&amp;amp;utm_campaign=announcement" rel="noopener noreferrer"&gt;Stellate&lt;/a&gt;&lt;br&gt;
GraphQL CDN - the leading GraphQL Caching solution.&lt;/p&gt;

&lt;p&gt;The Stellate team has created an innovative platform, industry leading solution for GraphQL Caching,&lt;br&gt;
fulfilling GraphQL's full potential for caching, enabling its superiority over all REST based&lt;br&gt;
caching solutions.&lt;/p&gt;

&lt;p&gt;The Guild's &lt;a href="https://the-guild.dev/about-us" rel="noopener noreferrer"&gt;goal&lt;/a&gt; - providing an open platform with everything a&lt;br&gt;
developer needs to take GraphQL into production, fits perfectly with Stellate's superb execution.&lt;/p&gt;

&lt;p&gt;That's why acquiring Stellate and integrating it into our&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/hive" rel="noopener noreferrer"&gt;GraphQL Hive Open Platform&lt;/a&gt; makes so much sense.&lt;/p&gt;

&lt;p&gt;We've always prided ourselves on being the provider the GraphQL community can count on for the long&lt;br&gt;
term.\&lt;br&gt;
In the past, we've taken maintainership of a number of popular solutions, to give them new life and&lt;br&gt;
improve them to the be industry leading solutions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  We've &lt;a href="https://the-guild.dev/blog/graphql-tools-v6" rel="noopener noreferrer"&gt;taken ownership&lt;/a&gt; of the famous GraphQL Tools
library from Apollo - improving it for many years and recently integrating it into our
&lt;a href="https://the-guild.dev/graphql/hive/docs/gateway" rel="noopener noreferrer"&gt;Hive Gateway&lt;/a&gt; - our open source gateway that
fully supports &lt;a href="https://the-guild.dev/graphql/hive/federation" rel="noopener noreferrer"&gt;Apollo Federation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;  We've &lt;a href="https://the-guild.dev/blog/announcing-graphql-yoga-v2" rel="noopener noreferrer"&gt;taken ownership&lt;/a&gt; of GraphQL Yoga
from Prisma - making it the &lt;a href="https://the-guild.dev/graphql/yoga-server/docs/comparison" rel="noopener noreferrer"&gt;leading&lt;/a&gt;
Subgraph and GraphQL server for the JS ecosystem.&lt;/li&gt;
&lt;li&gt;  We've done the same with
&lt;a href="https://www.prisma.io/blog/the-guild-takes-over-oss-libraries-vvluy2i4uevs" rel="noopener noreferrer"&gt;many other libraries&lt;/a&gt;
and continuously support official GraphQL Foundation projects like
&lt;a href="https://graphql.org/conf/2023/sessions/e0985f6bdb4bbf07a5ca5ba72fbcc39c/" rel="noopener noreferrer"&gt;GraphiQL&lt;/a&gt;,
&lt;a href="https://github.com/graphql/graphql-http#graphql-http" rel="noopener noreferrer"&gt;GraphQL-HTTP&lt;/a&gt;,
&lt;a href="https://graphql.org/blog/2024-06-11-announcing-new-graphql-website/" rel="noopener noreferrer"&gt;GraphQL's official website&lt;/a&gt;
and many more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We offer GraphQL Hive to our users - a fully featured, complete 360˚ GraphQL platform that includes&lt;br&gt;
a schema registry, analytics platform, Federated Gateway - available either as a hosted platform or&lt;br&gt;
as a fully open-source, self-hosted solution under the&lt;br&gt;
&lt;a href="https://github.com/kamilkisiela/graphql-hive/blob/main/LICENSE" rel="noopener noreferrer"&gt;MIT license&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And now with an industry leading global GraphQL Edge Caching CDN!&lt;/p&gt;

&lt;p&gt;Like all of our other projects, this is just the start! We are looking to hear from you, where you&lt;br&gt;
wish us to take Stellate and our platform in the future.&lt;/p&gt;

&lt;p&gt;Existing Stellate users, we are here for you. Reach out directly and schedule a call with us, we&lt;br&gt;
want to learn about your current GraphQL experience and how the existing solutions can work better&lt;br&gt;
for you.&lt;/p&gt;

&lt;p&gt;To everyone else, try Stellate today,&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/hive/docs/get-started/first-steps" rel="noopener noreferrer"&gt;try Hive today&lt;/a&gt; and let us know&lt;br&gt;
what you wish the future of GraphQL to look like.&lt;/p&gt;

&lt;p&gt;See you all at &lt;a href="https://graphql.org/conf/2024/" rel="noopener noreferrer"&gt;GraphQL Conf&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>company</category>
    </item>
    <item>
      <title>Introducing GraphQL Mesh v1 and Hive Gateway v1</title>
      <dc:creator>TheGuildBot</dc:creator>
      <pubDate>Tue, 10 Sep 2024 14:26:47 +0000</pubDate>
      <link>https://dev.to/the-guild/introducing-graphql-mesh-v1-and-hive-gateway-v1-kki</link>
      <guid>https://dev.to/the-guild/introducing-graphql-mesh-v1-and-hive-gateway-v1-kki</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was published on Tuesday, September 10, 2024 by &lt;a href="https://twitter.com/ardatanrikulu" rel="noopener noreferrer"&gt;Arda Tanrikulu&lt;/a&gt; @ &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We, The Guild, are proud to announce both the Version 1 release of&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/mesh" rel="noopener noreferrer"&gt;GraphQL Mesh&lt;/a&gt; and&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/hive/docs/gateway" rel="noopener noreferrer"&gt;Hive Gateway&lt;/a&gt;, and we believe this release brings&lt;br&gt;
a new perspective to &lt;a href="https://the-guild.dev/graphql/hive/federation" rel="noopener noreferrer"&gt;GraphQL Federation&lt;/a&gt; that we&lt;br&gt;
call “Query Anything, Run Anywhere”.&lt;/p&gt;

&lt;p&gt;After several years of experience with composed APIs with early v0 versions of GraphQL Mesh and&lt;br&gt;
Schema Stitching, we have completely rebuild GraphQL Mesh from scratch for GraphQL Federation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: The previous GraphQL Mesh is now split into two complimentary projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;GraphQL Mesh&lt;/strong&gt;: Compose and Transform Datasources into a Federated GraphQL Schema. Query
anything anywhere. &lt;a href="https://the-guild.dev/graphql/mesh" rel="noopener noreferrer"&gt;Get started with GraphQL Mesh&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Hive Gateway&lt;/strong&gt;: Our Federation Gateway for that integrates with GraphQL Mesh and Schema
registries such as GraphQL Hive or Apollo Studio.
&lt;a href="https://the-guild.dev/graphql/hive/docs/gateway" rel="noopener noreferrer"&gt;Get started with Hive Gateway&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is Hive Gateway? {/* eslint-disable-line mdx/remark */}
&lt;/h2&gt;

&lt;p&gt;Hive Gateway is our fully&lt;br&gt;
&lt;a href="https://github.com/ardatan/graphql-mesh/tree/master/packages/hive-gateway" rel="noopener noreferrer"&gt;open source&lt;/a&gt; and&lt;br&gt;
&lt;a href="https://github.com/ardatan/graphql-mesh/blob/master/LICENSE" rel="noopener noreferrer"&gt;MIT&lt;/a&gt;-licensed GraphQL Gateway with&lt;br&gt;
native support for GraphQL Federation.&lt;/p&gt;

&lt;p&gt;It is designed to fully integrate with with our GraphQL Hive Platform offering, but also neatly&lt;br&gt;
integrates with other Schema Registries such as Apollo Studio.&lt;/p&gt;

&lt;p&gt;Hive Gateway is built on top of our existing and widely used open-source packages such as&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/yoga-server" rel="noopener noreferrer"&gt;GraphQL Yoga&lt;/a&gt; and&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/tools" rel="noopener noreferrer"&gt;GraphQL Tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With Hive Gateway adding these features is now a simple configuration change, &lt;strong&gt;no enterprise&lt;br&gt;
license is required&lt;/strong&gt;!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://the-guild.dev/graphql/hive/docs/gateway/subscriptions" rel="noopener noreferrer"&gt;GraphQL Subscriptions&lt;/a&gt; (via
WebSocket, SSE, or HTTP Callbacks)&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://the-guild.dev/graphql/hive/docs/gateway/usage-reporting" rel="noopener noreferrer"&gt;GraphQL API Usage and Analytics Reporting (GraphQL Hive or Apollo Studio)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://the-guild.dev/graphql/hive/docs/gateway/authorization-authentication" rel="noopener noreferrer"&gt;Authentication and Authorization (JWT)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://the-guild.dev/graphql/hive/docs/gateway/authorization-authentication#policy-directive-to-fetch-the-roles-from-a-policy-service" rel="noopener noreferrer"&gt;Role-based Access Control (RBAC)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://the-guild.dev/graphql/hive/docs/gateway/monitoring-tracing" rel="noopener noreferrer"&gt;Observability with Open Telemetry and Prometheus&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://the-guild.dev/graphql/hive/docs/gateway/other-features/performance" rel="noopener noreferrer"&gt;Caching&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://the-guild.dev/graphql/hive/docs/gateway/other-features/security/rate-limiting" rel="noopener noreferrer"&gt;Rate Limiting&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://the-guild.dev/graphql/hive/docs/gateway/persisted-documents" rel="noopener noreferrer"&gt;Persisted Documents&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://the-guild.dev/graphql/hive/docs/gateway/other-features/security/cost-limit" rel="noopener noreferrer"&gt;Query Complexity Analysis&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  And more…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We listened to the feedback of the companies using Version 0 of GraphQL Mesh, and decided that Hive&lt;br&gt;
Gateway should be as easy-to-use and be batteries-included by default. Many of our users are not as&lt;br&gt;
versed and deep within the JavaScript and npm eco-system. The new configuration is designed in a way&lt;br&gt;
to be approachable for users from all backgrounds.&lt;/p&gt;

&lt;p&gt;Getting started is easy, whether you're already using the Hive Schema Registry, Apollo GraphOS, or&lt;br&gt;
local subgraphs. With just a few lines of configuration, you'll end up with a running Gateway in no&lt;br&gt;
time.&lt;/p&gt;

&lt;h3&gt;
  
  
  How well does Hive Gateway support GraphQL Federation? {/* eslint-disable-line mdx/remark */}
&lt;/h3&gt;

&lt;p&gt;We put in a lot of effort over the last year into having a Federation compatibility test suite. We&lt;br&gt;
rebuilt our Federation Query Planner and Execution Engine completely from scratch from these&lt;br&gt;
learnings and now open-sources the test suite so other Apollo Federation Gateways can too benefit&lt;br&gt;
from our research as well. It already helped to discover and report some regressions in Apollo&lt;br&gt;
Router to the Apollo Team. We hope that this test suite will overall enhance the quality of all the&lt;br&gt;
GraphQL gateways on the market.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I have to use the Hive Registry? {/* eslint-disable-line mdx/remark */}
&lt;/h3&gt;

&lt;p&gt;No. You can gradually migrate to the Hive platform if desired. If you want to use your existing&lt;br&gt;
schema registry (e.g. GraphOS), Hive Gateway supports these registries as well. You don't have to&lt;br&gt;
migrate to the Hive Platform if you are just looking for a replacement to Apollo Router or Apollo&lt;br&gt;
Gateway.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy and Run Anywhere {/* eslint-disable-line mdx/remark */}
&lt;/h3&gt;

&lt;p&gt;Hive Gateway can run anywhere. No need to mess with JavaScript and Node.js. You can choose your&lt;br&gt;
preferred way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Single Executable Binary&lt;/li&gt;
&lt;li&gt;  Docker Image&lt;/li&gt;
&lt;li&gt;  NPM package&lt;/li&gt;
&lt;li&gt;  If you are a JavaScript Tinkerer

&lt;ul&gt;
&lt;li&gt;  Node.js, Bun, or Deno&lt;/li&gt;
&lt;li&gt;  Cloudflare Workers, AWS Lambda, Azure Functions and Google Cloud Functions.&lt;/li&gt;
&lt;li&gt;  Integrate with your existing server framework such as Express, Fastify, Hapi and Koa.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  What about GraphQL Mesh? {/* eslint-disable-line mdx/remark */}
&lt;/h2&gt;

&lt;p&gt;Previously what is now known as Hive Gateway has been one of the many building block of GraphQL&lt;br&gt;
Mesh. The other significant building block of GraphQL Mesh is the possibility to convert and compose&lt;br&gt;
any amount of APIs such as REST/OpenAPI, SOAP, gRPC or even a database like MySQL into a single&lt;br&gt;
unified GraphQL API, while applying a wide range of transforms e.g. for renaming or filtering the&lt;br&gt;
output API types.&lt;/p&gt;

&lt;p&gt;A lot of our clients have been using this approach to transform legacy APIs and all kind of other&lt;br&gt;
sources for many years with great success.&lt;/p&gt;

&lt;p&gt;From now on, GraphQL Mesh now only focuses only on composing datasources into a single annotated&lt;br&gt;
GraphQL/Supergraph SDL file that is 100% compatible with Apollo Federation.&lt;/p&gt;

&lt;p&gt;Serving the composed GraphQL schema is now a concern of Hive Gateway, which seamlessly integrates&lt;br&gt;
with GraphQL Mesh.&lt;/p&gt;

&lt;p&gt;All of the features introduced in GraphQL Mesh v0 remain unchanged. However, GraphQL Mesh now builds&lt;br&gt;
on top of the Apollo Federation specification. That means you do all the conversion, generation and&lt;br&gt;
stitching process at build time once, and then you generate a supergraph or subgraph SDL that can be&lt;br&gt;
consumed by any&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/hive/federation-gateway-audit" rel="noopener noreferrer"&gt;Apollo Federation compatible gateway&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To summarize, GraphQL Mesh is a framework that allows you to convert any API (REST, SOAP etc) into&lt;br&gt;
the Apollo Federation subgraph to be consumed by a gateway. For the best experience, we recommend&lt;br&gt;
using GraphQL Hive Gateway.&lt;/p&gt;

&lt;p&gt;💡 GraphQL Mesh extends Apollo Federation to consume OpenAPI, SOAP and other non GraphQL sources, and also transform them by renaming fields and so on.&lt;br&gt;
  Of course within the boundaries of Apollo Federation specification!&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I migrate to v1? {/* eslint-disable-line mdx/remark */}
&lt;/h3&gt;

&lt;p&gt;While GraphQL Mesh v1 introduces several breaking changes, the core functionality remain the same as&lt;br&gt;
in v0. All transforms, plugins, and other features are still available through the combination of&lt;br&gt;
GraphQL Mesh and Hive Gateway. Simply follow our migration guides to make the transition. And as&lt;br&gt;
always, feel free to reach out to us directly for assistance.&lt;/p&gt;

&lt;p&gt;However, there's no need to rush your migration — we will continue to maintain v0 for the&lt;br&gt;
foreseeable future.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the relationship between GraphQL Mesh and Hive Gateway? {/* eslint-disable-line mdx/remark */}
&lt;/h3&gt;

&lt;p&gt;GraphQL Mesh generates a GraphQL Federation subgraph from a non GraphQL source (OpenAPI, SOAP, gRPC&lt;br&gt;
etc) and/or a GraphQL API that doesn't have federation metadata. Then you can either compose that&lt;br&gt;
subgraph with Mesh, or publish it to the schema registry, or compose it using other tools like&lt;br&gt;
Apollo Rover to get a Federation Supergraph. Then this generated supergraph is consumed by a GraphQL&lt;br&gt;
Gateway like Hive Gateway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query Anything, Run Anywhere
&lt;/h2&gt;

&lt;p&gt;As our initial motto from the earlier stages of GraphQL Mesh. We still follow it.&lt;/p&gt;

&lt;p&gt;This time we combined this idea with Apollo Federation. GraphQL Mesh now federates non GraphQL and&lt;br&gt;
GraphQL sources on top of the official Apollo Federation specification.&lt;/p&gt;

&lt;p&gt;Hive Gateway is there to orchestrate calls to those APIs and serve the responses to the client. You&lt;br&gt;
can use them together or take one of them and use with other alternatives.&lt;/p&gt;

&lt;p&gt;Both are free, open-source, MIT-licensed, without the need to pay extra for enterprise grade&lt;br&gt;
features.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://the-guild.dev/graphql/hive/docs/gateway" rel="noopener noreferrer"&gt;Learn more about Hive Gateway&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://the-guild.dev/graphql/mesh" rel="noopener noreferrer"&gt;Learn more about GraphQL Mesh&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>graphql</category>
      <category>mesh</category>
      <category>graphqlhive</category>
    </item>
    <item>
      <title>Audit of GraphQL Gateways Supporting Apollo Federation</title>
      <dc:creator>TheGuildBot</dc:creator>
      <pubDate>Tue, 10 Sep 2024 14:26:16 +0000</pubDate>
      <link>https://dev.to/the-guild/audit-of-graphql-gateways-supporting-apollo-federation-19pn</link>
      <guid>https://dev.to/the-guild/audit-of-graphql-gateways-supporting-apollo-federation-19pn</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was published on Tuesday, September 10, 2024 by &lt;a href="https://twitter.com/kamilkisiela" rel="noopener noreferrer"&gt;Kamil Kisiela&lt;/a&gt; @ &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Apollo Federation spec is a hot topic, we must admit. The adoption of it keeps increasing,&lt;br&gt;
especially over past two years. There's a reason! It's a fantastic piece of technology, but also a&lt;br&gt;
complex piece of tech.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're curious about the results,&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/hive/federation-gateway-audit" rel="noopener noreferrer"&gt;visit the audit page&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Complexity Is Not Obvious{/* eslint-disable-line mdx/remark */}
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;As a user&lt;/strong&gt; of Apollo Federation, you might not see the full spectrum of&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/hive/federation" rel="noopener noreferrer"&gt;Apollo Federation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When building subgraphs, you might occasionally encounter composition errors, but ultimately,&lt;br&gt;
everything works and you query data. The real complexity lies in tooling, starting with the&lt;br&gt;
composition library, and ending on the gateway and it's query planning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As maintainers&lt;/strong&gt; of &lt;a href="https://the-guild.dev/graphql/hive/docs/gateway" rel="noopener noreferrer"&gt;Hive Gateway&lt;/a&gt;&lt;br&gt;
(&lt;a href="https://dev.to/blog/graphql-mesh-v1-hive-gateway-v1"&gt;previously part of GraphQL Mesh&lt;/a&gt;) and creators of GraphQL&lt;br&gt;
Hive (our Schema Registry for GraphQL Federation), we've seen a wide range of supergraphs. Over the&lt;br&gt;
past few years, we've been working with companies adopting or already using Apollo Federation in&lt;br&gt;
production.&lt;/p&gt;

&lt;p&gt;We learned something, actually quite a lot!&lt;/p&gt;

&lt;p&gt;Today, we're even collaborating with creators of Apollo Federation and the&lt;br&gt;
&lt;a href="https://chillicream.com/" rel="noopener noreferrer"&gt;ChilliCream&lt;/a&gt; teams (who built&lt;br&gt;
&lt;a href="https://chillicream.com/blog/2023/08/15/graphql-fusion/" rel="noopener noreferrer"&gt;GraphQL Fusion&lt;/a&gt;) on&lt;br&gt;
&lt;a href="https://graphql.org/blog/2024-05-16-composite-schemas-announcement/" rel="noopener noreferrer"&gt;the new specification for federated GraphQL APIs&lt;/a&gt;,&lt;br&gt;
as proud members of GraphQL Foundation.&lt;/p&gt;

&lt;p&gt;We've seen Apollo Federation's complexity, we understood the rules of it very well, and we have&lt;br&gt;
something incredibly interesting to share!&lt;/p&gt;

&lt;p&gt;Before we get to that, let's first discuss what does it mean to "support Apollo Federation" on a&lt;br&gt;
gateway.&lt;/p&gt;
&lt;h2&gt;
  
  
  What Does "Apollo Federation Support" Really Mean?{/* eslint-disable-line mdx/remark */}
&lt;/h2&gt;

&lt;p&gt;As you know, the spec contains a lot of directives, and these can be used in various ways, resulting&lt;br&gt;
in &lt;strong&gt;many&lt;/strong&gt; combinations. Sometimes weird at first glance, but when you really think about them,&lt;br&gt;
they make sense.&lt;/p&gt;

&lt;p&gt;In a lot of cases, the spec is abused, but hey… what's allowed, has to work!&lt;/p&gt;

&lt;p&gt;Most of the time you will see “Apollo Federation support” phrase or a list of supported directives,&lt;br&gt;
and this is fine, but it tells only a part of the story.&lt;/p&gt;

&lt;p&gt;If a gateway supports the &lt;code&gt;@key&lt;/code&gt; directive, it may or may not support it on an Interface type, for&lt;br&gt;
example. You simply don't know until you try it!&lt;/p&gt;

&lt;p&gt;Did you know that in Apollo Federation v1, a field that is annotated with &lt;code&gt;@external&lt;/code&gt;, that is also&lt;br&gt;
part of key fields, and is not defined anywhere else, is still resolvable?&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;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="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;key&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="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&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="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;key&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="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;upc&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="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="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;external&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="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;external&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;upc&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="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;external&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;price&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="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;Not everyone knows that key fields of extension types in Federation v1, must be annotated with&lt;br&gt;
@external , and these are still resolvable by the subgraph. That's why we built the audit!&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Here's how the auditing tool looks like. It's a simple CLI and we're going to release it on NPM&lt;br&gt;
and as a binary soon. As of today, you need to clone the repository.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Apollo Federation Audit!{/* eslint-disable-line mdx/remark */}
&lt;/h2&gt;

&lt;p&gt;As you know, The Guild has open source nature in its core. What we do we share, we open source, we&lt;br&gt;
give away for free. It was always like that, it won't ever change.&lt;/p&gt;

&lt;p&gt;Over the years we encountered a lot of aspects of Apollo Federation when working on query planning&lt;br&gt;
for Hive Gateway (previously GraphQL Mesh, just a reminder that it's not a new project, but rather&lt;br&gt;
well established).&lt;/p&gt;

&lt;p&gt;We spent quite a few months, writing down our knowledge about Apollo Federation, in form of 40&lt;br&gt;
supergraphs, covering wide range, if not all, of the spec.&lt;/p&gt;

&lt;p&gt;Each of those supergraphs, have a set of subgraphs running as real GraphQL APIs, with real runtime&lt;br&gt;
and real data.&lt;/p&gt;

&lt;p&gt;We have created 170 tests in total so far…&lt;/p&gt;

&lt;p&gt;All that effort to measure how compatible our gateway is with Apollo Federation... and now we give&lt;br&gt;
it away to everyone, even our “competitors”, for free, no strings attached!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We never had a tool to measure gateway's compatibility with Apollo Federation, but now we have one&lt;br&gt;
— and we've put it to the test!&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Visit the audit page and see the results:&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/hive/federation-gateway-audit" rel="noopener noreferrer"&gt;https://the-guild.dev/graphql/hive/federation-gateway-audit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main reason behind building such tool, was to improve our Hive Gateway, have a set of tests we&lt;br&gt;
can use for various of ways. We were also curious how well the rest of the GraphQL gateways perform,&lt;br&gt;
how compatible they are, how good their query planning understands Apollo Federation. The results&lt;br&gt;
are interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the Audit{/* eslint-disable-line mdx/remark */}
&lt;/h2&gt;

&lt;p&gt;The existing GraphQL Gateway benchmarks focus on performance, pure speed, query planning overhead&lt;br&gt;
and related factors. You only care about performance, if the gateway can query data correctly. Who&lt;br&gt;
wants a fast, but partially broken gateway? All the gateway implementors knows that, and they work&lt;br&gt;
hard to improve their gateway every day.&lt;/p&gt;

&lt;p&gt;We wanted to push the community forward, by giving them a chance to make a giant jump.&lt;/p&gt;

&lt;p&gt;That's why the auditing tool is fully open-source (MIT license), and available for everyone.&lt;/p&gt;

&lt;p&gt;Visit the repository:&lt;br&gt;
&lt;a href="https://github.com/the-guild-org/graphql-federation-gateway-audit" rel="noopener noreferrer"&gt;https://github.com/the-guild-org/graphql-federation-gateway-audit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We want to turn our effort into helping potential users of GraphQL gateways to better understand&lt;br&gt;
what Apollo Federation support means, but also the maintainers of those gateways to improve their&lt;br&gt;
score and learn from our experience.&lt;/p&gt;

&lt;p&gt;We aim to make it a shared effort, an "official" auditing tool for Apollo Federation gateways.&lt;/p&gt;

</description>
      <category>graphql</category>
    </item>
    <item>
      <title>Building Type-Safe Random GIF Generator with feTS</title>
      <dc:creator>TheGuildBot</dc:creator>
      <pubDate>Thu, 02 May 2024 13:14:39 +0000</pubDate>
      <link>https://dev.to/the-guild/building-type-safe-random-gif-generator-with-fets-1ekl</link>
      <guid>https://dev.to/the-guild/building-type-safe-random-gif-generator-with-fets-1ekl</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was published on Thursday, May 2, 2024 by &lt;a href="https://twitter.com/SimhaTuval" rel="noopener noreferrer"&gt;Tuval Simha&lt;/a&gt; @ &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Embarking on my journey as a developer, I sought a project that would not only be educational but&lt;br&gt;
also enjoyable. As a junior developer, I encountered the challenges of working with REST APIs,&lt;br&gt;
particularly the lack of type safety. This led me to explore feTS, a tool designed to simplify REST&lt;br&gt;
API development, offering type safety, efficiency, and seamless integration with TypeScript and&lt;br&gt;
OpenAPI.&lt;/p&gt;
&lt;h2&gt;
  
  
  Exploring feTS: Elevating Type Safety in REST API Development
&lt;/h2&gt;

&lt;p&gt;feTS, derived from 'Fetch' and 'TypeScript,' emerged as a game-changer in the realm of REST APIs. By&lt;br&gt;
leveraging TypeScript and the OpenAPI specification, feTS ensures clarity in data exchange between&lt;br&gt;
the client and server, significantly reducing errors during development. This blog post delves into&lt;br&gt;
a practical example – building a Random Gif Generator – to showcase how feTS transforms the&lt;br&gt;
development experience.&lt;/p&gt;
&lt;h2&gt;
  
  
  Building a Random Gif Generator
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 1: Getting Started with Giphy API
&lt;/h3&gt;

&lt;p&gt;To demonstrate the power of feTS, let's create a Random Gif Generator using the Giphy API. Begin by&lt;br&gt;
obtaining a free API key from the Giphy developer portal here.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Integrating OpenAPI Definitions into TypeScript
&lt;/h3&gt;

&lt;p&gt;Incorporate the Giphy API's OpenAPI definitions into a TypeScript file, exporting them with the as&lt;br&gt;
const modifier for strong typing. This integration ensures seamless cooperation with feTS. You can&lt;br&gt;
find the Giphy OpenAPI definitions here.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3: Installing feTS and Creating a Client
&lt;/h3&gt;

&lt;p&gt;Install feTS using your preferred package manager and create a client using the createClient&lt;br&gt;
function. The client instantiation involves providing the normalized OpenAPI types and specifying&lt;br&gt;
the Giphy API endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NormalizeOAS&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;feTS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;openAPIDoc&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./openapi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;NormalizeOAS&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;openAPIDoc&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.giphy.com/v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;
  You can find the complete OpenAPI definitions for the Giphy API&lt;br&gt;
  &lt;a href="https://api.apis.guru/v2/specs/giphy.com/1.0/openapi.json" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Building Endpoints with feTS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchRandomGif&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/gifs/random&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_API_KEY_HERE&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gifData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;gifData&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Utilizing the Gif Data
&lt;/h3&gt;

&lt;p&gt;Now, you can easily use the fetchRandomGif function in your application to obtain random gif data.&lt;br&gt;
Leverage the type safety provided by feTS to ensure accurate handling of the API response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useQuery&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-query&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;fetchRandomGif&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./feTS/endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;randomGif&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fetchRandomGif&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isLoading&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Loading&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;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;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;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Random Gif&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&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;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Advantages of feTS in Gif Generator Development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Clarity in Development
&lt;/h3&gt;

&lt;p&gt;feTS simplifies endpoint definitions, making API navigation clear and straightforward. The&lt;br&gt;
structured interface enhances collaboration and understanding among developers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthe-guild.dev%2Fblog-assets%2Fbuilding-random-gif-generator-with-fets-and-giphy%2Fauto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthe-guild.dev%2Fblog-assets%2Fbuilding-random-gif-generator-with-fets-and-giphy%2Fauto.png" alt="Autocomplate"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Speedy Implementation
&lt;/h3&gt;

&lt;p&gt;With feTS, manual response parsing becomes a thing of the past. Auto-generated API clients and&lt;br&gt;
TypeScript types accelerate the development process.&lt;/p&gt;
&lt;h3&gt;
  
  
  Type Safety at Its Best
&lt;/h3&gt;

&lt;p&gt;Enjoy robust type safety throughout the development cycle. feTS catches potential issues at compile&lt;br&gt;
time, ensuring a reliable and error-free application.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion: Elevating Gif Generator Development with feTS
&lt;/h2&gt;

&lt;p&gt;Building a Random Gif Generator using feTS exemplifies the tool's prowess in enhancing type safety,&lt;br&gt;
clarity, and efficiency in REST API development. By adopting feTS, developers can create&lt;br&gt;
applications with confidence, focusing on features rather than worrying about type-related&lt;br&gt;
challenges.&lt;/p&gt;


  ![Demo](https://the-guild.dev/blog-assets/building-random-gif-generator-with-fets-and-giphy/gif.gif)


&lt;p&gt;As you embark on your journey with feTS, remember that it's not just a tool; it's a paradigm shift&lt;br&gt;
towards seamless and elevated REST API development. Happy coding!&lt;/p&gt;

&lt;p&gt;&lt;br&gt;
  The full code for this Random GIF Generator example is available on&lt;br&gt;
  &lt;a href="https://github.com/TuvalSimha" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, and live demo can be found&lt;br&gt;
  &lt;a href="https://fets-giphy-app.vercel.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

</description>
      <category>fets</category>
    </item>
    <item>
      <title>GraphQL Request Cancellation in JavaScript</title>
      <dc:creator>TheGuildBot</dc:creator>
      <pubDate>Mon, 29 Apr 2024 07:33:49 +0000</pubDate>
      <link>https://dev.to/the-guild/graphql-request-cancellation-in-javascript-13eo</link>
      <guid>https://dev.to/the-guild/graphql-request-cancellation-in-javascript-13eo</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was published on Monday, April 29, 2024 by &lt;a href="https://twitter.com/n1rual" rel="noopener noreferrer"&gt;Laurin Quast&lt;/a&gt; @ &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Canceling in-flight requests in an application if a user navigates away from a view has become a&lt;br&gt;
standard in modern applications. GraphQL client libraries such as Apollo Client and urql support&lt;br&gt;
this by default. But is it also possible to cancel ongoing logic on the server if the client stops&lt;br&gt;
the request?&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;AbortController&lt;/code&gt; and &lt;code&gt;fetch&lt;/code&gt; on the Client {/* eslint-disable-line mdx/remark */}
&lt;/h2&gt;

&lt;p&gt;After the introduction of the&lt;br&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API" rel="noopener noreferrer"&gt;&lt;code&gt;fetch&lt;/code&gt; API&lt;/a&gt;, sometime later we also&lt;br&gt;
got the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/AbortController" rel="noopener noreferrer"&gt;&lt;code&gt;AbortController&lt;/code&gt; API&lt;/a&gt;.&lt;br&gt;
These both in combination made HTTP request cancellation logic straightforward.&lt;/p&gt;

&lt;p&gt;In the following React code snippet, we implement a React hook that uses fetch for fetching some&lt;br&gt;
data using the &lt;code&gt;useEffect&lt;/code&gt; hook. The &lt;code&gt;fetch&lt;/code&gt; call receives the &lt;code&gt;AbortSignal&lt;/code&gt; from an&lt;br&gt;
&lt;code&gt;AbortController&lt;/code&gt; . Within the cleanup function returned from &lt;code&gt;useEffect&lt;/code&gt;, that is invoked when the&lt;br&gt;
component containing this hook unmounts, the request is aborted via the call of the &lt;code&gt;abort&lt;/code&gt; method&lt;br&gt;
on the &lt;code&gt;AbortController&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```tsx filename="React AbortController example"&lt;br&gt;
function useProfileData() {&lt;br&gt;
  const [state, setState] = useState()&lt;/p&gt;

&lt;p&gt;useEffect(() =&amp;gt; {&lt;br&gt;
    const controller = new AbortController()&lt;br&gt;
    async function fetchData() {&lt;br&gt;
      const response = await fetch('/graphql', {&lt;br&gt;
        method: 'POST',&lt;br&gt;
        body: JSON.stringify({ query: '{ me { id  name } }' }),&lt;br&gt;
        headers: { 'Content-Type': 'application/json' },&lt;br&gt;
        signal: controller.signal&lt;br&gt;
      })&lt;br&gt;
      const data = await response.json()&lt;br&gt;
      setState(data)&lt;br&gt;
    }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetchData().catch(err =&amp;gt; console.log(err))
return function onUnmount() {
  controller.abort()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}, [])&lt;/p&gt;

&lt;p&gt;return state&lt;br&gt;
}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


When checking the network tab within the browser, we can see that the request was canceled.

&amp;lt;Callout&amp;gt;
  **Note:** When a pending fetch request is canceled, the Promise returned from the fetch call will
  reject with a [`DOMException`](https://developer.mozilla.org/en-US/docs/Web/API/DOMException)\`. It
  is recommended to always add a catch handler for your fetch calls to avoid unhandled promise
  rejections.
&amp;lt;/Callout&amp;gt;

All modern GraphQL clients use this under the hood for optimizing the user experience, as it is
unnecessary to load data that is no longer needed, e.g. because the user navigated away to another
view. This is especially true for devices where low data/roaming usage is desired.

## Isomorphic APIs

One of the great things about JavaScript is that APIs that were formerly exclusive to browser
environments are finally being added to various server-side runtimes. Whether Bun.js, Deno or
Node.js, all of them support both the `fetch` and `AbortController` API in recent versions!

| Runtime | fetch              | AbortController    |
| ------- | ------------------ | ------------------ |
| Node.js | ✅ (since v18.0.0) | ✅ (since v15.4.0) |
| Deno    | ✅ (since v1.0.0)  | ✅ (since v1.0.0)  |
| Bun     | ✅ (since v1.0.0)  | ✅ (since v1.0.0)  |

This enables us to run the exact same code from the client example on our server.

In addition to `AbortController` now being able on the server, all kind of libraries that do
asynchronous tasks such as IO, can similarly to the `fetch` API accept an `AbortSignal` option for
canceling any pending work in case the calling code is no longer interested in the result. An
example of this could be that a request from the client has been canceled and the server no longer
needs to load all the data and construct a response as requested previously.

## Cleaning up Resources and Pending Tasks Is Hard

While this is not particularly true for all programming languages, JavaScript servers are by default
single-threaded and no new thread or worker process is spawned for every incoming HTTP request.
Thus, we can not simply kill a thread or worker process that is performing some work in case the
request got aborted.

Because of that, cleaning up resources and canceling pending tasks is a cumbersome task that is left
to the user instead of being performed through magic.

On top of that a lot of tooling and libraries, yet need to catch up and provide the APIs (e.g. pass
`AbortSignal`) to allow cleaning up resources.

Some examples (on the server in case of an aborted client request):

*   Abort a non-transactional, expensive, and long-running SQL query (or query/read on any other
    database)
*   Abort pending HTTP requests to third-party services for fetching some data
*   Abort the GraphQL execution and stop the resolver waterfall calls for resolving all the data
    specified by the GraphQL operation sent by the client

The latter point is a superset of the two former points, as in most cases within the GraphQL
execution, the business logic as called within or specified in your resolvers will result in a
variation of reads from remote services or databases.

A good enough solution for many people could be to only have the latter and only further optimize
for the former two points when additional performance gains are justified.

## How GraphQL Execution Cancelation Works

When a GraphQL operation is sent to the server, the server will start executing the operation by
calling the resolver functions as specified by the GraphQL operation selection set. Some resolver
functions are light and will just read a property from an object, whereas others will call a remote
service or database.

Here is an example GraphQL operation causing the server to call several services in sequence.

```graphql filename="Example GraphQL Operation"
query Profile($userId: ID!) {
  user(id: $userId) {
    id
    name
    avatar {
      id
      url
    }
    posts(first: 10) {
      edges {
        node {
          id
          title
          body
          likeCount
          comments(first: 5) {
            edges {
              node {
                id
                body
                author {
                  id
                  name
                  avatar {
                    id
                    url
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
```

Here is a simplified view of what kind of operations will be performed as the resolvers are called.
The arrows indicate what action and resolver will be executed after another one has finished. For
simplification, we only show the resolvers that are performing IO operations.

```mermaid
flowchart
  id1["Load user (Query.user)"]
  id21["Load user avatar (User.avatar)"]
  id22["Load user posts (User.posts)"]
  id31["Load total post likes (Post.likeCount)"]
  id32["Load comments for each post (Post.comments)"]
  id4["Load author for each comments (Comment.author)"]
  id5["Load author avataer for each comment author (User.avatar)"]

  id1 --&amp;gt; id21
  id1 --&amp;gt; id22
  id22 --&amp;gt; id31
  id22 --&amp;gt; id32
  id32 --&amp;gt; id4
  id4 --&amp;gt; id5
```

So given the above operation, if the client cancels the request at the stage
`Load user posts (User.posts)`, there is no need for the server to perform all the resolver calls
and data-fetching happening after that point. Furthermore, event the pending
`Load user posts (User.posts)` call could be canceled.

```mermaid
flowchart
  id1["Load user (Query.user)"]
  id21["Load user avatar (User.avatar)"]
  id22["Load user posts (User.posts)"]
  id31["Load total post likes (Post.likeCount)"]
  id32["Load comments for each post (Post.comments)"]
  id4["Load author for each comments (Comment.author)"]
  id5["Load author avataer for each comment author (User.avatar)"]

  id1 --&amp;gt; id21
  id1 --&amp;gt; id22
  id22 -- client request cancel --&amp;gt; id31
  id22 -- client request cancel --&amp;gt; id32
  id32 --&amp;gt; id4
  id4 --&amp;gt; id5

  classDef opacity opacity:0.5
  class id31,id32,id4,id5 opacity
  linkStyle 2 opacity:0.5;
  linkStyle 3 opacity:0.5;
  linkStyle 4 opacity:0.5;
  linkStyle 5 opacity:0.5;
```

## Why We Forked GraphQL.js

GraphQL.js is the reference implementation of the GraphQL specification. GraphQL.js is also the
GraphQL engine that is used by almost all JavaScript GraphQL servers that exist today.

The reference implementation serves as a proofing ground for new features (e.g. the `@stream` and
`@defer` directives). However, there is one major drawback with GraphQL.js. Things generally move
slow and the process of testing new features and provide feedback is cumbersome as you will have to
maintain your own fork. If you want to test out multiple newly proposed features at the same time,
it gets even more complicated. We wanted to take that burden from GraphQL server builders!

When we revived Yoga Server, we wanted to make in-progress “GraphQL specification” features easily
accessible. That is why we forked GraphQL.js and now maintain this fork, where new features can be
enabled via flags.

This also allowed us to add support for passing `AbortSignal` for the GraphQL execution, which
allows canceling the GraphQL data resolving waterfall in case the incoming request got canceled.

## How to Enable GraphQL Execution Cancelation in GraphQL Yoga

Execution cancellation is not yet a feature that is enabled by default as we are still gathering
intel on its behavior in a real-world environment (on our [Hive](https://the-guild.dev/graphql/hive)
GraphQL API).

For now, opting into this feature is achieved via a plugin.

```ts filename="GraphQL Yoga cancelation plugin"
import { createYoga, useExecutionCancellation } from 'graphql-yoga'
import { schema } from './schema'

// Provide your schema
const yoga = createYoga({
  plugins: [useExecutionCancellation()],
  schema
})

// Start the server and explore http://localhost:4000/graphql
const server = createServer(yoga)
server.listen(4000, () =&amp;gt; {
  console.info('Server is running on http://localhost:4000/graphql')
})
```

After that, you should immediately benefit from GraphQL execution cancellation without having to do
any further optimizations.

Depending on whether you are performing other advanced GraphQL optimizations such as data-fetching
lookaheads or similar, you might also want to implement `AbortSignal` propagating in those API
surfaces. For that, we recommend reading the
[Yoga documentation on GraphQL execution cancellation](https://the-guild.dev/graphql/yoga-server/docs/features/execution-cancellation).

## Conclusion

HTTP request and database read cancelations are powerful tools that can be handy when encountering
performance problems for often aborted paths.

Similarly, aborting the GraphQL execution can potentially free up a lot of resources otherwise
wasted for fetching data and constructing a response that is no longer needed.

Writing cancelation logic for HTTP requests and database read cancelation can be cumbersome, but
implemented via an abstraction layer if needed.

Yoga server is a powerful JavaScript runtime agnostic GraphQL Server that supports GraphQL execution
cancellation.
[You can learn more here](https://the-guild.dev/graphql/yoga-server/docs/features/execution-cancellation).

If you are facing related or other issues with GraphQL APIs, feel free to reach out! We offer a wide
range of services and are experts in building and maintaining GraphQL API tooling.

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

&lt;/div&gt;

</description>
      <category>graphql</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>The Guild - Rebranding in open source</title>
      <dc:creator>TheGuildBot</dc:creator>
      <pubDate>Sat, 24 Feb 2024 14:30:30 +0000</pubDate>
      <link>https://dev.to/the-guild/the-guild-rebranding-in-open-source-4mg1</link>
      <guid>https://dev.to/the-guild/the-guild-rebranding-in-open-source-4mg1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was published on Saturday, February 24, 2024 by &lt;a href="https://twitter.com/UriGoldshtein" rel="noopener noreferrer"&gt;Uri Goldshtein&lt;/a&gt; @ &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  The Guild never had a marketing, design or branding function&lt;/li&gt;
&lt;li&gt;  As we see our tools as best of breed in any category we work in, we want to get more exposure to
it on our ecosystem&lt;/li&gt;
&lt;li&gt;  We've also want more open source developers to know you can create open source businesses in a
sustainable way, like we have successfully managed to do&lt;/li&gt;
&lt;li&gt;  We've decided its time for The Guild to go through a professional process of branding and
marketing&lt;/li&gt;
&lt;li&gt;  We've hired experts to help us in that process - &lt;a href="https://www.northstar.cx" rel="noopener noreferrer"&gt;North Star&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  Like everything we do at The Guild - we've decided to take the whole process open source and share
with our community everything in the process, including our wins and painful points&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Guild Today
&lt;/h2&gt;

&lt;p&gt;We are a group of developers, creating open source, developer experience and infrastructure tools&lt;br&gt;
for managing data and APIs.&lt;/p&gt;

&lt;p&gt;We've managed to create industry leading tools, that are fully open source, while still being very&lt;br&gt;
profitable with solid financials that makes us resilient for the future.&lt;/p&gt;

&lt;p&gt;The whole structure of the group was to make sure we can create tools everyone can rely on for the&lt;br&gt;
very long term.&lt;/p&gt;

&lt;p&gt;We've also managed to become a really interesting place for ambitious developers to work in - all of&lt;br&gt;
our libraries are under developer's names and not under The Guild's org, in order to give the&lt;br&gt;
developers the fully power and credit they deserve.&lt;/p&gt;

&lt;p&gt;Building on all of these foundations together, we believe we've managed to create a strong ground&lt;br&gt;
for building quality software and we want to inspire others to create long term, quality software&lt;br&gt;
instead of short term, trend and marketing based software foundations.&lt;/p&gt;

&lt;p&gt;We've had a unique vision and a way to achieve it and we've managed to be successful at it.&lt;/p&gt;

&lt;p&gt;At this stage, we feel that more people should be aware of what we do.&lt;/p&gt;

&lt;p&gt;Some as users of our tools and some as other open source developers and solution providers, to share&lt;br&gt;
our tools and learnings with the wider community.&lt;/p&gt;

&lt;p&gt;We have never done any marketing and we think this is a good time to start - At this stage,&lt;br&gt;
marketing to us is a force for bringing awareness to ideas we believe in&lt;/p&gt;

&lt;h2&gt;
  
  
  Where We Want to Be, Our Goals from the Process
&lt;/h2&gt;

&lt;p&gt;As we go through the process, we have to ask ourselves what do we actually want to get.&lt;/p&gt;

&lt;p&gt;Our current goals as we see them today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Clear offering:&lt;/strong&gt; We offer many products, spread across many places across the stack. It is
currently very hard for someone new to The Guild's ecosystem to understand what each tool does and
how it could benefit them&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This might seem slightly confusing...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Philosophy of development:&lt;/strong&gt; We've managed to create a philosophy around how we work, in order
to create sustainable, reliable, quality open source infrastructure. We want to share these ideas
with our users and other open source developers&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Hiring:&lt;/strong&gt; We want to give ambitious open source developers a career path that they are not
currently getting in other companies. Maximizing their individual potential is the core reason of
why we've created The Guild in the first place. We want to let developers know that The Guild is
more than a GraphQL provider and it's also more than an API provider — it's the open source
company, structured around the most solid solutions in open source that could be relied upon by
users and tool builders - &lt;strong&gt;More exposure:&lt;/strong&gt; More developers to be aware of the available products
we offer and why they are the best in the industry (if they are not, we want to understand why as
part of that process, we want to share that as well in public). That includes the GraphQL
ecosystem but also the wider API ecosystem&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Process
&lt;/h2&gt;

&lt;p&gt;Here is the process we'll go through, led by &lt;a href="https://www.northstar.cx" rel="noopener noreferrer"&gt;North Star&lt;/a&gt; (they've also&lt;br&gt;
wrote about the process&lt;br&gt;
&lt;a href="https://www.northstar.cx/blog-detail/the-guild-in-the-wind-of-change-open-source-rebranding-in-public" rel="noopener noreferrer"&gt;here&lt;/a&gt;):&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1oz8amp1xyr4qh7aovql.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1oz8amp1xyr4qh7aovql.png" alt="process" width="800" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  First Phase — Brand Audit
&lt;/h3&gt;

&lt;p&gt;During that process, &lt;a href="https://www.northstar.cx" rel="noopener noreferrer"&gt;North Star&lt;/a&gt; will analyse the current state of The&lt;br&gt;
Guild&lt;/p&gt;

&lt;p&gt;They will learn about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  How we communicate&lt;/li&gt;
&lt;li&gt;  Our current brand and identity&lt;/li&gt;
&lt;li&gt;  Our value propositions&lt;/li&gt;
&lt;li&gt;  The overall ecosystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will share the full analysis results with the community.&lt;/p&gt;

&lt;p&gt;We believe this would be helpful as we could get feedback from all of you about the results and if&lt;br&gt;
we got it right.&lt;/p&gt;

&lt;p&gt;Also, the fact that the evaluation of the ecosystem would be open source, could help other vendors,&lt;br&gt;
including direct competitors of ours, to get a clear picture of the current landscape, what is&lt;br&gt;
strong and what is missing. Also, If we get something wrong about them, they could contribute to the&lt;br&gt;
report!&lt;/p&gt;

&lt;p&gt;That same analysis could help solution providers and architects at companies to take more informed&lt;br&gt;
decisions on which tools to choose for the future of their companies.&lt;/p&gt;

&lt;p&gt;We can do it because we have the freedom to choose to use our competition when they are better. We&lt;br&gt;
can stop developing something and contribute to another existing solution if we don't see the&lt;br&gt;
benefit in our solution, thanks to our unique structure.&lt;/p&gt;

&lt;p&gt;In the world of open source, we believe that ‘competition' is not a harsh business reality. Rather&lt;br&gt;
than that, it is the collective effort towards building the best solutions that push the whole&lt;br&gt;
industry forward. And, of course, a personal motivation for growth!&lt;/p&gt;

&lt;h3&gt;
  
  
  Second Phase — Diagnostics
&lt;/h3&gt;

&lt;p&gt;During this phase, we'll diagnose our current brand identity. While all of us at The Guild have&lt;br&gt;
their own beliefs about the company, it's very important to us to see how you perceive us, so that&lt;br&gt;
we get as much user perspective as we can!&lt;/p&gt;

&lt;p&gt;We'll also take a look at other great companies in this space, to find inspiration and best&lt;br&gt;
practices.&lt;/p&gt;

&lt;p&gt;The diagnostics phase will aim to be as collaborative with the community as possible, as we want to&lt;br&gt;
challenge our own assumptions and find the most quality feedback!&lt;/p&gt;

&lt;h3&gt;
  
  
  Third Phase — Strategy
&lt;/h3&gt;

&lt;p&gt;Once we have a complete and data-driven understanding of the current state of The Guild, both from&lt;br&gt;
our internal perspective and external, with the help of our community, we'll be able to move towards&lt;br&gt;
building a set of strategic foundations.&lt;/p&gt;

&lt;p&gt;We will be hosting a workshop with North Star, during which we'll work together and decide how we&lt;br&gt;
want to tackle our goals and what are the best tactics to accomplish those.&lt;/p&gt;

&lt;p&gt;We are still thinking about the best ways to make that process also open source and collaborative&lt;br&gt;
with the community.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fourth Phase — Creative Execution
&lt;/h3&gt;

&lt;p&gt;Once we decide on the full strategy, we're going to execute on it — also here in an open source&lt;br&gt;
manner.&lt;/p&gt;

&lt;p&gt;All of our websites are already open source, so each change we'll make there would be as well.&lt;/p&gt;

&lt;p&gt;But we also want to open source our brand assets, design system in Figma and frontend components,&lt;br&gt;
communication strategy and guidelines and any other product or marketing related work we'll execute&lt;br&gt;
on.&lt;/p&gt;

&lt;p&gt;Usually these processes are not being done in the open, even at open source companies.&lt;/p&gt;

&lt;p&gt;We'll need to use or create tools and ways that help us collaborate on the process in that unique&lt;br&gt;
way. We hope others could benefit from that as well and maybe make it easier for companies to go&lt;br&gt;
through these types of processes in the open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Are We Sharing All of It in the Open?
&lt;/h2&gt;

&lt;p&gt;The Guild was created to be a place where solutions that are sustainable and for the long term are&lt;br&gt;
being built.&lt;/p&gt;

&lt;p&gt;One of the best ways to accomplish that is to be fully open source. It means that no matter what&lt;br&gt;
happens, including anything with the company itself — the solutions and the code are still&lt;br&gt;
available, out there and anyone could use and build upon them.&lt;/p&gt;

&lt;p&gt;As we've successfully managed to create that environment, it also came with a great deal of freedom.&lt;/p&gt;

&lt;p&gt;For example, we could have our most successful product -&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/hive" rel="noopener noreferrer"&gt;GraphQL Hive&lt;/a&gt; - to be&lt;br&gt;
&lt;a href="https://the-guild.dev/blog/announcing-self-hosted-graphql-hive" rel="noopener noreferrer"&gt;fully open source&lt;/a&gt;! While still&lt;br&gt;
being extremely successful SaaS business.&lt;/p&gt;

&lt;p&gt;That freedom drives us to work on things in the best way possible and we believe that sharing the&lt;br&gt;
marketing and branding process with all of you, will help us achieve the best results.&lt;/p&gt;

&lt;p&gt;It would help others who want to go through similar process, it will give access to our community to&lt;br&gt;
influence and take part in this important process and it would help other GraphQL vendors and push&lt;br&gt;
the whole ecosystem forward!&lt;/p&gt;

&lt;h2&gt;
  
  
  A Call for All of You
&lt;/h2&gt;

&lt;p&gt;Like open source tools - the most all of you will get involved, share your opinion and maybe even&lt;br&gt;
contribute - The Guild will become a better place and a powerful community for your needs.&lt;/p&gt;

&lt;p&gt;We will be sharing every step of the way here, on our blog. During the journey, we'll also be asking&lt;br&gt;
you to bring your thoughts and ideas in. They're most welcome!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>branding</category>
      <category>marketing</category>
    </item>
    <item>
      <title>Announcing Accounts.js 1.0 Release Candidate</title>
      <dc:creator>TheGuildBot</dc:creator>
      <pubDate>Mon, 08 Jan 2024 09:21:14 +0000</pubDate>
      <link>https://dev.to/the-guild/announcing-accountsjs-10-release-candidate-38ki</link>
      <guid>https://dev.to/the-guild/announcing-accountsjs-10-release-candidate-38ki</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was published on Monday, January 8, 2024 by &lt;a href="https://twitter.com/niccolobelli"&gt;Niccolo Belli&lt;/a&gt; @ &lt;a href="https://the-guild.dev/"&gt;The Guild Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first release candidate of &lt;a href="https://www.accountsjs.com/"&gt;Accounts.js&lt;/a&gt; 1.0 is now officially&lt;br&gt;
available!&lt;/p&gt;

&lt;p&gt;It's the culmination of a long process of rearchitecting the whole framework, which is finally a&lt;br&gt;
first-class citizen of the &lt;a href="https://the-guild.dev/graphql/modules"&gt;graphql-modules&lt;/a&gt; package. It&lt;br&gt;
supports the latest GraphQL.js v16 and &lt;a href="https://the-guild.dev/graphql/tools"&gt;graphql-tools&lt;/a&gt; v10 as&lt;br&gt;
well as any modern GraphQL server including Apollo Server v4 and&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/yoga-server"&gt;GraphQL Yoga&lt;/a&gt; v5.&lt;/p&gt;
&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;p&gt;My name is Niccolò Belli, &lt;a href="https://github.com/darkbasic"&gt;darkbasic&lt;/a&gt; on GitHub. I'm a freelance&lt;br&gt;
full-stack web developer passionate about open source who loves to work with Typescript and GraphQL,&lt;br&gt;
along with managing Linux servers. I've been working on Open Source technologies since many years&lt;br&gt;
and I've recently become an Accounts.js maintainer because I was tired of the existing alternatives&lt;br&gt;
and their lack of GraphQL integration. While I don't like overly-opinionated frameworks that lock&lt;br&gt;
you in into their ecosystems I love to work with libraries that allow you to quickly prototype your&lt;br&gt;
application while being scalable and highly customizable. That's why I'm also a MikroORM&lt;br&gt;
collaborator, which is the best Node.js ORM available and allows me to retain any amount of&lt;br&gt;
flexibility if I decide to manually write big PostgreSQL queries and hydrate the results back into&lt;br&gt;
the ORM for further processing. I've developed many tools around this workflow, including&lt;br&gt;
automatically generating &lt;a href="https://github.com/gajus/slonik"&gt;slonik&lt;/a&gt; types via the ORM metadata to&lt;br&gt;
manually write composable SQL queries that are type safe at runtime and build time. This is material&lt;br&gt;
for another blog post but I would love to make everything open source once my prerequisite&lt;br&gt;
&lt;a href="https://github.com/colinhacks/zod/pull/2234"&gt;zod PR&lt;/a&gt; gets merged.&lt;/p&gt;
&lt;h2&gt;
  
  
  What Is Accounts.JS
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;@accounts&lt;/code&gt; suite of packages aims to provide an end-to-end authentication and accounts&lt;br&gt;
management solution with n user-friendly way to start while preserving options for configuration.&lt;br&gt;
These packages offer OAuth support for popular providers such as Instagram or Twitter, two-factor&lt;br&gt;
authentication, password-based accounts, recovery options, and customizable account creation and&lt;br&gt;
validation.&lt;/p&gt;

&lt;p&gt;To integrate &lt;code&gt;accounts-js&lt;/code&gt; into your application, you need to configure these three components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Transports&lt;/strong&gt;: The flexibility of &lt;code&gt;accounts-js&lt;/code&gt; allows it to be integrated with different types&lt;br&gt;
of APIs. For now, we provide packages for both GraphQL and REST.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Databases&lt;/strong&gt;: Accounts.js provides a&lt;br&gt;
&lt;a href="https://github.com/accounts-js/accounts/tree/master/packages/database-mongo"&gt;native Mongo integration&lt;/a&gt;.&lt;br&gt;
Additionally, it offers&lt;br&gt;
&lt;a href="https://github.com/accounts-js/accounts/tree/master/packages/database-mikro-orm"&gt;MikroORM&lt;/a&gt; and&lt;br&gt;
&lt;a href="https://github.com/accounts-js/accounts/tree/master/packages/database-typeorm"&gt;Typeorm&lt;/a&gt;&lt;br&gt;
integrations, which lets you use &lt;code&gt;accounts-js&lt;/code&gt; with any database. Optionally, you can use Redis&lt;br&gt;
to store the session data, or provide a custom database adapter that will work with existing&lt;br&gt;
authentication strategies by implementing the &lt;code&gt;DatabaseInterface&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Strategies&lt;/strong&gt;: You can use multiple strategies to let your users access your app. For now, it&lt;br&gt;
supports password-based, magic link, and OAuth authentication methods.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Accounts.js is a &lt;strong&gt;full-stack&lt;/strong&gt; solution, providing a full set of packages to seamlessly&lt;br&gt;
implement your chosen authentication workflow on the &lt;strong&gt;client&lt;/strong&gt; as well!&lt;/p&gt;
&lt;h2&gt;
  
  
  The New Architecture
&lt;/h2&gt;

&lt;p&gt;In Accounts.js 1.0, we use &lt;code&gt;graphql-modules&lt;/code&gt; to compose the authentication framework, automatically&lt;br&gt;
piecing together your preferred database adapter(s) with the authentication service(s) of your&lt;br&gt;
choice (password-based, OAuth, etc). As mentioned before, &lt;code&gt;accounts-js&lt;/code&gt; currently supports GraphQL&lt;br&gt;
and REST. For the former, &lt;code&gt;graphql-modules&lt;/code&gt; automatically provides the schema based on the modules&lt;br&gt;
you're using, while for the latter, it provides dependency injection across the various modules to&lt;br&gt;
piece them together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createApplication&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;createAccountsCoreModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tokenSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nf"&gt;createAccountsPasswordModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;requireEmailVerification&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sendVerificationEmailAfterSignup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nf"&gt;createAccountsMongoModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;dbConn&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;schemaBuilder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;buildSchema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;typeDefs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resolvers&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your application already uses &lt;code&gt;graphql-modules&lt;/code&gt;, all you need to do is add the &lt;code&gt;accounts.js&lt;/code&gt;&lt;br&gt;
modules of your choice to your own application module. Otherwise, it's a matter of providing your&lt;br&gt;
resolvers and type definitions to the &lt;code&gt;buildSchema&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// GraphQL Yoga 5&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;yoga&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createYoga&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;useGraphQLModules&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
  &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createOperationController&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;createServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yoga&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Apollo Server 4&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apollo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApolloServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;gateway&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createApolloGateway&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;startStandaloneServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apollo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createOperationController&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;At this point, whatever your GraphQL server of choice, your authenticated application is just a few&lt;br&gt;
lines of code away.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But what if all I care is REST?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Use the &lt;code&gt;graphql-modules&lt;/code&gt; injector to retrieve the &lt;code&gt;AccountsServer&lt;/code&gt; instance and feed it to&lt;br&gt;
&lt;code&gt;@accounts/rest-express&lt;/code&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createOperationController&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accountsServer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;injector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AccountsServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;expressApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;accountsExpress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accountsServer&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, if you don't want to use &lt;code&gt;graphql-modules&lt;/code&gt;, you can still manually instantiate the&lt;br&gt;
providers. Here's&lt;br&gt;
&lt;a href="https://github.com/accounts-js/accounts/blob/master/examples/rest-express-typescript-without-modules/src/index.ts"&gt;an example&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The New MikroORM Database Adapter
&lt;/h2&gt;

&lt;p&gt;The second big change in Accounts.js 1.0 is the release of the brand new&lt;br&gt;
&lt;a href="https://mikro-orm.io/"&gt;MikroORM&lt;/a&gt; database adapter. MikroORM is a TypeScript ORM for Node.js based&lt;br&gt;
on Data Mapper, Unit of Work and Identity Map patterns. It is also very well-written and actively&lt;br&gt;
developed. Today also marks the release of the v6 of MikroORM, which incorporates&lt;br&gt;
&lt;a href="https://github.com/mikro-orm/mikro-orm/pull/4321"&gt;my recent work&lt;/a&gt; to automatically batch references&lt;br&gt;
and collections and retrieve them via dataloaders firing a single query. This is especially useful&lt;br&gt;
with GraphQL transport since it automatically solves its notorious N+1 problem without you even&lt;br&gt;
noticing it—more information &lt;a href="https://mikro-orm.io/docs/dataloaders"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Entity&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;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AccountsUser&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Property&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Property&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;nullable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;otherProps&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;CtorArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;otherProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Accounts.js MikroORM database adapter can be backed by your database of choice (PostgreSQL,&lt;br&gt;
MySQL, MariaDB, SQLite, MongoDB). It won't force you into any existing entity schema: you can use&lt;br&gt;
the existing entities or provide your own, but please make sure to extend the base ones so that&lt;br&gt;
authentication can occur.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;entities&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="nf"&gt;getUserSchema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;AccountsUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;abstract&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="nf"&gt;getEmailSchema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;UserEntity&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="nf"&gt;getServiceSchema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;UserEntity&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="nf"&gt;getSessionSchema&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;UserEntity&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, it uses MikroORM's &lt;a href="https://mikro-orm.io/docs/entity-schema"&gt;EntitySchema&lt;/a&gt;, so you&lt;br&gt;
must also provide the schema for the base entities.&lt;/p&gt;
&lt;h2&gt;
  
  
  Breaking Changes
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;@accounts/boost&lt;/code&gt; has been removed. It was no longer deemed necessary because of the new&lt;br&gt;
&lt;code&gt;graphql-modules&lt;/code&gt; architecture that already allows you to plug and play various modules. For&lt;br&gt;
example, instead of providing an existing database connection, you can let &lt;code&gt;@accounts/module-mongo&lt;/code&gt;&lt;br&gt;
create a new one for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createApplication&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[...],&lt;/span&gt;
    &lt;span class="c1"&gt;// If you don't provide dbConn it will automatically&lt;/span&gt;
    &lt;span class="c1"&gt;// create a new one, but the module needs to be awaited.&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createAccountsMongoModule&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@accounts/graphql-api&lt;/code&gt; has been moved into the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;@accounts/module-core&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;@accounts/module-magic-link&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;@accounts/module-mikro-orm&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;@accounts/module-mongo&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;@accounts/module-password&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;@accounts/module-typeorm&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These packages can assemble your desired authentication workflow and your preferred database&lt;br&gt;
adapter. Despite the significant changes under the hood, I strived to keep the public API mostly the&lt;br&gt;
same, so migrating to 1.0 should be a manageable effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's New
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  We switched from pnpm to yarn 4.&lt;/li&gt;
&lt;li&gt;  We now return code 401 unmasked errors when unauthorized.&lt;/li&gt;
&lt;li&gt;  Added the &lt;code&gt;requireEmailVerification&lt;/code&gt; option to require the user to verify the email in order to be
able to authenticate.&lt;/li&gt;
&lt;li&gt;  You can now enable both &lt;code&gt;ambiguousErrorMessages&lt;/code&gt; and &lt;code&gt;enableAutologin&lt;/code&gt; if
&lt;code&gt;requireEmailVerification&lt;/code&gt; is disabled.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;@accounts/password&lt;/code&gt; provides express endpoints to verify the email or reset the password whenever
the user clicks on the links received via email.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;@accounts/rest-express&lt;/code&gt; now validates its inputs via express-validator.&lt;/li&gt;
&lt;li&gt;  The examples now use graphql-yoga v5 instead of the old apollo-server 2.&lt;/li&gt;
&lt;li&gt;  A new &lt;code&gt;@apollo/server&lt;/code&gt; v4 example has been added.&lt;/li&gt;
&lt;li&gt;  A basic graphql-http example has been added.&lt;/li&gt;
&lt;li&gt;  A MikroORM example has been added.&lt;/li&gt;
&lt;li&gt;  The accounts-microservice example has been rewritten from scratch to use modern graphql-tools.&lt;/li&gt;
&lt;li&gt;  Docs have been refactored to use &lt;code&gt;docusaurus-plugin-typedoc-api&lt;/code&gt; instead of
&lt;code&gt;scripts/generate-api-docs.ts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  New and much improved CI release workflow.&lt;/li&gt;
&lt;li&gt;  Basic support for running tests from vscode.&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;graphql-modules&lt;/code&gt; to v3 alpha&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;@graphql-tools/merge&lt;/code&gt; to v9&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;@graphql-tools/schema&lt;/code&gt; to v10&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;@graphql-tools/utils&lt;/code&gt; to v10&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;graphql&lt;/code&gt; to v16&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;typeorm&lt;/code&gt; to 0.3.17&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;@apollo/client&lt;/code&gt; to 3.8&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;@graphql-codegen&lt;/code&gt; to v5&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;mongodb&lt;/code&gt; to v6&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;ioredis&lt;/code&gt; to v5&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;jsonwebtoken&lt;/code&gt; to v9&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;lodash&lt;/code&gt; to 4.17&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;pg&lt;/code&gt; to 8.11&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;request-ip&lt;/code&gt; to 3.3&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;oauth&lt;/code&gt; to 0.10&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;node-fetch&lt;/code&gt; to 2.7&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;express&lt;/code&gt; to 4.18&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;emittery&lt;/code&gt; to 0.13&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;@levminer/speakeasy&lt;/code&gt; to 1.4&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;@graphql-tools/delegate&lt;/code&gt; to v10&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;@graphql-tools/stitch&lt;/code&gt; to v9&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;@graphql-tools/wrap&lt;/code&gt; to v10&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;mongoose&lt;/code&gt; to v8&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;react&lt;/code&gt; to 18.2&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;jest&lt;/code&gt; to 29&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;typescript&lt;/code&gt; to 5.3&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;eslint&lt;/code&gt; to v8&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;prettier&lt;/code&gt; to v3&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;@apollo/server&lt;/code&gt; to 4.9&lt;/li&gt;
&lt;li&gt;  Upgraded &lt;code&gt;docusaurus&lt;/code&gt; to v3&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Remaining Work for the Stable Release
&lt;/h2&gt;

&lt;p&gt;OAuth authentication, while working, surely deserves some love. While REST endpoints for OAuth&lt;br&gt;
should be functional, there are no mutations or resolvers yet, meaning you can't use them with the&lt;br&gt;
GraphQL transport. I'd also like to review the OAuth code and write some examples.&lt;br&gt;
&lt;code&gt;@accounts/oauth-instagram&lt;/code&gt;, in particular, still relies upon the deprecated &lt;code&gt;request&lt;/code&gt; package and&lt;br&gt;
should be updated. Other popular OAuth providers like Facebook still need to be added (but PRs&lt;br&gt;
exist).&lt;/p&gt;

&lt;p&gt;Before the 1.0 stable gets released, I plan to get the existing providers in a better shape,&lt;br&gt;
together with examples and the relevant GraphQL schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Post 1.0
&lt;/h2&gt;

&lt;p&gt;I want to create a new &lt;code&gt;@accounts/phone&lt;/code&gt; authentication service which lets you authenticate via SMS&lt;br&gt;
OTPs. That would be especially useful in react-native applications where you could automatically&lt;br&gt;
read the SMS and automate the authentication process.&lt;/p&gt;

&lt;p&gt;Currently, Accounts.js bundles CommonJS code. While CommonJS can be imported in both CommonJS and&lt;br&gt;
ESM applications, that would rule out Deno/Bun support. For the same reason, we cannot use a wrapper&lt;br&gt;
either: while that would allow us to use ESM imports, it wouldn't be real ESM and thus won't be&lt;br&gt;
compatible. The remaining alternatives are pure ESM and dual packages. While several library authors&lt;br&gt;
opted for the former because of&lt;br&gt;
&lt;a href="https://nodejs.org/api/packages.html#packages_dual_package_hazard"&gt;dual package hazard&lt;/a&gt; concerns, I&lt;br&gt;
weigh the benefits differently. While dual package hazards are real, the whole GraphQL ecosystem&lt;br&gt;
relies on dual packages; thus, using &lt;code&gt;instance of&lt;/code&gt; is already a hazard. These authors suggest using&lt;br&gt;
&lt;code&gt;async imports&lt;/code&gt; to import their pure ESM libraries in common projects, which exposes everyone to the&lt;br&gt;
same hazard (not even considering that this is only viable in async contexts). That goes against why&lt;br&gt;
they decided to bundle pure ESM in the first place. I think it's still too early to target pure ESM,&lt;br&gt;
and dual package is the lesser evil, so I'm leaning towards that for future releases, but I'm ready&lt;br&gt;
to change my mind if you provide enough arguments.&lt;/p&gt;

&lt;p&gt;I'd also like to implement some form of account linking, where users could link their existing&lt;br&gt;
account with a different authentication service (for example, password-based and OAuth).&lt;/p&gt;

&lt;p&gt;I want to extend Multi-Factor Authentication outside of the password service, baking it into the&lt;br&gt;
core of accounts.js so that any authentication service can take advantage of it.&lt;/p&gt;

&lt;p&gt;If future major versions of Accounts.js introduce breaking changes to the database structure, I&lt;br&gt;
would like to provide migrations directly via the &lt;code&gt;@accounts/mikro-orm&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;Last but not least, I would like to bake in cookies authentication. Not only would that fare better&lt;br&gt;
against XSS, but it would also allow server-side rendering and thus enable the usage of frameworks&lt;br&gt;
like Next.js. Alternative storage methods would remain available for those using native&lt;br&gt;
applications.&lt;/p&gt;

&lt;p&gt;At the end of the day, 1.0 is just a number, and I really want to provide stable APIs via semantic&lt;br&gt;
versioning.&lt;/p&gt;

&lt;p&gt;Accounts.js is an open-source project, and we welcome your&lt;br&gt;
&lt;a href="https://github.com/accounts-js/accounts"&gt;contributions&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>accountsjs</category>
      <category>graphqlmodules</category>
      <category>graphql</category>
    </item>
    <item>
      <title>Building Open Source GraphQL Security</title>
      <dc:creator>TheGuildBot</dc:creator>
      <pubDate>Thu, 07 Dec 2023 23:44:52 +0000</pubDate>
      <link>https://dev.to/the-guild/building-open-source-graphql-security-1727</link>
      <guid>https://dev.to/the-guild/building-open-source-graphql-security-1727</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article was published on Friday, December 8, 2023 by &lt;a href="https://twitter.com/NoheHf" rel="noopener noreferrer"&gt;Nohé Hinniger-Foray&lt;/a&gt; @ &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild Blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Open-Source GraphQL Security, Importance &amp;amp; Tools
&lt;/h1&gt;

&lt;p&gt;Open-source principles have forged GraphQL as a standard, it's ecosystem and community. Bringing&lt;br&gt;
value via transparency and collective knowledge as well as empowering the community with tools and&lt;br&gt;
practices to build better, bigger &amp;amp; more efficient APIs from day to day. Now that GraphQL APIs are&lt;br&gt;
well-established and with a lots of queries on a daily basis, ensuring their security becomes&lt;br&gt;
crucial.&lt;/p&gt;

&lt;p&gt;In this exploration, we'll dive into how these open-source practices are important and benefits for&lt;br&gt;
the security of GraphQL and which community tools you can leverage today to secure your APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  GraphQL Is Open-Source at Its Core
&lt;/h2&gt;

&lt;p&gt;The inception and evolution of GraphQL are intrinsically tied to the principles of open-source,&lt;br&gt;
ensuring it flourished not just as a query language but as a community-driven initiative progressing&lt;br&gt;
toward broader, unified API development standards. From its public&lt;br&gt;
&lt;a href="https://github.com/graphql/graphql-spec" rel="noopener noreferrer"&gt;specifiction release&lt;/a&gt; in 2015 by Facebook to its&lt;br&gt;
transition to the &lt;a href="https://graphql.org/foundation/" rel="noopener noreferrer"&gt;GraphQL Foundation&lt;/a&gt; in 2018—hosted by the Linux&lt;br&gt;
Foundation—its journey has been transparent and collaborative.&lt;/p&gt;

&lt;p&gt;While the GraphQL specification paved the way for consistent and efficient API queries, the&lt;br&gt;
open-source community enhanced this original draft further. Take the&lt;br&gt;
&lt;a href="https://relay.dev/graphql/connections.htm" rel="noopener noreferrer"&gt;Relay Pagination Specification&lt;/a&gt;, for instance, which&lt;br&gt;
streamlines how pagination can be handled in GraphQL (among other React specific features),&lt;br&gt;
providing a standard methodology that developers can rely on. Similarly, the introduction of custom&lt;br&gt;
directives allowed GraphQL to become more flexible and adaptable to specific use-cases, like the&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/tools/docs/schema-directives#fetching-data-from-a-rest-api" rel="noopener noreferrer"&gt;@rest directive&lt;/a&gt;&lt;br&gt;
or&lt;br&gt;
&lt;a href="https://the-guild.dev/blog/subscriptions-and-live-queries-real-time-with-graphql" rel="noopener noreferrer"&gt;@live queries&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Moreover, the vast majority of widespread GraphQL tools have and are being built under open-source&lt;br&gt;
licences. Servers implementations, frontend clients, utilities like schema management, code&lt;br&gt;
generation or even fully fledged API platforms are legion. You can find a comphrensive list of such&lt;br&gt;
tools on the &lt;a href="https://graphql.org/code/" rel="noopener noreferrer"&gt;graphql.org website&lt;/a&gt;. &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild&lt;/a&gt;&lt;br&gt;
are also masters when it comes to GrahpQL &amp;amp; Open-source and their tools come highly recommended.&lt;/p&gt;

&lt;p&gt;For instance, as GraphQL is transport agnostic, it can be used with any protocol, a tremendous&lt;br&gt;
amount of open-source tools have been built to leverage this flexibility, especially by&lt;br&gt;
&lt;a href="https://github.com/enisdenjo" rel="noopener noreferrer"&gt;@enisdenjo&lt;/a&gt;: &lt;a href="https://github.com/graphql/graphql-http" rel="noopener noreferrer"&gt;graphql-http&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/enisdenjo/graphql-ws" rel="noopener noreferrer"&gt;graphql-ws&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/enisdenjo/graphql-sse" rel="noopener noreferrer"&gt;graphql-sse&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I can also mention the work on unified APIs via&lt;br&gt;
&lt;a href="https://the-guild.dev/graphql/hive/federation" rel="noopener noreferrer"&gt;GraphQL federation&lt;/a&gt; that is also under active&lt;br&gt;
open-source development, with the&lt;br&gt;
&lt;a href="https://github.com/graphql/composite-schemas-wg" rel="noopener noreferrer"&gt;Composite Schema Working Group&lt;/a&gt; initiative, and&lt;br&gt;
upcoming&lt;br&gt;
&lt;a href="https://graphql.org/conf/sessions/4a4e842d1cd0c06083f484d31225abd1/?name=GraphQL%20Fusion:%20Rethinking%20Distributed%20GraphQL" rel="noopener noreferrer"&gt;GraphQL Fusion&lt;/a&gt;&lt;br&gt;
specification.&lt;/p&gt;

&lt;p&gt;And last but not least, the GraphQL community is also very community centered, wether via the&lt;br&gt;
&lt;a href="https://graphql.org/community/developers/#working-groups" rel="noopener noreferrer"&gt;GraphQL working group&lt;/a&gt; or the various&lt;br&gt;
events and meetups such as the &lt;a href="https://graphql.org/conf/" rel="noopener noreferrer"&gt;GraphQL Conf&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In essence, GraphQL isn't simply open-source in its availability but embodies open-source in its&lt;br&gt;
ongoing development, enhancements, and community engagement, perpetually enriching its ecosystem&lt;br&gt;
with diverse inputs, insights, and innovations.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Importance of Open Source and Public Resources in Security
&lt;/h2&gt;

&lt;p&gt;Keeping the internet safe is a big challenge. It's like a tightly connected place with lots of&lt;br&gt;
potential threats. Open source and public tools have been doing a great job at protecting it for&lt;br&gt;
years.&lt;/p&gt;

&lt;p&gt;Cybersecurity thrives on collaboration, exemplified by the Common Vulnerabilities and Exposures&lt;br&gt;
(&lt;a href="https://cve.mitre.org/" rel="noopener noreferrer"&gt;CVE&lt;/a&gt;) system. This public database acts as a central repository for known&lt;br&gt;
cybersecurity threats, allowing for quick dissemination and response. By making vulnerabilities&lt;br&gt;
public, the CVE system ensures timely and widespread implementation of security measures. For&lt;br&gt;
instance, the identification and patching of the Heartbleed bug in OpenSSL was significantly aided&lt;br&gt;
by the CVE system, showcasing its effectiveness in promoting rapid response.&lt;/p&gt;

&lt;p&gt;Open source plays a crucial role in cybersecurity by fostering an environment of transparency and&lt;br&gt;
collaboration. It allows for the open identification and resolution of vulnerabilities, benefiting&lt;br&gt;
the entire digital ecosystem. For example, the Linux Kernel, known for its security, continually&lt;br&gt;
improves through community contributions. Similarly, tools like Kali Linux offer insights into&lt;br&gt;
offensive cybersecurity strategies, helping developers strengthen their defenses.&lt;/p&gt;

&lt;p&gt;This combination of open source and CVE is especially vital in areas like GraphQL and API security,&lt;br&gt;
providing a foundation for robust, adaptable cybersecurity strategies. Through shared knowledge and&lt;br&gt;
tools, open source and CVE create a proactive defense against evolving cyber threats.&lt;/p&gt;

&lt;p&gt;In a field like cybersecurity, where dangers morph quickly, having shared knowledge, united&lt;br&gt;
alertness, and available-to-all tools become an essential shield against potential attacks. The&lt;br&gt;
marriage of open source and cybersecurity offers a lively platform for ongoing learning, changing,&lt;br&gt;
and sharing attack and defense mechanisms, crafting a global, united front against cyber threats.&lt;/p&gt;

&lt;p&gt;Moving forward, we'll dive into how this perfect pairing of open source and cybersecurity is&lt;br&gt;
crucial, not just relevant, for GraphQL and API security. We'll highlight practical tools and&lt;br&gt;
strategies you can use today to protect your applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Source GraphQL Security Ressources &amp;amp; Tools
&lt;/h2&gt;

&lt;p&gt;There are many GraphQL open-source tools available to help developers and businesses defend against&lt;br&gt;
possible cybersecurity threats. From defensive measures that shield sensitive data to offensive&lt;br&gt;
tools aimed at identifying vulnerabilities, the open-source community has build invaluable resources&lt;br&gt;
to cover a wide variedy of cyber-security needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning Tools &amp;amp; Resources: Armoring with Knowledge
&lt;/h3&gt;

&lt;p&gt;In the sphere of cybersecurity, especially concerning GraphQL, the adage 'knowledge is power' is&lt;br&gt;
paramount. Continual learning, embracing best practices, and leveraging insights from the community&lt;br&gt;
is an essential shield to secure APIs against vulnerabilities.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Best Practices&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*   [Persisted/Trusted queries](https://benjie.dev/graphql/trusted-documents): This feature allows
    you to save bandwidth and improve performance by sending a hash of the query instead of the
    full query. It also has a huge impact on security, as it prevents attackers from sending
    arbitrary queries to your server. Check GraphQL Yoga
    [persisted operations](https://the-guild.dev/graphql/yoga-server/docs/features/persisted-operations)
*   [9 GraphQL Security Best Practices](https://escape.tech/blog/9-graphql-security-best-practices/):
    Dive into Escape's comprehensive guide which unveils nine pivotal security best practices,
    presenting a blend of actionable insights and theoretical knowledge to fortify GraphQL
    implementations against potential threats.
*   [The Guild's best practices article](https://the-guild.dev/blog/unleash-the-power-of-fragments-with-graphql-codegen):
    While this resource by The Guild isn't strictly security-focused, it provides invaluable best
    practices on GraphQL clients that, when adeptly applied, augment the robustness and efficiency
    of GraphQL APIs, subsequently enhancing their inherent security.
*   [Official authorization docs](https://graphql.org/learn/authorization/) The official GraphQL
    documentation provides a comprehensive guide to authorization, which is a crucial aspect of
    security in your API. Generally speaking, knowing the specification and documentation is a key
    to understanding how your application works and therefore how to secure it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://escape.tech/blog/api-security-academy/" rel="noopener noreferrer"&gt;API Security Academy&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The API Security Academy, an open-source platform developed by Escape, navigates through the&lt;br&gt;
multifaceted world of GraphQL security. A wellspring of knowledge, it offers structured learning&lt;br&gt;
paths, exploring vulnerabilities, attack vectors, and preventive strategies, thereby forging a&lt;br&gt;
security-savvy developer who can intuitively construct and validate secure APIs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Blogs and More&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Explore the many insights and experiences shared by experts through different channels:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*   **Blogs**: Immerse yourself in rich content through blogs from
    [Escape](https://escape.tech/blog/) and [The Guild](https://the-guild.dev/blog/), offering a
    spectrum of perspectives, learnings, and strategies around GraphQL and cybersecurity.
*   **Videos**: Discover visual insights through a collection of videos curated by
    [GraphQL WTF](https://graphql.wtf/). Although not strictly centered around security,
    understanding various facets of GraphQL enhances your capability to architect, implement, and
    secure GraphQL APIs more effectively.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Online security is always changing, often at a rapid pace. By adhering to best practices, engaging&lt;br&gt;
with learning platforms and tapping into the collective knowledge shared through blogs and videos,&lt;br&gt;
we arm ourselves and our APIs against the multifaceted cybersecurity threats that persist in the&lt;br&gt;
digital realm.&lt;/p&gt;

&lt;p&gt;This path of continuous learning and adaptation ensures that as developers and cybersecurity&lt;br&gt;
professionals, we remain up to date to secure our GraphQL APIs against both prevalent and emerging&lt;br&gt;
threats.&lt;/p&gt;

&lt;h3&gt;
  
  
  Defensive Tools
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Escape-Technologies/graphql-armor" rel="noopener noreferrer"&gt;GraphQL Armor&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Developed by our tech team at Escape, GraphQL Armor is a middleware plugin designed to be an&lt;br&gt;
immediate security upgrade for your GraphQL server. Acting like a personal bodyguard for your&lt;br&gt;
data, it integrates seamlessly with &lt;a href="https://the-guild.dev/graphql/envelop" rel="noopener noreferrer"&gt;Envelop&lt;/a&gt; — a&lt;br&gt;
flexible plugin system introduced by The Guild for crafting high-quality, performant GraphQL&lt;br&gt;
extensions. GraphQL Armor adheres to the ethos of providing accessible, user-friendly security&lt;br&gt;
solutions that can be efficiently integrated into your GraphQL setup, safeguarding it from&lt;br&gt;
potential vulnerabilities and threats.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/dimatill/graphql-shield" rel="noopener noreferrer"&gt;GraphQL Shield&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GraphQL Shield empowers developers with a permission layer for applications, securing APIs by&lt;br&gt;
utilizing an intuitive rule-API that activates the Shield engine on every request. Moreover, it&lt;br&gt;
smartly caches data to keep your application sprightly and ensures internal data remains under&lt;br&gt;
wraps, enhancing both performance and security.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With open-source defensive tools like GraphQL Armor and GraphQL Shield, businesses and developers&lt;br&gt;
can reinforce the security of their GraphQL APIs, protecting data and operations from unauthorized&lt;br&gt;
access and potential malicious activities. Navigating through the extensive open-source ecosystem&lt;br&gt;
and leveraging these security tools not only fortifies your GraphQL APIs but also enriches the&lt;br&gt;
collective knowledge and defense mechanisms of the community, aligning with the spirit of&lt;br&gt;
collaborative development and security.&lt;/p&gt;

&lt;p&gt;In the upcoming section, we'll delve into offensive tools and resources for learning to equip you&lt;br&gt;
with a holistic arsenal for safeguarding your GraphQL APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Offensive Tools: A Proactive Step towards Fortified Defense
&lt;/h3&gt;

&lt;p&gt;When it comes to ensuring an unbreakable security perimeter, adopting an offensive approach is&lt;br&gt;
pivotal. By putting our defenses to the test and simulating possible attacks, we preemptively expose&lt;br&gt;
potential vulnerabilities and weaknesses before they can be exploited maliciously. This strategy is&lt;br&gt;
basically following the idea: the best defense is a good offense. Let's uncover two powerful&lt;br&gt;
open-source tools that allow us to proactively secure our GraphQL APIs by adopting an offensive&lt;br&gt;
stance.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://escape.tech/blog/introducing-goctopus/" rel="noopener noreferrer"&gt;Goctopus&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Say hello to Goctopus, our open-source GraphQL endpoint discovery and fingerprinting tool. This&lt;br&gt;
tentacled marvel meticulously hunts down GraphQL endpoints, fingerprinting their authentication&lt;br&gt;
methods and schema availability, ensuring not a single detail slips through its grasp. Built by&lt;br&gt;
the Escape team, Goctopus lends developers and businesses a watchful eye, enabling them to&lt;br&gt;
identify and comprehend the specifics of GraphQL endpoints with precision, ensuring that they&lt;br&gt;
can reinforce any possible points of vulnerability within their organization before they become&lt;br&gt;
a target.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/nikitastupin/clairvoyance" rel="noopener noreferrer"&gt;Clairvoyance&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Meet Clairvoyance, a savvy tool designed to peek into GraphQL APIs even when introspection is&lt;br&gt;
disabled, which is a common security measure (e.g.,&lt;br&gt;
&lt;a href="https://www.apollographql.com/docs/tutorial/schema/#explore-your-schema" rel="noopener noreferrer"&gt;Apollo Server automatically disables introspection in production environments&lt;/a&gt;).&lt;br&gt;
Clairvoyance subtly and skillfully retrieves schema information from these APIs, providing&lt;br&gt;
developers with insights into the API structure and potential vulnerability points. This becomes&lt;br&gt;
particularly vital when dealing with APIs that have sought to shield their schema details as a&lt;br&gt;
security measure.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both Goctopus and Clairvoyance offer distinctive capabilities, allowing developers and cybersecurity&lt;br&gt;
professionals to proactively and meticulously assess and bolster their GraphQL API defenses. By&lt;br&gt;
utilizing these offensive tools, we position ourselves a step ahead, ensuring that our APIs are not&lt;br&gt;
just constructed with security in mind but are continually assessed and enhanced to defend against&lt;br&gt;
evolving cybersecurity threats.&lt;/p&gt;

&lt;p&gt;As we move forward, our journey will venture into open-source learning resources and best practices&lt;br&gt;
in GraphQL security, ensuring that your armory is not just stocked with tools but also with&lt;br&gt;
knowledge and strategies to implement them effectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up and Joining Forces
&lt;/h2&gt;

&lt;p&gt;Huge shoutout to &lt;a href="https://the-guild.dev/" rel="noopener noreferrer"&gt;The Guild&lt;/a&gt; for hosting this dive into the depths of&lt;br&gt;
GraphQL and open-source magic. Their work, and the work of countless others in our robust community,&lt;br&gt;
propels GraphQL to new heights daily. Your code, knowledge, and keen eyes are the gears moving this&lt;br&gt;
ecosystem forward.&lt;/p&gt;

&lt;p&gt;But hey, let's not stop there! &lt;strong&gt;Contribute, Engage, Elevate.&lt;/strong&gt; That's the open-source mantra. Your&lt;br&gt;
expertise could well be the next big leap forward for GraphQL tools and platforms. Check out these&lt;br&gt;
awesome GraphQL projects on &lt;a href="https://graphql.org/code/" rel="noopener noreferrer"&gt;graphql.org/code&lt;/a&gt; and the&lt;br&gt;
&lt;a href="https://github.com/Escape-Technologies/awesome-graphql-security" rel="noopener noreferrer"&gt;Awesome GraphQL security list&lt;/a&gt;!&lt;br&gt;
Here at &lt;a href="https://escape.tech/" rel="noopener noreferrer"&gt;Escape&lt;/a&gt;, our open-source initiatives and SaaS solutions are all about&lt;br&gt;
injecting the GraphQL space with robust, unshakeable security defenses. But it's a team sport, and&lt;br&gt;
every contribution counts.&lt;/p&gt;

&lt;p&gt;Let's keep the momentum, elevate our game in cybersecurity, and shape a future where GraphQL isn't&lt;br&gt;
just powerful and efficient but an unassailable fortress in API development.&lt;/p&gt;

&lt;p&gt;Thanks for tagging along on this adventure. Together, let's build a safer, and better GraphQL&lt;br&gt;
ecosystem.&lt;/p&gt;

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