Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BSPD-1017: GraphQL Schema Documentation #48

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
119 changes: 119 additions & 0 deletions graphql-schema-documentation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# GraphQl Schema Documentation

This example demonstrates Brightspot's ability to use a GraphQL endpoint to capture schema documentation. When brought to the front end using codegen, the types for the schema will have documentation for the content type itself and its fields.

## What you will learn

1. How to use Javadocs to add documentation to Brightspot's GraphQL Schemas
2. How to bring the documentation to your front-end application using [Codegen](https://www.the-guild.dev/graphql/codegen/docs/getting-started)
3. How this can be useful while developing

## Running the example application

Refer to the [README](/README.md) at the root of the `react-examples` repository for details on running example applications in depth. Make sure you have the Docker instance for the example applications running, then follow the quick-start steps starting in the `graphql-schema-documentation` directory:

To upload JS Classes in Brightspot (http://localhost/cms):

```sh
cd brightspot
yarn
npx brightspot types download
npx brightspot types upload src

```

To run the front-end:

```sh
cd app
yarn
yarn codegen
yarn start
```

# Step 1 Using GraphQL Explorer to View Schema Documentation

Once you have uploaded the content types, head to http://localhost/cms and go to GraphQLExplorer via the Menu, select the `GraphQL Schema Documentation Endpoint`. On the Right hand side of the Explorer, click on **Docs**. The panel will open with **Documentation Explorer**. There will be a search bar where you can search any of the content types or fields. There is also a section labeled **Root Types** which allows you to navigate through queries and operations available. Either search for `Profile` or click through the **Query** until you find profile.

Click on type **Profile** to see the content type with documentation based on the `brightspot/src/brightspot/example/graphql_schema_documentation/ProfileViewModel.ts` code. Click on each field to have a closer look at them each along with the documentation with any styling added.

# Step 2 Using React/Codegen to View Schema Documentation While Developing

The front-end React application is all set up to use **Codegen** to get the schema along with its documentation.

From the `graphql-schema-documentation/app` directory run the following command:

```
yarn codegen
```

The `codegen.yml` file will take the query included in `/components/AllProfilesQuery.graphql` as well as the schema from `http://localhost/graphql/delivery/graphql-schema-documentation` and will create a `generated.ts` file. This file will contain types and hooks based on the query.

Navigate to the `generated.ts` file in your IDE, we recommend [Visual Studio Code](https://code.visualstudio.com/Download). Highlighting any of the types and fields will display documentation to go with it. This can also be seen in the application itself. Review the code in `graphql-schema-documentation/app/src/App.tsx`:

```js
import './App.css'
import { Profile, useAllProfilesQuery } from './generated'

const App = () => {
const { loading, error, data } = useAllProfilesQuery()

if (loading) return <div>Loading...</div>
if (error) return <div>{error.message}</div>

const profilesArray = data?.AllProfiles?.ListOfProfiles

const arrayOfProfiles: Profile[] = []

profilesArray?.forEach((profile) => {
if (profile) {
const {
displayName,
favoriteSport,
favoriteBook,
favoriteFood,
favoriteSong,
}: Profile = profile

let p: Profile = {
displayName,
favoriteSport,
favoriteBook,
favoriteFood,
favoriteSong,
}
arrayOfProfiles.push(p)
}
})
return (
<div className="profiles-container">
{arrayOfProfiles.map((profile: Profile) => {
const {
displayName,
favoriteSport,
favoriteBook,
favoriteFood,
favoriteSong,
} = profile
return (
<div className="profile">
<h1>{displayName}</h1>
<h2>{favoriteBook}</h2>
<h2>{favoriteSport}</h2>
<h2>{favoriteFood}</h2>
<h2>{favoriteSong}</h2>
</div>
)
})}
</div>
)
}

export default App
```

Highlighting the variables within the **h1** and **h2** tags will display the fields documentation.

## Try it yourself

Add/Edit the documentation located in the `graphql-schema-documentation/brightspot/src/brightspot/example/graphql_schema_documentation/ProfileViewModel.ts`.
1 change: 1 addition & 0 deletions graphql-schema-documentation/app/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
REACT_APP_GRAPHQL_URL=http://localhost/graphql/delivery/graphql-schema-documentation
11 changes: 11 additions & 0 deletions graphql-schema-documentation/app/codegen.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
overwrite: true
schema: ${REACT_APP_GRAPHQL_URL}
documents: './src/components/**/*.graphql'
generates:
./src/generated.ts:
plugins:
- typescript
- typescript-operations
- typescript-react-apollo
config:
withHooks: true
51 changes: 51 additions & 0 deletions graphql-schema-documentation/app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "react-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@apollo/client": "3.6.9",
"@types/node": "16.7.13",
"@types/react": "18.0.0",
"@types/react-dom": "18.0.0",
"dotenv": "^16.0.1",
"graphql": "16.5.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-scripts": "5.0.1",
"typescript": "4.4.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"eject": "react-scripts eject",
"codegen": "graphql-codegen --require dotenv/config --config codegen.yml",
"format": "npx prettier --write src"
},
"eslintConfig": {
"extends": [
"react-app",
"prettier"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@graphql-codegen/cli": "2.8.1",
"@graphql-codegen/typed-document-node": "2.3.1",
"@graphql-codegen/typescript": "2.7.1",
"@graphql-codegen/typescript-operations": "2.5.1",
"@graphql-codegen/typescript-react-apollo": "3.3.1",
"eslint-config-prettier": "8.5.0",
"prettier": "2.7.1"
}
}
17 changes: 17 additions & 0 deletions graphql-schema-documentation/app/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="https://www.brightspot.com/favicon-32x32.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
name="description"
content="Sample App created using create-react-app"
/>
<title>Sample App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
32 changes: 32 additions & 0 deletions graphql-schema-documentation/app/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
html, body {
height: 100%;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

#root {
height: inherit;
}

.App {
margin-top: 10em;
text-align: center;
}

.profiles-container {
align-items: center;
display: flex;
height: inherit;
justify-content: center;
}

.profile {
border-radius: 8px;
box-shadow: 20px 20px 20px -15px #ee0120;
margin: 20px;
padding: 20px;
}
59 changes: 59 additions & 0 deletions graphql-schema-documentation/app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import './App.css'
import { Profile, useAllProfilesQuery } from './generated'

const App = () => {
const { loading, error, data } = useAllProfilesQuery()

if (loading) return <div className="profiles-container">Loading...</div>
if (error) return <div className="profiles-container">{error.message}</div>

const profilesArray = data?.AllProfiles?.ListOfProfiles

const arrayOfProfiles: Profile[] = []

profilesArray?.forEach((profile) => {
if (profile) {
const {
displayName,
favoriteSport,
favoriteBook,
favoriteFood,
favoriteSong,
}: Profile = profile

let p: Profile = {
displayName,
favoriteSport,
favoriteBook,
favoriteFood,
favoriteSong,
}
arrayOfProfiles.push(p)
}
})

return (
<div className="profiles-container">
{arrayOfProfiles.map((profile: Profile, index) => {
const {
displayName,
favoriteSport,
favoriteBook,
favoriteFood,
favoriteSong,
} = profile
return (
<div className="profile" key={index}>
<h1>{displayName}</h1>
<h2>{favoriteBook}</h2>
<h2>{favoriteSport}</h2>
<h2>{favoriteFood}</h2>
<h2>{favoriteSong}</h2>
</div>
)
})}
</div>
)
}

export default App
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
query AllProfiles {
AllProfiles {
ListOfProfiles: profiles {
displayName
favoriteBook
favoriteFood
favoriteSong
favoriteSport
}
}
}
15 changes: 15 additions & 0 deletions graphql-schema-documentation/app/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client'

const client = new ApolloClient({
uri: process.env.REACT_APP_GRAPHQL_URL ?? '',
cache: new InMemoryCache(),
})
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
root.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>
)
1 change: 1 addition & 0 deletions graphql-schema-documentation/app/src/react-app-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="react-scripts" />
20 changes: 20 additions & 0 deletions graphql-schema-documentation/app/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"]
}