Skip to content

salesforce/cms-graphql-apis


CMS GraphQL API

This is an open source project whose vision is to provide Salesforce CMS customers query the public CMS apis using GraphQL queries.
This project is currently integrated with CMS delivery apis »

Table of Contents
  1. About The Project
  2. Getting Started
  3. Usage
  4. Roadmap
  5. Contributing
  6. Acknowledgements

About The Project

GraphQL Sample Query

GraphQL provides a optimized way to fetch data which involves loq latency and high throughput

Couple of motivations behind using GraphQL for CMS delivery apis are:

  • Overfetching : Currently CMS Rest endpoint have a specific response schema. It ends up overfetching un-necessary metadata
  • Underfetching: In some scenarios we have to fetch the id of a related entity and request another rest endpoint to get the metadata.
  • Nested Queries: Ex: In order to get related contents in a channel, first we have to fetch all the channels and then make a query to fetch all the related contents. These nested queries increase the latency between the client and server
  • UI components: UI components require low latency , i.e. less nested query calls. GraphQL optimizes this by creating the nested query upfront and then provide the details to the server in one go

There are other reasons because of which GraphQL has a wide adoption across the industry.

Problem Statement

As a user I to get the channel Name, channel Type and only the managedContentId and banner image from the related content Nodes

Note this is an example of nested query. Here is how a user can achieve this

Imagine if a UI component is consuming this data, couple of issues this has are

  • We are overfetching channel metadata along with related content metadata
  • We are performing 2 nested queries, so the client has to wait for the response from both the queries before it is able to render
  • We don't have a way to define a directive like if or skip (We will discuss this with an example)

Getting Started

To get a local copy up and running follow these simple example steps.

Prerequisites

Installation

  1. Clone the repo

    git clone git@github.com:salesforce/cms-graphql-apis.git
  2. Open the project in Intellij

  3. Go to the application.properties under src/main/resources and paste the username, password, client id and client secret (from the connected app)

  4. Build and run GraphqlApiApplication

Usage

Once the project is up and running, open postman and do a post query

Postman Url: http://localhost:8081/graphql (Refer to the project snapshot image at the top)

Introspection

  1. First let's understand what kind of objects are supported currently GraphQL query:
{
  __schema {
    types {
      name
    }
  }
}

GrahQL response

{
    "data": {
        "__schema": {
            "types": [
                ...
                {
                    "name": "ManagedContentBannerImage"
                },
                {
                    "name": "ManagedContentBody"
                },
                {
                    "name": "ManagedContentExcerpt"
                },
                {
                    "name": "ManagedContentItem"
                },
                {
                    "name": "ManagedContentNodes"
                },
                {
                    "name": "ManagedContentSource"
                },
                {
                    "name": "ManagedContentTitle"
                },
                {
                    "name": "NodeTypeEnum"
                },
                {
                    "name": "Query"
                },
                ...
            ]
        }
    }
}
  1. Let's say if you want to know more details of any object GraphQL query:
{
    __type (name: "ManagedContentNodes"){
      name
      fields {
          name
          type {
              name
              kind
          }
      }
    }
  
}

GraphQl response:

{
    "data": {
        "__type": {
            "name": "ManagedContentNodes",
            "fields": [
                {
                    "name": "source",
                    "type": {
                        "name": "ManagedContentSource",
                        "kind": "OBJECT"
                    }
                },
                {
                    "name": "title",
                    "type": {
                        "name": "ManagedContentTitle",
                        "kind": "OBJECT"
                    }
                },
                {
                    "name": "bannerImage",
                    "type": {
                        "name": "ManagedContentBannerImage",
                        "kind": "OBJECT"
                    }
                },
                {
                    "name": "excerpt",
                    "type": {
                        "name": "ManagedContentExcerpt",
                        "kind": "OBJECT"
                    }
                },
                {
                    "name": "body",
                    "type": {
                        "name": "ManagedContentBody",
                        "kind": "OBJECT"
                    }
                }
            ]
        }
    }
}

Once we determine the fields then couple of use cases that are currently supported (Note these are examples which might not include all the fields, consider them just an example)

As a user I want to get few metadata from the channel and few from the related content

GraphQL Query:

query ChannelWithContents {
    channelById(channelId: "<<channelId>>"){
        channelName
        channelType
        domainId
        items (managedContentId: "<<managedContentId>>"){
            managedContentId
            contentNodes {
                bannerImage {
                    mediaType
                }
            }
        }
    }
}

GraphQl Response:

{
    "data": {
        "channelById": {
            "channelName": "<<Name>>",
            "channelType": "Community",
            "domainId": null,
            "items": [
                {
                    "managedContentId": "<<id>>",
                    "contentNodes": {
                        "bannerImage": {
                            "mediaType": "Image"
                        }
                    }
                },
                {
                    "managedContentId": "<<id>>",
                    "contentNodes": {
                        "bannerImage": null
                    }
                }
            ]
        }
    }
}

As a user I want to search for a particular queryTerm in a channel

GraphQL Query:

query SearchContent {
    searchContent (channelId: "0ap1R000000blKCQAY", queryTerm: "Addidas") {
        contentType {
            developerName
        }
        id
        publishDate
        title 
        urlName
    }
}

GraphQL Response:

{
    "data": {
        "searchContent": [
            {
                "contentType": {
                    "developerName": "news"
                },
                "id": "20Y1R000000CaV9UAK",
                "publishDate": "2020-12-28T05:57:50.000Z",
                "title": "Addidas News",
                "urlName": "addidas-news"
            }
        ]
    }
}

As a user I want to define a way to include or exclude metadata from my response

GraphQL Query:

query ChannelWithContent ($includeBanner: Boolean!){
    channelById(channelId: "0ap1R000000blKCQAY"){
        channelName
        channelType
        domainId
        items{
            managedContentId
            contentNodes {
                bannerImage @include(if: $includeBanner){
                    mediaType
                }
            }
        }
    }
}

Note the variable definition at the top ($includeBanner) this is an example which defines if a section is added or removed from the response

GraphQL variable payload

{
    "includeBanner": false
}

GraphQL Response

{
    "data": {
        "channelById": {
            "channelName": "Ankhi Arts",
            "channelType": "Community",
            "domainId": null,
            "items": [
                {
                    "managedContentId": "20Y1R000000CaV9UAK",
                    "contentNodes": {}
                },
                {
                    "managedContentId": "20Y1R000000001EUAQ",
                    "contentNodes": {}
                }
            ]
        }
    }
}

Roadmap

See the open issues for a list of proposed features (and known issues).

Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Acknowledgements

About

No description, website, or topics provided.

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages