├── .gitignore ├── .gitpod.yml ├── .vscode ├── launch.json └── settings.json ├── README.md ├── astra.json ├── graphql-backend-examples ├── .mvn │ └── wrapper │ │ ├── MavenWrapperDownloader.java │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── .project ├── .vscode │ ├── launch.json │ └── settings.json ├── HELP.md ├── bin │ └── main │ │ ├── application.properties │ │ └── com │ │ └── example │ │ └── demo │ │ └── DemoApplication.class ├── demo.zip ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ ├── DemoApplication.java │ │ │ ├── Genre.java │ │ │ ├── GenresDatafetcher.java │ │ │ ├── Show.java │ │ │ ├── ShowsDatafetcher.java │ │ │ └── ZRedirectGraphIQlController.java │ └── resources │ │ ├── application.properties │ │ └── schema │ │ └── schema.graphqls │ └── test │ └── java │ └── com │ └── example │ └── demo │ └── DemoApplicationTests.java ├── graphql-client-examples ├── .env.sample ├── README.md ├── functions │ ├── getGenresAstra.js │ ├── getGenresBackend.js │ ├── getShowsAstra.js │ └── getShowsBackend.js ├── netlify.toml ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt └── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── components │ ├── Genres.js │ ├── ReferenceList.js │ ├── Shows.js │ └── ShowsByName.js │ ├── graphql_logo.svg │ ├── index.css │ ├── index.js │ └── setupTests.js ├── hostURL.sh ├── slides └── slides.pdf └── tutorial └── images ├── NewTabOpen.png ├── create_astra_db.png ├── db-pending.png ├── dot-env-2.png ├── error_shows_by_name.png ├── gitpod-shape.png ├── graphQL_logo.png ├── graphiql-queries.png ├── graphql-CreateShowsTable.png ├── graphql-CreateShowsTable_result.png ├── graphql-badge.png ├── graphql-client-showing-shows.png ├── graphql-field-undefined-error.png ├── graphql-getallshows.png ├── graphql-insertShows.png ├── graphql-insertShows_result.png ├── graphql-playground-2b.png ├── graphql-playground-3.png ├── graphql-playground.png ├── graphql-url-ending.png ├── open-java-DGS-files-in-gitpod.png ├── open-playground-2-wh.png ├── open-playground-2.png ├── playground-1.png └── tabs-vs-playgroundtabs-labeled.png /.gitignore: -------------------------------------------------------------------------------- 1 | # nodejs 2 | node_modules 3 | .env 4 | package-lock.json 5 | 6 | # java 7 | application.properties 8 | 9 | # eclipse conf file 10 | .settings 11 | .classpath 12 | .project 13 | .cache 14 | 15 | # idea conf files 16 | .idea 17 | *.ipr 18 | *.iws 19 | *.iml 20 | 21 | # building 22 | target 23 | build 24 | tmp 25 | dist 26 | 27 | # misc 28 | .DS_Store 29 | 30 | .factorypath 31 | .sts4-cache 32 | *.log 33 | # Local Netlify folder 34 | .netlify 35 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | # We install astra-cli using the Node terminal, so that we are sure to 2 | # source astra-init there and have astra available. 3 | # On the other hand, we need to make sure mvn clean install happens cleanly 4 | # after java 17 is installed, so the sdk install is on the Java terminal. 5 | # This *should* work without nondeterministic ordering issues. 6 | tasks: 7 | - name: cors-host-config 8 | before: bash hostURL.sh 9 | command: gp open README.md 10 | - name: graphQL-Client 11 | before: | 12 | # astra-cli 13 | printf 'export PATH="$HOME%s:$PATH"\n' "/.astra/cli" >> $HOME/.bashrc 14 | printf 'unset JAVA_TOOL_OPTIONS\n' >> $HOME/.bashrc 15 | curl -Ls "https://dtsx.io/get-astra-cli-java" | bash >> ./install.log 16 | # node dependencies 17 | cd graphql-client-examples 18 | nvm install 16.13.0 19 | npm install -g npm@latest 20 | npm install astra-setup 21 | npm install -g netlify-cli 22 | npm install 23 | command: | 24 | source /home/gitpod/.astra/cli/astra-init.sh 25 | clear 26 | echo -e "\n*** workshop-intro-to-graphql gitpod ready - LET'S DO THIS! ***\n" 27 | - name: graphQL-Backend 28 | openMode: split-right 29 | before: | 30 | # REMOVE USER VALIDATION -Y ON JAVA 17 INSTALLATION 31 | sed -i '1,$s/sdkman_auto_answer=false/sdkman_auto_answer=true/' /home/gitpod/.sdkman/etc/config 32 | sed -i '1,$s/sdkman_selfupdate_enable=true/sdkman_selfupdate_enable=false/' /home/gitpod/.sdkman/etc/config 33 | # JAVA17 INSTALL 34 | sdk install java 35 | init: | 36 | # build the Java app 37 | cd graphql-backend-examples 38 | mvn clean install 39 | command: | 40 | # astra-cli 41 | unset JAVA_TOOL_OPTIONS 42 | source /home/gitpod/.astra/cli/astra-init.sh 43 | # 44 | cd graphql-backend-examples 45 | mvn spring-boot:run 46 | ports: 47 | - port: 8888 48 | onOpen: open-preview 49 | - port: 8080 50 | visibility: public 51 | onOpen: open-browser 52 | - port: 3000 53 | onOpen: ignore 54 | github: 55 | prebuilds: 56 | master: true 57 | branches: true 58 | pullRequests: true 59 | pullRequestsFromForks: false 60 | addCheck: true 61 | addComment: false 62 | addBadge: true 63 | addLabel: false 64 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "type": "java", 5 | "name": "Spring Boot-DemoApplication", 6 | "request": "launch", 7 | "cwd": "${workspaceFolder}", 8 | "console": "internalConsole", 9 | "mainClass": "com.example.demo.DemoApplication", 10 | "projectName": "demo", 11 | "args": "" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.configuration.updateBuildConfiguration": "interactive", 3 | "editor.autoSave": "on", 4 | "workbench.editor.enablePreviewFromCodeNavigation": true, 5 | "workbench.editor.enablePreviewFromQuickOpen": true, 6 | "workbench.editor.enablePreview": true, 7 | "workbench.editorAssociations": { 8 | "*.md": "vscode.markdown.preview.editor" 9 | } 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🎓 Introduction to GraphQL + React + Java + Astra DB 2 | 3 | [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/from-referrer/) 4 | [![License Apache2](https://img.shields.io/hexpm/l/plug.svg)](http://www.apache.org/licenses/LICENSE-2.0) 5 | [![Discord](https://img.shields.io/discord/685554030159593522)](https://discord.com/widget?id=685554030159593522&theme=dark) 6 | 7 | *50 minutes, Beginner/Intermediate, [Start Building](#1-login-or-register-to-astradb-and-create-database)* 8 | 9 | Both a simple **graphQL** enabled **ReactJS** app built using [**create-react-app**](https://create-react-app.dev/) AND a simple **Java** backend **graphQL** service built with [**Spring Initializr**](https://start.spring.io/) and using [**The Netflix DGS framework**](https://netflix.github.io/dgs/getting-started/) PLUS **Astra DB** hooked up and ready to rock! :heart_eyes_cat: 10 | 11 | This is a companion to our [Netflix Clone using Astra DB and GraphQL](https://github.com/datastaxdevs/appdev-week3-graphql) workshop and is essentially a "prologue" to that content. Once complete, feel free to to go deploy a Netflix clone using what you learned here. 12 | 13 | Finally, this content uses **React/JS** concepts. If you are not familiar with those or need a refresher, [take a look HERE](https://github.com/datastaxdevs/react-basics) to get up to date. 14 | 15 | The materials have been built by the DataStax developer advocates team. 16 | 17 | ![GraphQL Logo](./tutorial/images/graphQL_logo.png) 18 | 19 | ## 🎯 Objectives 20 | * An overview of what GraphQL is and what makes it cool 21 | * What differs between GraphQL and other APIs (such as REST), including their pros/cons 22 | * Hands-on examples of GraphQL queries and mutations 23 | * How to build GraphQL APIs for mobile and web applications 24 | * Setting up your Astra DB to store application data via GraphQL 25 | 26 | ## ℹ️ Frequently asked questions ℹ️ 27 | 28 |

29 |

30 | 1️⃣ Can I run the code for this workshop on my local computer instead of using Gitpod? 31 |
32 |

There is nothing preventing you from running the workshop on your own machine. If you do so, you will need the following: 33 |

    34 |
  1. node 15 or 16 and npm 7 or later
  2. 35 |
  3. netlify-cli (use "npm install -g netlify-cli")
  4. 36 |
37 |

38 | You will have to adapt commands and paths based on your environment (including digging into file ".gitpod.yml") and install the dependencies by yourself. We won't provide support to keep on track with schedule. However, we will do our best to give you the info you need to be successful. This is considered a more advanced path to take. 39 |
40 |

41 |

42 | 2️⃣ What other prerequisites are there? 43 |
44 | 49 |

50 |
51 |

52 |

53 | 3️⃣ Do I need to pay for anything for this workshop? 54 |
55 | No. All tools and services we provide here are FREE. FREE not only during the session but also afterwards. 56 |
57 |

58 |

59 | 4️⃣ Will I get a certificate if I attend this workshop? 60 |
61 | Attending the session is not enough. You need to complete the homework detailed below and you will get a nice badge that you can share on linkedin or anywhere else (open badge specification). 62 |
63 |

64 | 65 | 66 | ## Materials for the Session 67 | 68 | It doesn't matter if you join our workshop live or you prefer to do at your own pace, we have you covered. In this repository, you'll find everything you need for this workshop: 69 | 70 | - [Slide deck](./slides/slides.pdf) 71 | - [Discord chat](https://bit.ly/cassandra-workshop) 72 | - ["cassandra" on StackOverflow](https://stackoverflow.com/questions/tagged/cassandra) 73 | - ["cassandra" on DBA StackExchange](https://dba.stackexchange.com/questions/tagged/cassandra) 74 | 75 | ## Homework 76 | 77 | 78 | 79 | Don't forget to complete your upgrade and get your verified skill badge! Finish and submit your homework! 80 | 81 | 1. Complete the practice steps from this repository, as described below, to the end; 82 | 2. Insert (mutate) a **new show** or a **new genre** of your choice in the database; 83 | 3. Take a single **screenshot** of the React app with all of the working Astra DB sections and showing the entry you just added; 84 | 4. Submit your homework [here](https://dtsx.io/homework-intro-graphql). 85 | 86 | That's it, done. 87 | We will then grade the submissions: expect an email in a few days! 88 | 89 | # Let's start 90 | 91 | 92 | ### Extra resources 93 | [graphql.org](https://graphql.org/) - The first place to learn about GraphQL 94 | 95 | [The Netflix DGS framework Tutorial](https://netflix.github.io/dgs/getting-started/) - Java/Spring GraphQL backend (used to generate this code) 96 | 97 | [Spring Initializr](https://start.spring.io/) - Used in the ^above tutorial to generate the Java/Spring backend starter 98 | 99 | [GraphiQL](https://www.gatsbyjs.com/docs/how-to/querying-data/running-queries-with-graphiql/) - GraphQL IDE included with The Netflix DGS Framework 100 | 101 | [Apollo client](https://www.apollographql.com/docs/react/) - Awesome GraphQL client for React/JS (not used here, but really solid, Netflix uses this) 102 | 103 | [Top 7 GraphQL IDEs](https://hasura.io/blog/top-7-graphql-ides-you-should-know-about-in-2021/) - A nice collection of cool GraphQL IDEs to use 104 | 105 | [create-react-app tutorial](https://create-react-app.dev/) - Create a React app from scratch (used to generate this code) 106 | 107 | [A Beginner's Guide to GraphQL](https://www.youtube.com/watch?v=c2fJ7T0N1Sk) - Ali Spittel's really awesome GraphQL starter video 108 | 109 | 110 | 111 | ## 1. Login or Register to Astra DB and create database 112 | 113 | _**`ASTRA DB`** is the simplest way to run Cassandra with zero operations at all - just push the button and get your cluster. No credit card required, 40M read/write operations and about 80GB storage monthly for free - sufficient to run small production workloads. If you use up your credits the databases will pause, no charge, and you will be given the option to upgrade to a higher tier._ 114 | 115 | Leveraging [Database creation guide](https://awesome-astra.github.io/docs/pages/astra/create-instance/#c-procedure) create a database. *Right-Click the following button* with *Open in a new TAB.* 116 | 117 | 118 | 119 | |Field|Value| 120 | |---|---| 121 | |**Database Name**| `workshops`| 122 | |**Keyspace Name**| `intrographql`| 123 | |**Regions**| Select `GOOGLE CLOUD`, then an Area close to you, then a region with no LOCK 🔒 icons: the LOCKed regions are the region not accessible to the Free Tier. 124 | 125 | > **ℹ️ Note:** If you already have a database `workshops`, simply add a keyspace `intrographql` using the `Add Keyspace` button on the bottom right hand corner of the DB Dashboard page. You may have to "Resume" the database first in case it is in "hibernated" state. 126 | 127 | While the database is being created, you will also get a **Security token** (needed to authenticate with your database and start using it): 128 | **please IGNORE THIS ONE, as we will be soon creating a new, more powerful token for today**. 129 | 130 | The status will change from `Pending` to `Active` when the database is ready, this usually only takes 2-3 minutes. 131 | 132 | 133 | 134 | ## 2. Create a security token 135 | 136 | > Note: this step is very important, as the token generated automatically for you with 137 | > the database lacks some permissions we'll use in the workshop. 138 | 139 | [Create a token for your app](https://awesome-astra.github.io/docs/pages/astra/create-token/#c-procedure), _using the **"Database Administrator"** role_. 140 | Keep it handy for later use (best to download it in CSV format, as the values 141 | will not be visible afterward). 142 | This will provide authentication later when interacting with the database. 143 | Today, in particular, we will need the string labeled "token" (the one starting with `AstraCS:...`). 144 | 145 | > **⚠️ Important** 146 | > ``` 147 | > The instructor will show the token creation on screen, 148 | > but will then destroy it immediately for security reasons. 149 | > ``` 150 | 151 | ## 3. Launch Gitpod 152 | 153 | [Gitpod](https://www.gitpod.io/) is an 100% online IDE based on [Visual Studio Code](https://github.com/gitpod-io/vscode/blob/gp-code/LICENSE.txt?lang=en-US). To initialize your environment simply click on the button below _(CTRL + Click to open in new tab)_ You will be asked for you github account, as needed. 154 | 155 | **Warning**: for best results, open the link with Chrome or Firefox! 156 | 157 | [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/datastaxdevs/workshop-intro-to-graphql) 158 | 159 | 160 | This will bootstrap your demo environment. Be patient, it will take a few minutes as everything loads up. 161 | 162 | > **Note**: during loading of the Gitpod environment, a new tab will be tentatively opened 163 | > with an URL such as `https://8080-datastaxdev-[...].gitpod.io/graphiql`. 164 | > Please **CHECK YOUR POPUP BLOCKER** and allow it before continuing: this will be your GraphiQL interface! 165 | 166 |

167 | Show me how Gitpod looks like for this workshop 168 | 169 | Gitpod starts with a file explorer on the left (1), an editor panel on the top (2), 170 | and - in the case of this specific environment - two consoles side by side, 171 | one to launch commands and later start the Node app (3) and one busy with 172 | running the Java backend (4). On the right you will find a console switcher to 173 | easily locate any console and make it active (but even just clicking 174 | on the desired console would do the trick). 175 | 176 | ![The shape of Gitpod](tutorial/images/gitpod-shape.png) 177 | 178 |
179 | 180 | 181 | ## 4. Experiment with GraphiQL 182 | It just so happens that [The Netflix DGS framework](https://netflix.github.io/dgs/getting-started/) comes with GraphiQL already integrated and ready for use. This is a wonderful tool you can use to explore graphQL queries and mutations. Let's experiment with this now! 183 | 184 | > _Note:_ the GraphiQL should be open already in a new tab for you; in case it isn't for some reason, 185 | > run this command in a Gitpod console and manually point a new tab to the URL it prints:```echo `gp url 8080`/graphiql```. 186 | 187 | Something to point out here is there is no database just yet. We are powering the graphQL schema via the back-end Java application and the graphQL data is completely hardcoded. 188 | Take a look at both **`ShowsDatafetcher.java`** and **`GenresDatafetcher.java`** located in **`graphql-backend-examples/src/main/java/com/example/demo`** 189 | to find the simple implementations using DGS annotations `@DgsComponent` and `@DgsQuery`. 190 | 191 |
192 | Show me how to open these files in Gitpod 193 | 194 | In the left toolbar, choose the first tool ("Explorer") and navigate the directory to the desired directory; then, clicking on the files will open them in the editor (topmost panel on the right). 195 | 196 | ![Open files in Gitpod](tutorial/images/open-java-DGS-files-in-gitpod.png) 197 | 198 |
199 | 200 | 201 | #### Now, let's try out some graphQL queries 202 | Plug these into the GraphiQL IDE that launched into a new tab from GitPod. 203 | 204 | ```GraphQL 205 | query justTitle { 206 | shows { 207 | title 208 | } 209 | } 210 | ``` 211 | 212 | ```GraphQL 213 | query withReleaseYear { 214 | shows { 215 | title 216 | releaseYear 217 | } 218 | } 219 | ``` 220 | 221 | ```GraphQL 222 | query getOneShow { 223 | shows (titleFilter: "Ozark") { 224 | title 225 | releaseYear 226 | } 227 | } 228 | ``` 229 | 230 | ```GraphQL 231 | query ShowsAndGenres { 232 | shows { 233 | title 234 | releaseYear 235 | } 236 | genres { 237 | value 238 | } 239 | } 240 | ``` 241 | 242 | ![GraphiQL queries](tutorial/images/graphiql-queries.png) 243 | 244 | #### Compare the GraphQL schema 245 | 246 | The objects known to a GraphQL API are defined starting from its "Schema". 247 | In the case of our DGS Java application, the schema is found in 248 | `graphql-backend-examples/src/main/resources/schema/schema.graphqls`. 249 | Take a look at its contents: notice the special `Query` item that defines 250 | the possible queries and, after that, the user-defined types available to 251 | the API: 252 | 253 | ```GraphQL 254 | type Query { 255 | shows(titleFilter: String): [Show] 256 | genres(labelFilter: String): [Genre] 257 | } 258 | 259 | type Show { 260 | title: String 261 | releaseYear: Int 262 | } 263 | 264 | type Genre { 265 | value: String! 266 | } 267 | ``` 268 | 269 | ## 5. Experiment with Astra DB's GraphQL Playground 270 | 271 | Ok, let's take this a step further and prepare the data layer for our app. 272 | At this point you should have already [created your Astra DB database](#1-login-or-register-to-astradb-and-create-database). 273 | Follow the instructions below to launch the **GraphQL Playground** provided in **Astra DB**: 274 | 275 | #### ✅ Step 5a: Open GraphQL Playground: 276 | 277 | 0. Ensure you are logged on to your [Astra](https://astra.datastax.com) account 278 | 1. Click on the "workshops" database on the left (expanding the list if needed) 279 | 2. Click `Connect` TAB 280 | 3. Click the `APIs` connection method 281 | 4. Make sure `GraphQL API` is selected 282 | 5. Locate the link to your GraphQL Playground in the text 283 | 284 | ![Open Astra DB GraphQL Playground image](tutorial/images/open-playground-2.png) 285 | 286 |
287 | Click here if you are using the "New Astra Experience" UI 288 | 289 | ![Open Astra DB GraphQL Playground image, new Astra UI](tutorial/images/open-playground-2-wh.png) 290 | 291 |
292 | 293 | **Note**: in the following, we will refer to "playground tabs". These are _not_ the tabs 294 | in your browser, rather they are tabs _within_ the Playground application, 295 | to switch between the (logically distinct) realms of "managing schema" and "managing data in the tables" 296 | (more on that later). 297 | 298 | ![Playground tabs VS Browser tabs](tutorial/images/tabs-vs-playgroundtabs-labeled.png) 299 | 300 | #### ✅ Step 5b: Insert the Astra DB Token to run schema queries 301 | 302 | In the GraphQL Playground, **Populate HTTP HEADER** variable `x-cassandra-token` on the bottom of the page with your token (including the `AstraCS:` part). 303 | _This is the "Database Administrator" token you created earlier on the Astra DB dashboard (Step 2 above)._ 304 | 305 | **Note**: make sure you are on the **`graphql-schema`** playground tab in this step, as this image illustrates: 306 | 307 | ![GraphQL Playground and token header, Schema playground tab](tutorial/images/graphql-playground.png) 308 | 309 | > Note: the GraphQL Playground starts with a ready-to-use _temporary token_ as the `x-cassandra-token` header. But we want the queries run in the Playground 310 | > to be identical to those that the Netlify functions will run from code, so **please replace the token with your DB token as instructed**. 311 | 312 | #### ✅ Step 5c: Create a table in the GraphQL Playground 313 | 314 | Run the following mutation in the `graphql-schema` playground tab, making sure to replace `intrographql` in the URL if you used a different keyspace name: 315 | 316 | - Copy the following mutation on the left panel 317 | 318 | ```GraphQL 319 | mutation { 320 | reference_list: createTable( 321 | keyspaceName:"intrographql", 322 | tableName:"reference_list", 323 | ifNotExists:true 324 | partitionKeys: [ 325 | { name: "label", type: {basic: TEXT} } 326 | ] 327 | clusteringKeys: [ 328 | { name: "value", type: {basic: TEXT}, order: "ASC" } 329 | ] 330 | ) 331 | } 332 | ``` 333 | 334 | Click on the arrow in the middle of the screen to execute the query. 335 | 336 | ![Execute a query in GraphQL Playground](tutorial/images/playground-1.png) 337 | 338 | ## 6. Insert data to DB using the GraphQL Playground 339 | 340 | #### ✅ Step 6a: Adjust the second playground tab to your keyspace 341 | 342 | In the GraphQL playground, switch to the second Playground tab (`graphql`). Edit the ending of the URL _shown within the Playground page_ from `system` to the keyspace name `intrographql`: 343 | 344 | ![GraphQL URL ending](tutorial/images/graphql-url-ending.png) 345 | 346 | #### ✅ Step 6b: Set the token to run data queries 347 | 348 | Populate the **HTTP HEADER** variable `x-cassandra-token` on the bottom of the page with your DB token as shown below _(Note: you did this for the `graphql-schema` playground tab, now repeat for the `graphql` playground tab!)_ 349 | 350 | ![GraphQL Playground and token header, GraphQL playground tab](tutorial/images/graphql-playground-2b.png) 351 | 352 | #### ✅ Step 6c: Insert genre names with the Playground 353 | 354 | In the GraphQL Playground, populate the `reference_list` table with all values: 355 | copy the following mutation on the left panel 356 | 357 | ```GraphQL 358 | mutation insertGenres { 359 | action: insertreference_list(value: {label:"genre", value:"Action"}) { 360 | value{value} 361 | } 362 | anime: insertreference_list(value: {label:"genre", value:"Anime"}) { 363 | value{value} 364 | } 365 | award: insertreference_list(value: {label:"genre", value:"Award-Winning"}) { 366 | value{value} 367 | } 368 | children: insertreference_list(value: {label:"genre", value:"Children & Family"}) { 369 | value{value} 370 | } 371 | comedies: insertreference_list(value: {label:"genre", value:"Comedies"}) { 372 | value{value} 373 | } 374 | documentaries: insertreference_list(value: {label:"genre", value:"Documentaries"}) { 375 | value{value} 376 | } 377 | drama: insertreference_list(value: {label:"genre", value:"Dramas"}) { 378 | value{value} 379 | } 380 | fantasy: insertreference_list(value: {label:"genre", value:"Fantasy"}) { 381 | value{value} 382 | } 383 | french: insertreference_list(value: {label:"genre", value:"French"}) { 384 | value{value} 385 | } 386 | horror: insertreference_list(value: {label:"genre", value:"Horror"}) { 387 | value{value} 388 | } 389 | independent: insertreference_list(value: {label:"genre", value:"Independent"}) { 390 | value{value} 391 | } 392 | music: insertreference_list(value: {label:"genre", value:"Music & Musicals"}) { 393 | value{value} 394 | } 395 | romance: insertreference_list(value: {label:"genre", value:"Romance"}) { 396 | value{value} 397 | } 398 | scifi: insertreference_list(value: {label:"genre", value:"Sci-Fi"}) { 399 | value{value} 400 | } 401 | thriller: insertreference_list(value: {label:"genre", value:"Thriller"}) { 402 | value{value} 403 | } 404 | } 405 | ``` 406 | 407 | Click on the arrow in the middle of the screen to execute the query. 408 | 409 | ## 7. Retrieve values from DB using the GraphQL Playground 410 | 411 | #### ✅ Step 7a: Read genres with a query in the Playground 412 | 413 | In the GraphQL Playground (staying on the `graphql` playground tab), list values from the table with the following query: 414 | 415 | ```yaml 416 | query getAllGenre { 417 | reference_list (value: {label:"genre"}) { 418 | values { 419 | value 420 | } 421 | } 422 | } 423 | ``` 424 | 425 | *👁️ Expected output* 426 | ![Playground getAllGenre query result](tutorial/images/graphql-playground-3.png) 427 | 428 | ## 8. Start up React 429 | 430 | So far we have executed GraphQL queries and mutations by hand from specific UIs. 431 | Now it's time to start the React client app and query the GraphQL endpoints from it! 432 | 433 | > "Endpoints", two of them. Each GraphQL server exposes a single endpoint for everything, 434 | > but remember this app will query both the local DGS app and the Astra DB server! 435 | 436 | First you need to run a couple commands to get things set up: 437 | in your **`GitPod`** IDE navigate to the "Client" terminal 438 | *(it should already be open for you on the bottom left)* 439 | and make sure you are in the **`workshop-intro-to-graphql/graphql-client-examples`** directory. 440 | **This is where you'll be running the nodejs/React app.** 441 | 442 |
443 | Remind me what is this "client terminal" ... 444 | 445 | It is the block labeled as "3". Click on it, or use the switcher (5): 446 | 447 | ![The shape of Gitpod](tutorial/images/gitpod-shape.png) 448 | 449 |
450 | 451 | #### ✅ Step 8a: Execute the following command 452 | ```shell 453 | npm install -g netlify-cli 454 | ``` 455 | 456 | This will install the **Netlify CLI** (command line interface) which our **React/JS** app uses in conjunction with the serverless functions we've setup to talk to our **graphQL** endpoints. 457 | 458 | #### ✅ Step 8b: Then, execute 459 | ```shell 460 | netlify dev 461 | ``` 462 | 463 | This will start the **React/JS** application and display results from both the **`Shows`** and **`Genres`** **graphQL** queries and endpoints we were just experimenting with. 464 | 465 | You should see Gitpod's mini-browser opening up by itself and showing the client application wihtin Gitpod. 466 | 467 | > _Note:_ the client, at this point, should be opened in the mini-browser within Gitpod; to open it manually, 468 | > run this command in a Gitpod console and point a new tab to the URL it prints:```echo `gp url 8888` ```. 469 | 470 | #### Compare javascript code to our graphQL queries from above 471 | If you take a look at both **`getShowsBackend.js`** and **`getGenresBackend.js`** located in **`graphql-client-examples/functions`** you should notice that both use the **same exact** **graphQL** queries that we used above. 472 | 473 | ```javascript 474 | const query = ` 475 | query getAllShows { 476 | shows { 477 | title 478 | releaseYear 479 | } 480 | } 481 | ` 482 | ``` 483 | 484 | ```javascript 485 | const query = ` 486 | query getAllGenres { 487 | genres { 488 | value 489 | } 490 | } 491 | ` 492 | ``` 493 | 494 | All of the javascript wrapped around these is simply there to call the **graphQL** endpoint with the given query and pass the responseBody back to the calling function. 495 | 496 | #### Now for the cool part 497 | 498 | Take a look at **`Shows.js`** and **`Genres.js`** located in **`graphql-client-examples/src/components/`**. In both cases they use **React** state, `gqlResult` 499 | 500 | ```javascript 501 | const [gqlResult, setGqlResult] = useState(null) 502 | ``` 503 | 504 | to receive the responseBody from from our **graphQL** queries, set the **React** state, and inject the values dynamically into the DOM. Check out the following javascript snippet from **`Shows.js`**. 505 | 506 | ```javascript 507 | // Asynchronously fetch any "shows" graphQL data from the Java backend 508 | // using the getShowsBackend serverless function to call out to the 509 | // Netflix DGS Java graphQL endpoint 510 | const response = await fetch("/.netlify/functions/getShowsBackend", { 511 | method: "POST", 512 | }) 513 | const responseBody = await response.json() 514 | setGqlResult(responseBody) // on response set our graphQL result state 515 | ``` 516 | 517 | Notice how the fields (title, releaseYear) match our **graphQL** `Shows` schema exactly. 518 | 519 | ```javascript 520 | // Finally, if all other checks pass get the data 521 | // from the payload via gqlResult state and inject it into the DOM 522 | // Notice how the payload example below and the fields "title" and "releaseYear" match exactly 523 | // {"data":{"shows":[{"title":"Stranger Things","releaseYear":2016},{"title":"Ozark","releaseYear":2017}... 524 | return gqlResult.data.shows.map(({ title, releaseYear }) => ( 525 |
526 |

527 | {title}: {releaseYear} 528 |

529 |
530 | )); 531 | ``` 532 | 533 | Notice how the field (value) matches our **graphQL** `Genres` schema exactly. 534 | 535 | ```javascript 536 | // Finally, if all other checks pass get the data 537 | // from the payload via gqlResult state and inject it into the DOM 538 | // Notice how the payload example below and the field "value" match exactly 539 | // {"data":{"genres":[{"value":"Action"},{"value":"Anime"}... 540 | return gqlResult.data.genres.map(({ value }) => ( 541 |
542 |

543 | {value} 544 |

545 |
546 | )); 547 | ``` 548 | 549 | ## 9. Hook the database up to the React client app 550 | 551 | The next step is to make the client able to retrieve the genres and the shows 552 | from the database, by querying Astra DB's GraphQL API. To achieve this, 553 | it's time to provide connection details (addresses, secrets) to the 554 | serverless Netlify functions which will back the React client. 555 | 556 | #### ✅ Step 9a: Initialize Astra CLI 557 | In the **`GitPod`** IDE, click on the "Client" terminal to make it active, hit `Ctrl-C` to stop the running client, if any, and make sure you are in the **`workshop-intro-to-graphql/graphql-client-examples`** directory. 558 | 559 | Now you will create a `.env` file with connection info (addresses and secrets) for the Netlify function to be able to reach both the local backend and your Astra DB's GraphQL endpoint. 560 | You will use the Astra command-line interface to prepare a dot-env file for you; then you will complete it by adding a line defining the address of the local backend (i.e. the DGS locally-running GraphQL API). 561 | 562 | Run the following command and provide your **DB Administrator** token string (starting with `AstraCS:...`) when prompted: 563 | 564 | ``` 565 | astra setup 566 | ``` 567 | 568 | #### ✅ Step 9b: Configure database credentials 569 | 570 | Once you get a "Configuration has been saved" confirmation, proceed with: 571 | 572 | ``` 573 | astra db create-dotenv workshops -k intrographql 574 | cat .local-backend.env >> .env 575 | gp open .env 576 | ``` 577 | 578 | The credentials are now all set up: your dot-env file should be now shown in the editor for you to check its contents. 579 | You will see several lines pertaining to Astra DB (not all of which will be used by today's client) 580 | and, at the end, a single setting about the Java GraphQL API you tested earlier. 581 | 582 | Here is how the `.env` might look like (as a reference, check out the provided `.env.sample`): 583 | 584 | ![Sample dot-env file](tutorial/images/dot-env-2.png) 585 | 586 | > If you are preparing the file manually (i.e. as opposed to using the `astra-cli` tool), be aware that the only 587 | > variables needed by the React client are: `ASTRA_DB_APPLICATION_TOKEN`, `ASTRA_DB_GRAPHQL_URL` 588 | > and `JAVA_GRAPHQL_ENDPOINT`. 589 | 590 | #### ✅ Step 9c: Start your React app again 591 | 592 | Launch the following command once more: 593 | ```shell 594 | netlify dev 595 | ``` 596 | 597 | #### ✅ Step 9d: Verify data load 598 | At this point your app should be running with a bunch of data displayed in the **`Shows`**, **`Genres,`** and **`ReferenceList`** sections, but notice the **`ShowsByName`** section displays **"Error :("** 599 | 600 | ![Error in Shows by name](tutorial/images/error_shows_by_name.png) 601 | 602 | #### Can you figure out what's going on here? 603 | Let's break this down. 604 | 605 | * We just added the database configuration and the **`ReferenceList`** section is populated which tells us our DB config and graphQL endpoints are configured properly 606 | 607 | * In the GraphQL Playground we added a schema for the **`reference_list`** table and added some data to the table, but we never created a schema for the **`ShowsByName`** section 608 | 609 | * If you take a look at the **`getShowsAstra.js`** script in **`graphql-client-examples/functions`** you can see the graphQL being used to query for data 610 | ```javascript 611 | exports.handler = async function (event) { 612 | const query = ` 613 | query getAllShows { 614 | show_by_name { 615 | values { 616 | title 617 | releaseYear 618 | } 619 | } 620 | } 621 | ` 622 | ``` 623 | 624 | #### ✅ Step 9e: Test this query 625 | 626 | Go back to the GraphQL **`graphQL`** playground tab. 627 | 628 | Copy this into the playground and press the _"play"_ button to execute the query. **NOTE, you can simply append the query to the end of the list and then choose the query you wish to execute when you hit the "play" button.** 629 | 630 | ```GraphQL 631 | query getAllShows { 632 | show_by_name { 633 | values { 634 | title 635 | releaseYear 636 | } 637 | } 638 | } 639 | ``` 640 | 641 | ![GraphQL getAllShows execution](tutorial/images/graphql-getallshows.png) 642 | 643 | #### View Results 644 | Notice what happened here. We have a validation error because there is no schema associated with the query we just executed. GraphQL uses a typed validation system so this is something to expect if a query is malformed, missing a schema, or something along those lines. You will want to control for this in your code. 645 | 646 | ![GraphQL "Field undefined" error](tutorial/images/graphql-field-undefined-error.png) 647 | 648 | #### ✅ Step 9f: Create the missing table 649 | 650 | To fix up the schema issue, and resolve the error, 651 | create the **`ShowsByName`** table with a graphQL mutation to fix the app. 652 | Execute the following mutation in the **`graph-schema`** Playground tab 653 | 654 | ```GraphQL 655 | mutation CreateShowsTable { 656 | createTable( 657 | keyspaceName: "intrographql" 658 | tableName: "show_by_name" 659 | partitionKeys: [{ 660 | name: "title", type: {basic:TEXT} 661 | }] 662 | values:[{ 663 | name: "releaseYear", type: {basic:INT} 664 | }] 665 | ) 666 | } 667 | ``` 668 | 669 | ![GraphQL CreateShowsTable query](tutorial/images/graphql-CreateShowsTable.png) 670 | 671 | #### ✅ Verify result 672 | Once executed you should see a result like this 673 | 674 | ![GrahQL CreateShowsTable result](tutorial/images/graphql-CreateShowsTable_result.png) 675 | 676 | #### ✅ Step 9g: Add some data 677 | Now, go back to the **`graphql`** playground tab and add the following mutation 678 | ```GraphQL 679 | mutation insertShows { 680 | stranger: insertshow_by_name ( 681 | value: { 682 | title: "Stranger Things", 683 | releaseYear: 2016}) { 684 | value{title} 685 | } 686 | ozark: insertshow_by_name ( 687 | value: { 688 | title: "Ozark", 689 | releaseYear: 2017}) { 690 | value{title} 691 | } 692 | } 693 | ``` 694 | 695 | ![GraphQL "insertShows"](tutorial/images/graphql-insertShows.png) 696 | 697 | #### ✅ Check the result 698 | 699 | ![GraphQL insertShows, result](tutorial/images/graphql-insertShows_result.png) 700 | 701 | #### ✅ Step 9h: Check the client again 702 | 703 | Finally, refresh your React app. 704 | 705 | Notice this no longer displays an error. Now it correctly displays the data you just inserted (mutated). It might be fun to add some of your own data to this schema and refresh your page. 706 | 707 | ![GraphQL, client showing shows from DB](tutorial/images/graphql-client-showing-shows.png) 708 | 709 | #### Play a bit more! 710 | 711 | Feel free to experiment with a couple more graphQL queries now that you have some data in the table 712 | 713 | Queries usually offer some way to restrict the results returned, 714 | in the form of parameters passed to queries. Recall the original `getAllShows`, repeated here for convenience: 715 | 716 | 717 | ```GraphQL 718 | query getAllShows { 719 | show_by_name { 720 | values { 721 | title 722 | releaseYear 723 | } 724 | } 725 | } 726 | ``` 727 | 728 | Now let's see a way to pass a `title` parameter to the query and just get 729 | matching values (a single entry, in this case): 730 | 731 | ```GraphQL 732 | query getOneShow { 733 | show_by_name (value: {title: "Ozark"}) { 734 | values { 735 | title 736 | releaseYear 737 | } 738 | } 739 | } 740 | ``` 741 | 742 | The following query, which uses the [more general `filter` syntax](https://docs.datastax.com/en/astra/docs/develop/dev-with-graphql-cql-first.html#_retrieve_data), 743 | is completely equivalent to the previous one: 744 | 745 | ```GraphQL 746 | query getOneShowF { 747 | show_by_name(filter: {title: {eq: "Ozark"}}){ 748 | values { 749 | title 750 | releaseYear 751 | } 752 | } 753 | } 754 | ``` 755 | 756 | 757 | ### That's it, you did it! Nice job! 758 | 759 | We hope this workshop gave you enough information on GraphQL to be dangerous and start you on a journey to using GraphQL in your own apps. 760 | Also, don't forget your [HOMEWORK](#homework). 761 | -------------------------------------------------------------------------------- /astra.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Introduction to GraphQL", 3 | "description": "Learn the basics of GraphQL. Plenty of hands-on experience covering: a React client interacting with Astra DB using the Netlify stack; usage of playgrounds and tooling; running your own Java GraphQL backend based on the Netflix DGS framework.", 4 | "duration": "120 minutes", 5 | "skillLevel": "Beginner", 6 | "language":["java", "javascript", "nodejs"], 7 | "stack": ["cassandra", "jamstack", "netlify"], 8 | "githubUrl": "https://github.com/datastaxdevs/workshop-intro-to-graphql", 9 | "badge": "https://media.badgr.com/uploads/badges/6d9d20f0-8a8e-4cc9-9cf2-dc4e1baa97d6.png", 10 | "youTubeUrl": ["https://www.youtube.com/watch?v=Z83XTWhav7g"], 11 | "tags": [ 12 | { "name": "workshop" }, 13 | { "name": "nosql" }, 14 | { "name": "cassandra" }, 15 | { "name": "graphql" }, 16 | { "name": "gitpod" }, 17 | { "name": "astradb" } 18 | ], 19 | "category": "workshop", 20 | "usecases": [] 21 | } -------------------------------------------------------------------------------- /graphql-backend-examples/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.6"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /graphql-backend-examples/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/graphql-backend-examples/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /graphql-backend-examples/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /graphql-backend-examples/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | demo 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | org.springframework.ide.eclipse.boot.validation.springbootbuilder 20 | 21 | 22 | 23 | 24 | 25 | org.eclipse.jdt.core.javanature 26 | org.eclipse.m2e.core.maven2Nature 27 | 28 | 29 | 30 | 1631126904356 31 | 32 | 30 33 | 34 | org.eclipse.core.resources.regexFilterMatcher 35 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /graphql-backend-examples/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "type": "java", 5 | "name": "Spring Boot-DemoApplication", 6 | "request": "launch", 7 | "cwd": "${workspaceFolder}", 8 | "console": "internalConsole", 9 | "mainClass": "com.example.demo.DemoApplication", 10 | "projectName": "demo", 11 | "args": "" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /graphql-backend-examples/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.configuration.updateBuildConfiguration": "interactive" 3 | } -------------------------------------------------------------------------------- /graphql-backend-examples/HELP.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ### Reference Documentation 4 | For further reference, please consider the following sections: 5 | 6 | * [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) 7 | * [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.5.4/maven-plugin/reference/html/) 8 | * [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.5.4/maven-plugin/reference/html/#build-image) 9 | * [Spring Web](https://docs.spring.io/spring-boot/docs/2.5.4/reference/htmlsingle/#boot-features-developing-web-applications) 10 | 11 | ### Guides 12 | The following guides illustrate how to use some features concretely: 13 | 14 | * [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) 15 | * [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) 16 | * [Building REST services with Spring](https://spring.io/guides/tutorials/bookmarks/) 17 | 18 | -------------------------------------------------------------------------------- /graphql-backend-examples/bin/main/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /graphql-backend-examples/bin/main/com/example/demo/DemoApplication.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/graphql-backend-examples/bin/main/com/example/demo/DemoApplication.class -------------------------------------------------------------------------------- /graphql-backend-examples/demo.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/graphql-backend-examples/demo.zip -------------------------------------------------------------------------------- /graphql-backend-examples/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | fi 118 | 119 | if [ -z "$JAVA_HOME" ]; then 120 | javaExecutable="`which javac`" 121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 122 | # readlink(1) is not available as standard on Solaris 10. 123 | readLink=`which readlink` 124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 125 | if $darwin ; then 126 | javaHome="`dirname \"$javaExecutable\"`" 127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 128 | else 129 | javaExecutable="`readlink -f \"$javaExecutable\"`" 130 | fi 131 | javaHome="`dirname \"$javaExecutable\"`" 132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 133 | JAVA_HOME="$javaHome" 134 | export JAVA_HOME 135 | fi 136 | fi 137 | fi 138 | 139 | if [ -z "$JAVACMD" ] ; then 140 | if [ -n "$JAVA_HOME" ] ; then 141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 142 | # IBM's JDK on AIX uses strange locations for the executables 143 | JAVACMD="$JAVA_HOME/jre/sh/java" 144 | else 145 | JAVACMD="$JAVA_HOME/bin/java" 146 | fi 147 | else 148 | JAVACMD="`which java`" 149 | fi 150 | fi 151 | 152 | if [ ! -x "$JAVACMD" ] ; then 153 | echo "Error: JAVA_HOME is not defined correctly." >&2 154 | echo " We cannot execute $JAVACMD" >&2 155 | exit 1 156 | fi 157 | 158 | if [ -z "$JAVA_HOME" ] ; then 159 | echo "Warning: JAVA_HOME environment variable is not set." 160 | fi 161 | 162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 163 | 164 | # traverses directory structure from process work directory to filesystem root 165 | # first directory with .mvn subdirectory is considered project base directory 166 | find_maven_basedir() { 167 | 168 | if [ -z "$1" ] 169 | then 170 | echo "Path not specified to find_maven_basedir" 171 | return 1 172 | fi 173 | 174 | basedir="$1" 175 | wdir="$1" 176 | while [ "$wdir" != '/' ] ; do 177 | if [ -d "$wdir"/.mvn ] ; then 178 | basedir=$wdir 179 | break 180 | fi 181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 182 | if [ -d "${wdir}" ]; then 183 | wdir=`cd "$wdir/.."; pwd` 184 | fi 185 | # end of workaround 186 | done 187 | echo "${basedir}" 188 | } 189 | 190 | # concatenates all lines of a file 191 | concat_lines() { 192 | if [ -f "$1" ]; then 193 | echo "$(tr -s '\n' ' ' < "$1")" 194 | fi 195 | } 196 | 197 | BASE_DIR=`find_maven_basedir "$(pwd)"` 198 | if [ -z "$BASE_DIR" ]; then 199 | exit 1; 200 | fi 201 | 202 | ########################################################################################## 203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 204 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 205 | ########################################################################################## 206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 207 | if [ "$MVNW_VERBOSE" = true ]; then 208 | echo "Found .mvn/wrapper/maven-wrapper.jar" 209 | fi 210 | else 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 213 | fi 214 | if [ -n "$MVNW_REPOURL" ]; then 215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 216 | else 217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 218 | fi 219 | while IFS="=" read key value; do 220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 221 | esac 222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 223 | if [ "$MVNW_VERBOSE" = true ]; then 224 | echo "Downloading from: $jarUrl" 225 | fi 226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 227 | if $cygwin; then 228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 229 | fi 230 | 231 | if command -v wget > /dev/null; then 232 | if [ "$MVNW_VERBOSE" = true ]; then 233 | echo "Found wget ... using wget" 234 | fi 235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 236 | wget "$jarUrl" -O "$wrapperJarPath" 237 | else 238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" 239 | fi 240 | elif command -v curl > /dev/null; then 241 | if [ "$MVNW_VERBOSE" = true ]; then 242 | echo "Found curl ... using curl" 243 | fi 244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 245 | curl -o "$wrapperJarPath" "$jarUrl" -f 246 | else 247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 248 | fi 249 | 250 | else 251 | if [ "$MVNW_VERBOSE" = true ]; then 252 | echo "Falling back to using Java to download" 253 | fi 254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 255 | # For Cygwin, switch paths to Windows format before running javac 256 | if $cygwin; then 257 | javaClass=`cygpath --path --windows "$javaClass"` 258 | fi 259 | if [ -e "$javaClass" ]; then 260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 261 | if [ "$MVNW_VERBOSE" = true ]; then 262 | echo " - Compiling MavenWrapperDownloader.java ..." 263 | fi 264 | # Compiling the Java class 265 | ("$JAVA_HOME/bin/javac" "$javaClass") 266 | fi 267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 268 | # Running the downloader 269 | if [ "$MVNW_VERBOSE" = true ]; then 270 | echo " - Running MavenWrapperDownloader.java ..." 271 | fi 272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 273 | fi 274 | fi 275 | fi 276 | fi 277 | ########################################################################################## 278 | # End of extension 279 | ########################################################################################## 280 | 281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 282 | if [ "$MVNW_VERBOSE" = true ]; then 283 | echo $MAVEN_PROJECTBASEDIR 284 | fi 285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 286 | 287 | # For Cygwin, switch paths to Windows format before running java 288 | if $cygwin; then 289 | [ -n "$M2_HOME" ] && 290 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 291 | [ -n "$JAVA_HOME" ] && 292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 293 | [ -n "$CLASSPATH" ] && 294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 295 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 297 | fi 298 | 299 | # Provide a "standardized" way to retrieve the CLI args that will 300 | # work with both Windows and non-Windows executions. 301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 302 | export MAVEN_CMD_LINE_ARGS 303 | 304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 305 | 306 | exec "$JAVACMD" \ 307 | $MAVEN_OPTS \ 308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 311 | -------------------------------------------------------------------------------- /graphql-backend-examples/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /graphql-backend-examples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.5.4 9 | 10 | 11 | com.example 12 | graphql-backend-examples 13 | 0.0.1-SNAPSHOT 14 | graphql-backend-examples 15 | Demo project for Spring Boot 16 | 17 | 11 18 | 19 | 20 | 21 | 22 | 23 | com.netflix.graphql.dgs 24 | graphql-dgs-platform-dependencies 25 | 26 | 4.1.0 27 | pom 28 | import 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-web 37 | 38 | 39 | 40 | com.netflix.graphql.dgs 41 | graphql-dgs-spring-boot-starter 42 | 43 | 44 | 45 | org.springframework.boot 46 | spring-boot-starter-test 47 | test 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-maven-plugin 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /graphql-backend-examples/src/main/java/com/example/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import java.util.logging.Logger; 4 | 5 | import org.springframework.beans.factory.annotation.Value; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 10 | import org.springframework.web.servlet.config.annotation.CorsRegistry; 11 | 12 | @SpringBootApplication 13 | public class DemoApplication { 14 | Logger logger = Logger.getLogger(DemoApplication.class.getName()); 15 | 16 | @Value("${JAVA_GRAPHQL_ENDPOINT}") 17 | private String graphQLEndpoint; 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(DemoApplication.class, args); 21 | } 22 | 23 | /* 24 | * No cors origin global setting. 25 | * This is needed to allow clients from a different origin 26 | * other than where this server is running to connect without 27 | * being denied via a CORS error 28 | */ 29 | @Bean 30 | public WebMvcConfigurer corsConfigurer() { 31 | 32 | return new WebMvcConfigurer() { 33 | @Override 34 | public void addCorsMappings(CorsRegistry registry) { 35 | final String[] endpoint = graphQLEndpoint.split("/graphql"); 36 | final String origin = endpoint[0]; 37 | 38 | logger.info("GraphQL endpoint is: " + origin); 39 | registry.addMapping("/graphql").allowedOrigins("" + origin + ""); 40 | } 41 | }; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /graphql-backend-examples/src/main/java/com/example/demo/Genre.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | public class Genre { 4 | private final String value; 5 | 6 | public Genre(String value) { 7 | this.value = value; 8 | } 9 | 10 | public String getValue() { 11 | return value; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /graphql-backend-examples/src/main/java/com/example/demo/GenresDatafetcher.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import com.netflix.graphql.dgs.DgsComponent; 4 | import com.netflix.graphql.dgs.DgsQuery; 5 | import com.netflix.graphql.dgs.InputArgument; 6 | 7 | import java.util.List; 8 | import java.util.stream.Collectors; 9 | 10 | import java.util.logging.*; 11 | 12 | @DgsComponent 13 | public class GenresDatafetcher { 14 | Logger logger = Logger.getLogger(GenresDatafetcher.class.getName()); 15 | 16 | private final List genres = List.of( 17 | new Genre("Action"), 18 | new Genre("Anime"), 19 | new Genre("Award-Winning"), 20 | new Genre("Children & Family"), 21 | new Genre("Comedies") 22 | ); 23 | 24 | @DgsQuery 25 | public List genres(@InputArgument String labelFilter) { 26 | logger.info("QUERY executed - Genres value is: " + genres.get(0).getValue()); 27 | 28 | if(labelFilter == null) { 29 | return genres; 30 | } 31 | 32 | return genres.stream().filter(s -> s.getValue().contains(labelFilter)).collect(Collectors.toList()); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /graphql-backend-examples/src/main/java/com/example/demo/Show.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | public class Show { 4 | private final String title; 5 | private final Integer releaseYear ; 6 | 7 | public Show(String title, Integer releaseYear) { 8 | this.title = title; 9 | this.releaseYear = releaseYear; 10 | } 11 | 12 | public String getTitle() { 13 | return title; 14 | } 15 | 16 | public Integer getReleaseYear() { 17 | return releaseYear; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /graphql-backend-examples/src/main/java/com/example/demo/ShowsDatafetcher.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import com.netflix.graphql.dgs.DgsComponent; 4 | import com.netflix.graphql.dgs.DgsQuery; 5 | import com.netflix.graphql.dgs.InputArgument; 6 | 7 | import java.util.List; 8 | import java.util.stream.Collectors; 9 | 10 | import java.util.logging.*; 11 | 12 | @DgsComponent 13 | public class ShowsDatafetcher { 14 | Logger logger = Logger.getLogger(ShowsDatafetcher.class.getName()); 15 | 16 | private final List shows = List.of( 17 | new Show("Stranger Things", 2016), 18 | new Show("Ozark", 2017), 19 | new Show("The Crown", 2016), 20 | new Show("Dead to Me", 2019), 21 | new Show("Orange is the New Black", 2013) 22 | ); 23 | 24 | @DgsQuery 25 | public List shows(@InputArgument String titleFilter) { 26 | logger.info("QUERY executed - Shows title is: " + shows.get(0).getTitle()); 27 | 28 | if(titleFilter == null) { 29 | return shows; 30 | } 31 | 32 | return shows.stream().filter(s -> s.getTitle().contains(titleFilter)).collect(Collectors.toList()); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /graphql-backend-examples/src/main/java/com/example/demo/ZRedirectGraphIQlController.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.GetMapping; 5 | 6 | import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR; 7 | import static org.springframework.web.servlet.view.UrlBasedViewResolver.REDIRECT_URL_PREFIX; 8 | 9 | @Controller 10 | public class ZRedirectGraphIQlController { 11 | 12 | @GetMapping(DEFAULT_PATH_SEPARATOR) 13 | public String index() { 14 | return REDIRECT_URL_PREFIX + "/graphiql"; 15 | } 16 | 17 | } 18 | 19 | -------------------------------------------------------------------------------- /graphql-backend-examples/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /graphql-backend-examples/src/main/resources/schema/schema.graphqls: -------------------------------------------------------------------------------- 1 | type Query { 2 | shows(titleFilter: String): [Show] 3 | genres(labelFilter: String): [Genre] 4 | } 5 | 6 | type Show { 7 | title: String 8 | releaseYear: Int 9 | } 10 | 11 | type Genre { 12 | value: String! 13 | } -------------------------------------------------------------------------------- /graphql-backend-examples/src/test/java/com/example/demo/DemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.demo; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DemoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /graphql-client-examples/.env.sample: -------------------------------------------------------------------------------- 1 | ASTRA_DB_APPLICATION_TOKEN="AstraCS:..." 2 | ASTRA_DB_GRAPHQL_URL="https://....apps.astra.datastax.com/api/graphql/intrographql" 3 | ASTRA_DB_GRAPHQL_URL_ADMIN="https://......-.......apps.astra.datastax.com/api/graphql-admin" 4 | ASTRA_DB_GRAPHQL_URL_PLAYGROUND="https://......-.......apps.astra.datastax.com/api/playground" 5 | ASTRA_DB_GRAPHQL_URL_SCHEMA="https://......-.......apps.astra.datastax.com/api/graphql-schema" 6 | ASTRA_DB_ID="......" 7 | ASTRA_DB_KEYSPACE="intrographql" 8 | ASTRA_DB_REGION="......" 9 | ASTRA_DB_REST_URL="https://......-.......apps.astra.datastax.com/api/rest" 10 | ASTRA_DB_REST_URL_SWAGGER="https://......-.......apps.astra.datastax.com/api/rest/swagger-ui/" 11 | ASTRA_DB_SECURE_BUNDLE_PATH="/home/gitpod/.astra/scb/scb_......_.......zip" 12 | ASTRA_DB_SECURE_BUNDLE_URL="https://datastax-cluster-config.....amazonaws.com/....../secure-connect-workshops.zip?......" 13 | ASTRA_ORG_ID="......" 14 | ASTRA_ORG_NAME="user@domain.com" 15 | ASTRA_ORG_TOKEN="AstraCS:..." 16 | 17 | # Non-Astra-DB additional setting (local backend URL): 18 | JAVA_GRAPHQL_ENDPOINT="https://8080-datastaxdev-......gitpod.io/graphql" 19 | -------------------------------------------------------------------------------- /graphql-client-examples/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 35 | 36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 39 | 40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /graphql-client-examples/functions/getGenresAstra.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch') 2 | 3 | exports.handler = async function (event) { 4 | const query = ` 5 | query getAllGenres { 6 | reference_list (value: { label: "genre"}) { 7 | values { 8 | value 9 | } 10 | } 11 | } 12 | ` 13 | const url = process.env.ASTRA_DB_GRAPHQL_URL 14 | const response = await fetch(url, { 15 | method: 'POST', 16 | headers: { 17 | "Content-Type": "application/json", 18 | "x-cassandra-token": process.env.ASTRA_DB_APPLICATION_TOKEN 19 | }, 20 | body: JSON.stringify({ query }) 21 | }) 22 | 23 | try { 24 | const responseBody = await response.json() 25 | return { 26 | statusCode: 200, 27 | body: JSON.stringify(responseBody) 28 | } 29 | } catch (e) { 30 | console.log(e) 31 | return { 32 | statusCode: 500, 33 | body: JSON.stringify(e) 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /graphql-client-examples/functions/getGenresBackend.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch') 2 | 3 | exports.handler = async function (event) { 4 | const query = ` 5 | query getAllGenres { 6 | genres { 7 | value 8 | } 9 | } 10 | ` 11 | const url = process.env.JAVA_GRAPHQL_ENDPOINT 12 | const response = await fetch(url, { 13 | method: 'POST', 14 | headers: { 15 | "Content-Type": "application/json" 16 | }, 17 | body: JSON.stringify({ query }) 18 | }) 19 | 20 | try { 21 | const responseBody = await response.json() 22 | return { 23 | statusCode: 200, 24 | body: JSON.stringify(responseBody) 25 | } 26 | } catch (e) { 27 | console.log(e) 28 | return { 29 | statusCode: 500, 30 | body: JSON.stringify(e) 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /graphql-client-examples/functions/getShowsAstra.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch') 2 | 3 | exports.handler = async function (event) { 4 | const query = ` 5 | query getAllShows { 6 | show_by_name { 7 | values { 8 | title 9 | releaseYear 10 | } 11 | } 12 | } 13 | ` 14 | const url = process.env.ASTRA_DB_GRAPHQL_URL 15 | const response = await fetch(url, { 16 | method: 'POST', 17 | headers: { 18 | "Content-Type": "application/json", 19 | "x-cassandra-token": process.env.ASTRA_DB_APPLICATION_TOKEN 20 | }, 21 | body: JSON.stringify({ query }) 22 | }) 23 | 24 | try { 25 | const responseBody = await response.json() 26 | return { 27 | statusCode: 200, 28 | body: JSON.stringify(responseBody) 29 | } 30 | } catch (e) { 31 | console.log(e) 32 | return { 33 | statusCode: 500, 34 | body: JSON.stringify(e) 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /graphql-client-examples/functions/getShowsBackend.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch') 2 | 3 | exports.handler = async function (event) { 4 | const query = ` 5 | query getAllShows { 6 | shows { 7 | title 8 | releaseYear 9 | } 10 | } 11 | ` 12 | const url = process.env.JAVA_GRAPHQL_ENDPOINT 13 | const response = await fetch(url, { 14 | method: 'POST', 15 | headers: { 16 | "Content-Type": "application/json" 17 | }, 18 | body: JSON.stringify({ query }) 19 | }) 20 | 21 | try { 22 | const responseBody = await response.json() 23 | return { 24 | statusCode: 200, 25 | body: JSON.stringify(responseBody) 26 | } 27 | } catch (e) { 28 | console.log(e) 29 | return { 30 | statusCode: 500, 31 | body: JSON.stringify(e) 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /graphql-client-examples/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "npm run build" 3 | functions = "functions" 4 | publish = "build" -------------------------------------------------------------------------------- /graphql-client-examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@apollo/client": "^3.4.10", 7 | "@testing-library/jest-dom": "^5.14.1", 8 | "@testing-library/react": "^11.2.7", 9 | "@testing-library/user-event": "^12.8.3", 10 | "node-fetch": "^2.6.1", 11 | "netlify-cli": "^3.31.14", 12 | "graphql": "^15.5.2", 13 | "react": "^17.0.2", 14 | "react-dom": "^17.0.2", 15 | "react-scripts": "4.0.3" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": [ 25 | "react-app", 26 | "react-app/jest" 27 | ] 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /graphql-client-examples/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/graphql-client-examples/public/favicon.ico -------------------------------------------------------------------------------- /graphql-client-examples/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /graphql-client-examples/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/graphql-client-examples/public/logo192.png -------------------------------------------------------------------------------- /graphql-client-examples/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/graphql-client-examples/public/logo512.png -------------------------------------------------------------------------------- /graphql-client-examples/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /graphql-client-examples/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /graphql-client-examples/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | margin-top:25px; 7 | height: 10vmin; 8 | pointer-events: none; 9 | } 10 | 11 | @media (prefers-reduced-motion: no-preference) { 12 | .App-logo { 13 | animation: App-logo-spin infinite 50s linear; 14 | } 15 | } 16 | 17 | .App-header { 18 | background-color: #282c34; 19 | min-height: 100vh; 20 | display: flex; 21 | flex-direction: column; 22 | align-items: center; 23 | justify-content: center; 24 | font-size: calc(10px + 2vmin); 25 | color: white; 26 | } 27 | 28 | .App-subtitle a { 29 | color: gold; 30 | font-style: italic; 31 | } 32 | 33 | .App-link { 34 | color: #61dafb; 35 | } 36 | 37 | @keyframes App-logo-spin { 38 | from { 39 | transform: rotate(0deg); 40 | } 41 | to { 42 | transform: rotate(360deg); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /graphql-client-examples/src/App.js: -------------------------------------------------------------------------------- 1 | import graphql_logo from './graphql_logo.svg'; 2 | import './App.css'; 3 | import Shows from './components/Shows'; 4 | import Genres from './components/Genres'; 5 | import ShowsByName from './components/ShowsByName'; 6 | import ReferenceList from './components/ReferenceList'; 7 | 8 | function App() { 9 | return ( 10 |
11 |
12 | 13 | logo 14 | 15 |

16 | 17 | Intro to GraphQL by DataStax Developers 18 | 19 |

20 |

Shows(Local)

21 | 22 |

Genres(Local)

23 | 24 |

ShowsByName(Astra DB)

25 | 26 |

ReferenceList(Astra DB)

27 | 28 |
29 |
30 | ); 31 | } 32 | 33 | export default App; 34 | -------------------------------------------------------------------------------- /graphql-client-examples/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /graphql-client-examples/src/components/Genres.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react" 2 | 3 | function Genres() { 4 | const [gqlResult, setGqlResult] = useState(null) // State to hold graphQL result data 5 | const [isLoading, setIsLoading] = useState(true) // State to determine when the async graphQL call is complete 6 | const [isError, setIsError] = useState(true) // State to determine if the graphQL payload contains an error object 7 | 8 | const fetchData = async () => { 9 | 10 | // Asynchronously fetch any "genres" graphQL data from the Java backend 11 | // using the getGenresBackend serverless function to call out to the 12 | // Netflix DGS Java graphQL endpoint 13 | const response = await fetch("/.netlify/functions/getGenresBackend", { 14 | method: "POST", 15 | }) 16 | const responseBody = await response.json() 17 | setGqlResult(responseBody) // on response set our graphQL result state 18 | } 19 | 20 | useEffect(() => { 21 | fetchData() 22 | }, []) 23 | 24 | // Watch gqlResult for any state changes and determine if we 25 | // are finishled loading the payload or if there are 26 | // any errors 27 | useEffect(() => { 28 | if (gqlResult !== null) { 29 | setIsLoading(false) 30 | 31 | // Check the payload for any errors https://graphql.org/learn/validation/ 32 | // and if any exist set error state and dump the message to the console 33 | if ('errors' in gqlResult) { 34 | setIsError(true) 35 | console.log("genres ERROR IS: ", gqlResult.errors) 36 | } else { 37 | setIsError(false) 38 | } 39 | } 40 | }, [gqlResult]) // <- watch me for state changes 41 | 42 | // If no result yet display loading text and return 43 | // This will exit the function and "skip" conditions below it 44 | if (isLoading) return

Is Loading...

; 45 | 46 | // If there is an error state display error text and return 47 | // This will exit the function and "skip" conditions below it 48 | if (isError) return

Error :(

; 49 | 50 | // If payload loading is complete and there are no errors 51 | // now check to see there is any data returned 52 | // (If this triggers it essentially means there are no rows returned from the data layer) 53 | // This will exit the function and "skip" conditions below it 54 | if (!gqlResult.data.genres.length) return

No Data

; 55 | 56 | // Finally, if all other checks pass get the data 57 | // from the payload via gqlResult state and inject it into the DOM 58 | // Notice how the payload example below and the field "value" match exactly 59 | // {"data":{"genres":[{"value":"Action"},{"value":"Anime"}... 60 | return gqlResult.data.genres.map(({ value }) => ( 61 |
62 |

63 | {value} 64 |

65 |
66 | )); 67 | 68 | } 69 | 70 | export default Genres; -------------------------------------------------------------------------------- /graphql-client-examples/src/components/ReferenceList.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react" 2 | 3 | function ReferenceList() { 4 | const [gqlResult, setGqlResult] = useState(null) // State to hold graphQL result data 5 | const [isLoading, setIsLoading] = useState(true) // State to determine when the async graphQL call is complete 6 | const [isError, setIsError] = useState(true) // State to determine if the graphQL payload contains an error object 7 | 8 | const fetchData = async () => { 9 | 10 | // Asynchronously fetch any "reference_list" graphQL data from the Astra DB GraphQL API 11 | // using the getGenresAstra serverless function to call out to the 12 | // Astra/Stargate graphQL endpoint 13 | // https://stargate.io/docs/stargate/1.0/developers-guide/graphql.html 14 | const response = await fetch("/.netlify/functions/getGenresAstra", { 15 | method: "POST", 16 | }) 17 | const responseBody = await response.json() 18 | setGqlResult(responseBody) // on response set our graphQL result state 19 | } 20 | 21 | useEffect(() => { 22 | fetchData() 23 | }, []) 24 | 25 | // Watch gqlResult for any state changes and determine if we 26 | // are finishled loading the payload or if there are 27 | // any errors 28 | useEffect(() => { 29 | if (gqlResult !== null) { 30 | setIsLoading(false) 31 | 32 | // Check the payload for any errors https://graphql.org/learn/validation/ 33 | // and if any exist set error state and dump the message to the console 34 | if ('errors' in gqlResult) { 35 | setIsError(true) 36 | console.log("reference_list ERROR IS: ", gqlResult.errors) 37 | } else { 38 | setIsError(false) 39 | } 40 | } 41 | }, [gqlResult]) // <- watch me for state changes 42 | 43 | // If no result yet display loading text and return 44 | // This will exit the function and "skip" conditions below it 45 | if (isLoading) return

Is Loading...

; 46 | 47 | // If there is an error state display error text and return 48 | // This will exit the function and "skip" conditions below it 49 | if (isError) return

Error :(

; 50 | 51 | // If payload loading is complete and there are no errors 52 | // now check to see there is any data returned 53 | // (If this triggers it essentially means there are no rows returned from the data layer) 54 | // This will exit the function and "skip" conditions below it 55 | if (!gqlResult.data.reference_list.values.length) return

No Data

; 56 | 57 | // Finally, if all other checks pass get the data 58 | // from the payload via gqlResult state and inject it into the DOM 59 | // Notice how the payload example below and the field "value" match exactly 60 | // {"data":{"reference_list":{"values":[{"value":"Action"},{"value":"Anime"}... 61 | return gqlResult.data.reference_list.values.map(({ value }) => ( 62 |
63 |

64 | {value} 65 |

66 |
67 | )); 68 | 69 | } 70 | 71 | export default ReferenceList; -------------------------------------------------------------------------------- /graphql-client-examples/src/components/Shows.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react" 2 | 3 | function Shows() { 4 | const [gqlResult, setGqlResult] = useState(null) // State to hold graphQL result data 5 | const [isLoading, setIsLoading] = useState(true) // State to determine when the async graphQL call is complete 6 | const [isError, setIsError] = useState(true) // State to determine if the graphQL payload contains an error object 7 | 8 | const fetchData = async () => { 9 | 10 | // Asynchronously fetch any "shows" graphQL data from the Java backend 11 | // using the getShowsBackend serverless function to call out to the 12 | // Netflix DGS Java graphQL endpoint 13 | const response = await fetch("/.netlify/functions/getShowsBackend", { 14 | method: "POST", 15 | }) 16 | const responseBody = await response.json() 17 | setGqlResult(responseBody) // on response set our graphQL result state 18 | } 19 | 20 | useEffect(() => { 21 | fetchData() 22 | }, []) 23 | 24 | // Watch gqlResult for any state changes and determine if we 25 | // are finishled loading the payload or if there are 26 | // any errors 27 | useEffect(() => { 28 | if (gqlResult !== null) { 29 | setIsLoading(false) 30 | 31 | // Check the payload for any errors https://graphql.org/learn/validation/ 32 | // and if any exist set error state and dump the message to the console 33 | if ('errors' in gqlResult) { 34 | setIsError(true) 35 | console.log("shows ERROR IS: ", gqlResult.errors) 36 | } else { 37 | setIsError(false) 38 | } 39 | } 40 | }, [gqlResult]) // <- watch me for state changes 41 | 42 | // If no result yet display loading text and return 43 | // This will exit the function and "skip" conditions below it 44 | if (isLoading) return

Is Loading...

; 45 | 46 | // If there is an error state display error text and return 47 | // This will exit the function and "skip" conditions below it 48 | if (isError) return

Error :(

; 49 | 50 | // If payload loading is complete and there are no errors 51 | // now check to see there is any data returned 52 | // (If this triggers it essentially means there are no rows returned from the data layer) 53 | // This will exit the function and "skip" conditions below it 54 | if (!gqlResult.data.shows.length) return

No Data

; 55 | 56 | // Finally, if all other checks pass get the data 57 | // from the payload via gqlResult state and inject it into the DOM 58 | // Notice how the payload example below and the fields "title" and "releaseYear" match exactly 59 | // {"data":{"shows":[{"title":"Stranger Things","releaseYear":2016},{"title":"Ozark","releaseYear":2017}... 60 | return gqlResult.data.shows.map(({ title, releaseYear }) => ( 61 |
62 |

63 | {title}: {releaseYear} 64 |

65 |
66 | )); 67 | 68 | } 69 | 70 | export default Shows; -------------------------------------------------------------------------------- /graphql-client-examples/src/components/ShowsByName.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react" 2 | 3 | function ShowsByName() { 4 | const [gqlResult, setGqlResult] = useState(null) // State to hold graphQL result data 5 | const [isLoading, setIsLoading] = useState(true) // State to determine when the async graphQL call is complete 6 | const [isError, setIsError] = useState(true) // State to determine if the graphQL payload contains an error object 7 | const [errorString, setErrorString] = useState("") // State to keep the error message(s) for display if necessary 8 | 9 | const fetchData = async () => { 10 | 11 | // Asynchronously fetch any "shows_by_name" graphQL data from the Astra DB GraphQL API 12 | // using the getShowsAstra serverless function to call out to the 13 | // Astra/Stargate graphQL endpoint 14 | // https://stargate.io/docs/stargate/1.0/developers-guide/graphql.html 15 | const response = await fetch("/.netlify/functions/getShowsAstra", { 16 | method: "POST", 17 | }) 18 | const responseBody = await response.json() 19 | setGqlResult(responseBody) // on response set our graphQL result state 20 | } 21 | 22 | useEffect(() => { 23 | fetchData() 24 | }, []) 25 | 26 | // Watch gqlResult for any state changes and determine if we 27 | // are finishled loading the payload or if there are 28 | // any errors 29 | useEffect(() => { 30 | if (gqlResult !== null) { 31 | setIsLoading(false) 32 | 33 | // Check the payload for any errors https://graphql.org/learn/validation/ 34 | // and if any exist set error state and dump the message to the console 35 | if ('errors' in gqlResult) { 36 | setIsError(true) 37 | setErrorString(JSON.stringify(gqlResult.errors)) 38 | console.log("show_by_name ERROR IS: ", gqlResult.errors) 39 | } else { 40 | setIsError(false) 41 | } 42 | } 43 | }, [gqlResult]) // <- watch me for state changes 44 | 45 | // If no result yet display loading text and return 46 | // This will exit the function and "skip" conditions below it 47 | if (isLoading) return

Is Loading...

; 48 | 49 | // If there is an error state display error text and return 50 | // This will exit the function and "skip" conditions below it 51 | if (isError) return

Error :( { errorString }

; 52 | 53 | // If payload loading is complete and there are no errors 54 | // now check to see there is any data returned 55 | // (If this triggers it essentially means there are no rows returned from the data layer) 56 | // This will exit the function and "skip" conditions below it 57 | if (!gqlResult.data.show_by_name.values.length) return

No Data

; 58 | 59 | // Finally, if all other checks pass get the data 60 | // from the payload via gqlResult state and inject it into the DOM 61 | // Notice how the payload example below and the fields "title" and "releaseYear" match exactly 62 | // {"data":{"show_by_name":{"values":[{"title":"Stranger Things","releaseYear":2016},{"title":"Ozark","releaseYear":2017}... 63 | return gqlResult.data.show_by_name.values.map(({ title, releaseYear }) => ( 64 |
65 |

66 | {title}: {releaseYear} 67 |

68 |
69 | )); 70 | 71 | } 72 | 73 | export default ShowsByName; -------------------------------------------------------------------------------- /graphql-client-examples/src/graphql_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 72 | -------------------------------------------------------------------------------- /graphql-client-examples/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /graphql-client-examples/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | ReactDOM.render( 7 | 8 | 9 | , 10 | document.getElementById('root') 11 | ); -------------------------------------------------------------------------------- /graphql-client-examples/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /hostURL.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | URL=`gp url 8080` 3 | 4 | # writing this snippet to later re-inject into the "Astra" dotenv 5 | echo -e "\n# Non-Astra-DB additional setting (local backend URL):\nJAVA_GRAPHQL_ENDPOINT=\"$URL/graphql\"" > /workspace/workshop-intro-to-graphql/graphql-client-examples/.local-backend.env 6 | # also writing here to have a local-only-working React app from the start 7 | echo -e "\n# Non-Astra-DB additional setting (local backend URL):\nJAVA_GRAPHQL_ENDPOINT=\"$URL/graphql\"" > /workspace/workshop-intro-to-graphql/graphql-client-examples/.env 8 | 9 | # writing this to have GraphiQL reach the local (DGS-powered) Spring Boot GraphQL server 10 | echo -e "JAVA_GRAPHQL_ENDPOINT=$URL/graphql" >> /workspace/workshop-intro-to-graphql/graphql-backend-examples/src/main/resources/application.properties 11 | -------------------------------------------------------------------------------- /slides/slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/slides/slides.pdf -------------------------------------------------------------------------------- /tutorial/images/NewTabOpen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/NewTabOpen.png -------------------------------------------------------------------------------- /tutorial/images/create_astra_db.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/create_astra_db.png -------------------------------------------------------------------------------- /tutorial/images/db-pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/db-pending.png -------------------------------------------------------------------------------- /tutorial/images/dot-env-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/dot-env-2.png -------------------------------------------------------------------------------- /tutorial/images/error_shows_by_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/error_shows_by_name.png -------------------------------------------------------------------------------- /tutorial/images/gitpod-shape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/gitpod-shape.png -------------------------------------------------------------------------------- /tutorial/images/graphQL_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphQL_logo.png -------------------------------------------------------------------------------- /tutorial/images/graphiql-queries.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphiql-queries.png -------------------------------------------------------------------------------- /tutorial/images/graphql-CreateShowsTable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphql-CreateShowsTable.png -------------------------------------------------------------------------------- /tutorial/images/graphql-CreateShowsTable_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphql-CreateShowsTable_result.png -------------------------------------------------------------------------------- /tutorial/images/graphql-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphql-badge.png -------------------------------------------------------------------------------- /tutorial/images/graphql-client-showing-shows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphql-client-showing-shows.png -------------------------------------------------------------------------------- /tutorial/images/graphql-field-undefined-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphql-field-undefined-error.png -------------------------------------------------------------------------------- /tutorial/images/graphql-getallshows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphql-getallshows.png -------------------------------------------------------------------------------- /tutorial/images/graphql-insertShows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphql-insertShows.png -------------------------------------------------------------------------------- /tutorial/images/graphql-insertShows_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphql-insertShows_result.png -------------------------------------------------------------------------------- /tutorial/images/graphql-playground-2b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphql-playground-2b.png -------------------------------------------------------------------------------- /tutorial/images/graphql-playground-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphql-playground-3.png -------------------------------------------------------------------------------- /tutorial/images/graphql-playground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphql-playground.png -------------------------------------------------------------------------------- /tutorial/images/graphql-url-ending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/graphql-url-ending.png -------------------------------------------------------------------------------- /tutorial/images/open-java-DGS-files-in-gitpod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/open-java-DGS-files-in-gitpod.png -------------------------------------------------------------------------------- /tutorial/images/open-playground-2-wh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/open-playground-2-wh.png -------------------------------------------------------------------------------- /tutorial/images/open-playground-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/open-playground-2.png -------------------------------------------------------------------------------- /tutorial/images/playground-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/playground-1.png -------------------------------------------------------------------------------- /tutorial/images/tabs-vs-playgroundtabs-labeled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datastaxdevs/workshop-intro-to-graphql/5e472012272d3a73a3d9d6a3679c3ab24f85fdb3/tutorial/images/tabs-vs-playgroundtabs-labeled.png --------------------------------------------------------------------------------