Logo

dev-resources.site

for different kinds of informations.

Crafting a Unified GraphQL Experience with AWS AppSync Merged APIs

Published at
5/11/2024
Categories
aws
appsync
graphql
serverless
Author
rubenrangel
Categories
4 categories in total
aws
open
appsync
open
graphql
open
serverless
open
Author
11 person written this
rubenrangel
open
Crafting a Unified GraphQL Experience with AWS AppSync Merged APIs

Lately, Ive been exploring AWS AppSync Merged APIs to better understand the complexities and tradeoffs involved in creating a unified GraphQL API experience that can be supported by various subdomain teams.

Motivation

GraphQL is all about the graph formed by the Types in the schema. Forming relationships between Types allows clients to connect these different entities. This enables enhanced client experiences and can result in more efficient server interactions.

However, as the number of Types (vertices in the graph) increases, so does the maintenance of the API. Maybe the API holds all the functionality for a scaling business, and so the capabilities of the API and the number of engineers supporting the API grow. If the GraphQL API is implemented in AppSync, Merged APIs can help lower the cognitive load of maintenance by allowing subsections of the API to be powered by Source APIs (and possibly a single domain team).

Example

Our simplified example involves the API of a fictional car manufacturer called Wheely. Wheely has software teams supporting two areas of the business: Parts Manufacturing and Car Assembly. Due to various reasons, the two teams prefer not to maintain their shared AppSync API in a single codebase (possibly due to differences like spaces vs. tabs). They decide to split the codebase to better suit their domains' needs but still aim to collectively provide support for a unified GraphQL API to maximize its benefits for the business.

They opt to use AppSync Merged APIs to create a single Wheely API supported by a single AppSync API for each domain. The Car Assembly team wants to manage the core information about Wheely's car offerings, while the Parts Manufacturing team focuses on overseeing the inventory of parts used in the cars. Both teams also see the value in being able to retrieve all parts used in a specific car as a key feature of the API.

API Design

Both source APIs will provide their parts of the overall GraphQL API and each leverage the @canonical annotation to avoid conflicts on Types and Fields.

Car Assembly

The Car Assembly API owns the Car Type and the getCar Query. This schema also has the Car.parts Field, but makes note to other engineers that it does not own it, so other engineers can be aware of this dependency. The same is true for the Part Type.

# Owned by the Parts Manufacturing AppSync API
type Part {
    id: ID!
}

type Car @canonical {
    id: ID!
    make: String!
    model: String!
    # Owned by the Parts Manufacturing AppSync API
    parts: [Part!]!
}

type Query {
    getCar(id: ID!): Car @canonical
}
Enter fullscreen mode Exit fullscreen mode

Parts Manufacturing

The Parts Manufacturing API owns the Part Type and the getPart Field. It also owns the Car.parts Field even though it doesn't own the Car Type. This AppSync API has a resolver for the Car.parts Field and no other source API can add a resolver for that Field, making this API the source of truth for this piece of data.

# Owned by the Car Assembly AppSync API
type Car {
    parts: [Part!]! @canonical
}

type Part @canonical {
    id: ID!
    name: String!
}

type Query {
    getPart(id: ID!): Part @canonical
}
Enter fullscreen mode Exit fullscreen mode
Car.parts Resolver

This resolver relies on the IDs of the parts to retrieve being passed to it either via the source or stash in the context. It then uses those IDs to filter its datastore to retrieve the parts needed to fulfill the parts Field for the request.

/**
 * This resolver assumes the part IDs will be a field from the parent field OR be included in the stash.
 */
export function request(ctx) {
    /**
     * @type {string[] | undefined}
     */
    const partIds = ctx.source.partIds ? ctx.source.partIds : ctx.stash.partIds;

    if (partIds === undefined) {
        util.error('No part IDs supplied.')
    }

    const parts = [
        {
            id: "1",
            name: "Headlights"
        },
        {
            id: "2",
            name: "Sunroof"
        },
        {
            id: "3",
            name: "Leather Seats"
        },
        {
            id: "4",
            name: "Cloth Seats"
        }
    ];

    return {
        payload: parts.filter(part => partIds.includes(part.id))
    };
}

export function response(ctx) {
    return ctx.result
}
Enter fullscreen mode Exit fullscreen mode

Merged API

This is the final merged API that the client would depend on. The client doesn't see that the implementation of this is spread across multiple APIs. We've really leaned into the "Interface" part of the API here.

type Car {
  id: ID!
  make: String!
  model: String!
  parts: [Part!]!
}

type Part {
  id: ID!
  name: String!
}

type Query {
  getCar(id: ID!): Car
  getPart(id: ID!): Part
}
Enter fullscreen mode Exit fullscreen mode

Tradeoffs and Considerations

Managing API Design

With the nested Type dependency from the merged APIs, communication between owners of the Source APIs is important. GraphQL design (and any API for that matter) should have time put into the "how" it should work. Doing that over disparate teams and evolving the API over time increases complexity.

Collaboration is always important in software engineering. However, using Merged APIs without a plan of how to drive changes, who owns which parts, or which parts live in which AppSync APIs could hinder success.

Contract Coordination

As you can see in the Car.parts resolver, it expects the partIds data to be passed in either from the parent Field resolver (in the source) or inserted earlier in the request's stash. The implementation in the repository will have the Query.getCar resolver always return the partIds Field to AppSync, even if the client doesn't request the Car.parts Field. It's returning the entire data model.

This works fine for this simple example. But, maybe in the future, the Car Assembly team makes a design decision to only return to AppSync Fields that the client requests, so they can increase performance. If the client doesn't request Car.parts, then the resolver will not return partIds, and then the implicit contract between that API and the Parts Manufacturing API will break.

Similar to the API design consideration above, the software teams need to be aware of the interactions between dependencies and dependents.

"Unowned" API Resources

In AppSync Merged APIs, the resulting API is the combination of all the source APIs. Not everything in the Merged API needs the @canonical annotation though. Source APIs can contribute any Type, Query, Mutation, etc. and not provide any conflict-resolution through the @canonical annotation. Conflicting definitions could result in unexpected behaviors for clients and bugs.

Resources

appsync Article's
30 articles in total
Favicon
The Power of AWS API Gateway and AWS AppSync: Transforming API Development, Functionality, and Use Cases
Favicon
Grow your startup business with TechnBrains App Development.
Favicon
Testing AppSync Subscriptions
Favicon
Why does McDonald's ask about mobile apps?
Favicon
Easy Victory APK (Download Free Latest Version)V1.7.1
Favicon
How To Build an Ethereum wallet?
Favicon
How to List Held Tokens by an Address Using the Moralis API
Favicon
Effortless API Scaling: Unlock the Power of AWS AppSync
Favicon
Guarantee message deliveries for real-time WebSocket APIs with Serverless on AWS
Favicon
AWS AppSync Events — Serverless WebSockets Done Right or Just Different?
Favicon
What Makes the Best App Development Course in Jaipur?
Favicon
A Complete Guide to Different Types Of Mobile Apps
Favicon
App Ruckus - Ultimate mobile app reviews and recommendations
Favicon
Adding Real-Time Interactivity to Your Live Streams With AWS AppSync
Favicon
Rope Hero Mod APK Download 2024
Favicon
What is Shopify App Development and Why Does Your E-commerce Business Need It Now?
Favicon
Building Well-Architected AWS AppSync GraphQL APIs
Favicon
How to Use Terabox Ads-Free 2024
Favicon
Testing AWS AppSync JavaScript Resolvers
Favicon
TeaTv App Recommended for web-series and movies
Favicon
What Is Lightroom Mod APK?
Favicon
JOJOYAPK Download APPS Free
Favicon
Crafting a Unified GraphQL Experience with AWS AppSync Merged APIs
Favicon
Decoding Cross-Platform and Native Development in 2024
Favicon
What is SSL pinning, and how do you implement it in a mobile app?
Favicon
Executing long running tasks with AppSync
Favicon
How Mobile App Analytics Can Help?
Favicon
TaskRabbit Clone: Launch Your On
Favicon
The Power of Mobile Apps in Digital World
Favicon
Exploring the Thrilling World of Truck Simulator Ultimate Mod APK

Featured ones: