{"id":21089990,"url":"https://github.com/travelxml/netflix-clone-with-astradb-graphql","last_synced_at":"2026-05-07T06:35:01.117Z","repository":{"id":83407485,"uuid":"434886175","full_name":"TravelXML/NETFLIX-CLONE-WITH-ASTRADB-GRAPHQL","owner":"TravelXML","description":"Netflix Clone with Cassandra, GraphQL and Node, Netflix clone built with AstraDB and GraphQL. A comprehensive project showcasing database integration and GraphQL for scalable, efficient video streaming applications.","archived":false,"fork":false,"pushed_at":"2021-12-08T13:58:56.000Z","size":35235,"stargazers_count":2,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-21T01:11:14.691Z","etag":null,"topics":["astradb","cassandra","cassandra-cql","cassandra-database","clone","clone-app","clone-coding","cloner","cloud","cloud-computing","gitpod","graphql","graphql-api","headless","js","netlify","node","node-js","nodejs","serverless"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/TravelXML.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-04T11:44:53.000Z","updated_at":"2024-07-10T05:34:45.000Z","dependencies_parsed_at":"2023-03-09T12:15:27.392Z","dependency_job_id":null,"html_url":"https://github.com/TravelXML/NETFLIX-CLONE-WITH-ASTRADB-GRAPHQL","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TravelXML%2FNETFLIX-CLONE-WITH-ASTRADB-GRAPHQL","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TravelXML%2FNETFLIX-CLONE-WITH-ASTRADB-GRAPHQL/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TravelXML%2FNETFLIX-CLONE-WITH-ASTRADB-GRAPHQL/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TravelXML%2FNETFLIX-CLONE-WITH-ASTRADB-GRAPHQL/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TravelXML","download_url":"https://codeload.github.com/TravelXML/NETFLIX-CLONE-WITH-ASTRADB-GRAPHQL/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243532560,"owners_count":20306157,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["astradb","cassandra","cassandra-cql","cassandra-database","clone","clone-app","clone-coding","cloner","cloud","cloud-computing","gitpod","graphql","graphql-api","headless","js","netlify","node","node-js","nodejs","serverless"],"created_at":"2024-11-19T21:33:17.584Z","updated_at":"2026-05-07T06:34:56.073Z","avatar_url":"https://github.com/TravelXML.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--- STARTEXCLUDE ---\u003e\n# Netflix Clone Using Astra DB and GraphQL \n\n\u003ca href=\"https://github.com/TravelXML/NETFLIX-CLONE-WITH-ASTRADB-GRAPHQL\" target=”_blank”\u003e\n  \u003cimg align=\"center\" src=\"https://github.com/TravelXML/NETFLIX-CLONE-WITH-ASTRADB-GRAPHQL/blob/main/tutorial/images/netflix-clone-astradb-graphql-node-prod.png\" alt=\"Netflix Clone\" align=\"top\" /\u003e\n\u003c/a\u003e\n\n\u003cspan align=\"right\"\u003e[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/from-referrer/)[![License Apache2](https://img.shields.io/hexpm/l/plug.svg)](http://www.apache.org/licenses/LICENSE-2.0)\u003c/span\u003e\n\n\n\n# Create Netflix Clone in 1 Hour\n[Let's Start Building](#1-login-or-register-to-astradb-and-create-database)\n\n## Technology Stack ##\n\n* Node\n* GraphQL\n* Cassandra - Astra DB\n\n\n\u003c!--- ENDEXCLUDE ---\u003e\n\nSee the [Video Walkthrough](https://imgur.com/3ns3UJB) of what you will build!\n\n\n## 🎯 Objectives\n* Deploy a Netflix clone to production\n* Learn **GraphQL API** and how to use it with a database to create the tables and navigate the data.\n* Learn about **paging** and **infinite scrolling** in web ui\n* Leverage Netlify and Astra DB\n\n## ℹ️ Frequently asked questions ℹ️\n\n- *Can I run this Project on my computer?*\n\n\u003e There is nothing preventing you from running the project on your own machine.\n\u003e If you do so, you will need\n\u003e * git installed on your local system\n\u003e * [node 15 and npm 7 or later](https://www.whitesourcesoftware.com/free-developer-tools/blog/update-node-js/)\n\u003e\n\u003e You will have to adapt commands and paths based on your environment 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.\n\n- *What other prerequisites are there?*\n\u003e * You will need a github account\n\u003e * You will also need Netlify and Astra DB accounts, but we'll work through that in the exercises\n\u003e * Use \u003cimg src=\"tutorial/images/chrome-logo.svg\" height=\"20\"/\u003e Chrome or \u003cimg src=\"tutorial/images/firefox-logo.svg\" height=\"20\"/\u003e Firefox for the best experience. Other browsers are great, but don't work well with the GitPod integration we use a bit later.\n\n## Table of contents\n\n### Part I - DB Setup \u0026 Data Ingest\n1. [Create Astra DB Instance](#1-login-or-register-to-astradb-and-create-database)\n2. [Create a security token](#2-create-a-security-token)\n3. [Create table **genre** with GraphQL](#3-create-table-genre-with-graphql)\n4. [Insert data in **genre**  with GraphQL](#4-insert-data-in-the-table-with-graphql)\n5. [Retrieve values of **genre** table](#5-retrieving-list-of-values)\n6. [Create **movie** table](#6-creating-a-movies-table)\n7. [Insert values in **movie** table](#7-insert-values-in-movie-table)\n8. [Retrieve values from **movie** table](#8-retrieve-values-from-movie-tables)\n9. [Load a CSV DataSet](#9-load-a-csv-dataset)\n\n###  Part II - Build Front-End\n1. [Launch GitPod](#1-launch-gitpod-ide)\n2. [Serverless Functions](#2-serverless-functions)\n3. [Fetching from the Front-End](#3-fetching-from-the-front-end)\n4. [Install the Netlify CLI](#4-install-the-netlify-cli-command-line-interface)\n5. [Retrieve application token to securely connect to the database](#5-retrieve-application-token-to-securely-connect-to-the-database)\n6. [Configure Environment Variables and Install Dependencies](#6-configure-environment-variables-and-install-dependencies)\n7. [Launch your app](#7-launch-your-app)\n\n\n# Part 1 - DB Setup \u0026 Data Ingest\n\n## 1. Login or Register to AstraDB and create database\n\n\u003e *When creating your instance use the promotion code **ANIA200** to get 200$ of free credit allowing you about 30 million writes + 30 Million reads  + 50GB a month of monthly storage!!*\n\n**`ASTRADB`** is the simplest way to run Cassandra with zero operations at all - just push the button and get your cluster. No credit card required, $25.00 USD credit every month, roughly 5M writes, 30M reads, 40GB storage monthly - sufficient to run small production workloads.  \n\n✅ **Step 1a:** Click the button to login or register with Datastax. You can use your `Github`, `Google` accounts or register with an `email`.\n\n_Make sure to chose a password with minimum 8 characters, containing upper and lowercase letters, at least one number and special character_\n\n\u003ca href=\"https://astra.dev/12-3\"\u003e\u003cimg src=\"img/create_astra_db.png?raw=true\" /\u003e\u003c/a\u003e\n- \u003cdetails\u003e\u003csummary\u003eShow me!\u003c/summary\u003e\n    \u003cimg src=\"https://github.com/TravelXML/NETFLIX-CLONE-WITH-ASTRADB-GRAPHQL/blob/main/tutorial/images/astra-create-db.gif\" /\u003e\n\u003c/details\u003e\n\n\n**Use the following values when creating the database**\n|Field| Value|\n|---|---|\n|**database name**| `workshops` |\n|**keyspace**| `netflix` |\n|**Cloud Provider**| *Use the one you like, click a cloud provider logo,  pick an Area in the list and finally pick a region.* |\n\n_You can technically use whatever you want and update the code to reflect the keyspace. This is really to get you on a happy path for the first run._\n\nYou will see your new database `pending` in the Dashboard.\n\n![image](./tutorial/images/db-pending.png)\n\nThe status will change to `Active` when the database is ready, this will only take 2-3 minutes. You will also receive an email when it is ready.\n\n[🏠 Back to Table of Contents](#table-of-contents)\n\n\n## 2. Create a security token\n\n✅  **Step 2a:**  [Create a token for your app](https://docs.datastax.com/en/astra/docs/manage-application-tokens.html) to use in the settings screen. Use \"Database Administrator\" permission.\n\n✅  **Step 2b:**  Copy the token value (eg `AstraCS:KDfdKeNREyWQvDpDrBqwBsUB:ec80667c....`) in your clipboard and save the CSV, this value would not be provided afterward.\n\n**👁️ Expected output**\n- \u003cdetails\u003e\u003csummary\u003eShow me!\u003c/summary\u003e\n    \u003cimg src=\"img/astra-create-token.gif?raw=true\" /\u003e\n\u003c/details\u003e\n\n[🏠 Back to Table of Contents](#table-of-contents)\n\n## 3. Create table **genre** with GraphQL\n\n✅  **Step 3a:** Open **GraphQL Playground** by\n1. Click on your active database\n2. Click `Connect` TAB\n3. Click `GRAPHQL API`\n4. Click the link to your playground.\n\n*As shown in the picture below.*\n![image](img/open-playground.png?raw=true)\n\n\u003e *Note that values in the picture do no reflect the database name `workshops`, reason is we do not reproduce every picture each time*\n\n✅  **Step 3b:** In GraphQL Playground, **Populate HTTP HEADER** variable `x-cassandra-token` on the bottom of the page with your token as shown below\n\n![image](img/graphql-playground.png?raw=true)\n\n✅  **Step 3c:** In GraphQL Playground, create a table with the following mutation, making sure to replace `netflix` if you used a different name:\n\n- Copy the following mutation on the left panel\n```yaml\nmutation {\n  reference_list: createTable(\n    keyspaceName:\"netflix\",\n    tableName:\"reference_list\",\n    ifNotExists:true\n    partitionKeys: [\n      { name: \"label\", type: {basic: TEXT} }\n    ]\n    clusteringKeys: [\n      { name: \"value\", type: {basic: TEXT}, order: \"ASC\" }\n    ]\n  )\n}\n```\n* Use the arrow in the middle of the screen to execute the query\n\n![image](tutorial/images/playground-1.png?raw=true)\n\n[🏠 Back to Table of Contents](#table-of-contents)\n\n## 4. Insert data in the Table with GraphQL\n\n✅  **Step 4a:** In the graphQL playground, change the tab to now use `graphql`. Edit the end of the URl to change from `system` to the name of your keyspace: `netflix`\n\n✅  **Step 4b:** Populate **HTTP HEADER** variable `x-cassandra-token` on the bottom of the page with your token as shown below (again !! yes this is not the same tab)\n\n![image](img/graphql-playground-2.png?raw=true)\n\n✅  **Step 4c:** In GraphQL Playground,populate the `reference_list` table with the following values\n\n- Copy the following mutation on the left panel\n\n```yaml\nmutation insertGenres {\n  action: insertreference_list(value: {label:\"genre\", value:\"Action\"}) {\n    value{value}\n  }\n  anime: insertreference_list(value: {label:\"genre\", value:\"Anime\"}) {\n     value{value}\n  }\n  award: insertreference_list(value: {label:\"genre\", value:\"Award-Winning\"}) {\n     value{value}\n  }\n  children: insertreference_list(value: {label:\"genre\", value:\"Children \u0026 Family\"}) {\n     value{value}\n  }\n  comedies: insertreference_list(value: {label:\"genre\", value:\"Comedies\"}) {\n     value{value}\n  }\n  documentaries: insertreference_list(value: {label:\"genre\", value:\"Documentaries\"}) {\n     value{value}\n  }\n  drama: insertreference_list(value: {label:\"genre\", value:\"Dramas\"}) {\n     value{value}\n  }\n  fantasy: insertreference_list(value: {label:\"genre\", value:\"Fantasy\"}) {\n     value{value}\n  }\n  french: insertreference_list(value: {label:\"genre\", value:\"French\"}) {\n     value{value}\n  }\n  horror: insertreference_list(value: {label:\"genre\", value:\"Horror\"}) {\n     value{value}\n  }\n  independent: insertreference_list(value: {label:\"genre\", value:\"Independent\"}) {\n     value{value}\n  }\n  music: insertreference_list(value: {label:\"genre\", value:\"Music \u0026 Musicals\"}) {\n     value{value}\n  }\n  romance: insertreference_list(value: {label:\"genre\", value:\"Romance\"}) {\n     value{value}\n  }\n  scifi: insertreference_list(value: {label:\"genre\", value:\"Sci-Fi\"}) {\n     value{value}\n  }\n  thriller: insertreference_list(value: {label:\"genre\", value:\"Thriller\"}) {\n     value{value}\n  }\n  realitytv: insertreference_list(value: {label:\"genre\", value:\"Reality TV\"}) {\n     value{value}\n  }\n  tvshow: insertreference_list(value: {label:\"genre\", value:\"TV Show\"}) {\n     value{value}\n  }\n  musicmusicals: insertreference_list(value: {label:\"genre\", value:\"Music \u0026 Musicals\"}) {\n     value{value}\n  }\n  classic: insertreference_list(value: {label:\"genre\", value:\"Classic\"}) {\n     value{value}\n  }\n  international: insertreference_list(value: {label:\"genre\", value:\"International\"}) {\n     value{value}\n  }\n  crime: insertreference_list(value: {label:\"genre\", value:\"Crime\"}) {\n     value{value}\n  }\n  cult: insertreference_list(value: {label:\"genre\", value:\"Cult\"}) {\n     value{value}\n  }  \n}\n```\n\n* Use the arrow in the middle of the screen to execute the query\n\n[🏠 Back to Table of Contents](#table-of-contents)\n\n## 5. Retrieving list of values\n\n✅  **Step 5a:** In GraphQL Playground, not changing tab (yeah) list values from the table with the following query.\n\n```yaml\nquery getAllGenre {\n    reference_list (value: {label:\"genre\"}) {\n      values {\n          value\n      }\n    }\n}\n```\n\n*👁️ Expected output*\n![image](img/graphql-playground-3.png?raw=true)\n\n[🏠 Back to Table of Contents](#table-of-contents)\n\n## 6. Creating a Movies Table\n\n✅  **Step 6a:** Move to tab `GRAPHQL-SCHEMA`, everything should be set, use the following mutation to create a new table:\n_Remember to change the keyspaceName if you used something different.\n\n```yaml\nmutation {\n  movies_by_genre: createTable(\n    keyspaceName:\"netflix\",\n    tableName:\"movies_by_genre\",\n    ifNotExists: true,\n    partitionKeys: [\n      { name: \"genre\", type: {basic: TEXT} }\n    ]\n    clusteringKeys: [\n      { name: \"year\", type: {basic: INT}, order: \"DESC\" },\n      { name: \"title\", type: {basic: TEXT}, order: \"ASC\" }\n    ]\n    values: [\n      { name: \"synopsis\", type: {basic: TEXT} },\n      { name: \"duration\", type: {basic: INT} },\n      { name: \"thumbnail\", type: {basic: TEXT} }\n    ]\n  )\n}\n```\n\n*👁️ Expected output*\n![image](img/graphql-playground-4.png?raw=true)\n\n[🏠 Back to Table of Contents](#table-of-contents)\n\n## 7. Insert Values in Movie table\n\n✅  **Step 7a:** Move to tab `GRAPHQL`, everything should be set, use the following mutation to populate movies table:\n\n```yaml\nmutation insertMovies {\n  inception: insertmovies_by_genre(\n    value: {\n      genre:\"Sci-Fi\",\n      year:2010,\n      title:\"Inception\",\n      synopsis:\"Cobb steals information from his targets by entering their dreams.\",\n      duration:121,\n      thumbnail:\"https://i.imgur.com/RPa4UdO.mp4\"}) {\n    value{title}\n    }\n \n  prometheus: insertmovies_by_genre(value: {\n      genre:\"Sci-Fi\",\n      year:2012,\n      title:\"Prometheus\",\n      synopsis:\"After a clue to mankind's origins is discovered, explorers are sent to the darkest corner of the universe.\",\n      duration:134,\n      thumbnail:\"https://i.imgur.com/L8k6Bau.mp4\"}) {\n    value{title}\n    }\n \n      aliens: insertmovies_by_genre(value: {\n      genre:\"Sci-Fi\",\n      year:1986,\n      title:\"Aliens\",\n      synopsis:\"Ellen Ripley is sent back to the planet LV-426 to establish contact with a terraforming colony.\",\n      duration:134,\n      thumbnail:\"https://i.imgur.com/QvkrnyZ.mp4\"}) {\n    value{title}\n    }\n \n    bladeRunner: insertmovies_by_genre(value: {\n      genre:\"Sci-Fi\",\n      year:1982,\n      title:\"Blade Runner\",\n      synopsis:\"Young Blade Runner K's discovery of a long-buried secret leads him to track down former Blade Runner Rick Deckard.\",\n      duration:145,\n      thumbnail:\"https://i.imgur.com/xhhvmj1.mp4\"}) {\n    value{title}\n    }\n  }\n```\n\n*👁️ Expected output*\n![image](img/graphql-playground-5.png?raw=true)\n\n\u003e ℹ️ You can find more movie data in the `data` folder, however, we will be doing a bulk import of all this data shortly.\n\n[🏠 Back to Table of Contents](#table-of-contents)\n\n## 8. Retrieve values from Movie tables\n\n✅  **Step 8a:** In GraphQL Playground, not changing tab (yeah) list values from the table with the following command.\n\n```yaml\nquery getMovieAction {\n    movies_by_genre (\n      value: {genre:\"Sci-Fi\"},\n       orderBy: [year_DESC]) {\n      values {\n        year,\n        title,\n        duration,\n        synopsis,\n        thumbnail\n      }\n    }\n}\n```\n\n*👁️ Expected output*\n![image](img/graphql-playground-6.png?raw=true)\n\n✅ **Step 8b Enable paging:** For small datasets you can retrieve all values in the table but for performance or network reasons you need to perform paging. Let's do same query as before now asking for a `page size to 2`\n\n```yaml\nquery getMovieAction {\n    movies_by_genre (\n      value: {genre:\"Sci-Fi\"},\n       options: {pageSize: 2},\n       orderBy: [year_DESC]) {\n      values {\n        year,\n        title,\n        duration,\n        synopsis,\n        thumbnail\n      }\n    pageState\n    }\n}\n```\n\n*👁️ Expected output*\n\n![image](tutorial/images/playground-2.png?raw=true)\n\n✅ **Step 8c: Fetch next page paging:**  Notice that `pageState` is also now returned. Let's use it to fetch the next 2 items (next page). Edit the next query to replace your own pageState `YOUR_PAGE_STATE`\n\n```yaml\nquery getMovieAction {\n    movies_by_genre (\n      value: {genre:\"Sci-Fi\"},\n       options: {pageSize: 2, pageState: \"\u003cYOUR_PAGE_STATE\u003e\"},\n       orderBy: [year_DESC]) {\n      values {\n        year,\n        title,\n        duration,\n        synopsis,\n        thumbnail\n      }\n    pageState\n    }\n}\n```\n \n*👁️ Expected output*\n\n![image](tutorial/images/playground-3.png?raw=true)\n\n[🏠 Back to Table of Contents](#table-of-contents)\n\n## 9. Load a CSV DataSet\n\n✅ **Step 9a: Download the dataset**\n\nTo download the DATASET, right-click (or CTRL + Click to open in new tab) the button below and download the target file on your machine.\n\n\u003e *If the file opens in the browser save it with the name `movies_by_genre.csv`. This is important as the filename will be the table name.*\n\n\u003cp align=\"left\"\u003e\n\u003ca href=\"https://raw.githubusercontent.com/TravelXML/NETFLIX-CLONE-WITH-ASTRADB-GRAPHQL/main/tutorial/images/movies_by_genre.csv?raw=true\"\u003e\n \u003cimg src=\"https://dabuttonfactory.com/button.png?t=Download Dataset\u0026f=Roboto-Bold\u0026ts=20\u0026tc=fff\u0026hp=20\u0026vp=15\u0026c=11\u0026bgt=unicolored\u0026bgc=15d798\" /\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n✅ **Step 9b: Open Astra Data Loader Importer**\n\n- Locate the `Load Data` button to open the Data Loader.\n\n![image](tutorial/images/import-movies-0.png?raw=true)\n\n✅ **Step 9c: Upload the dataset**\n\nClick on the area Drag n drop a single file and look for the file `movies_by_genre.csv` on your machine, this file has been downloaded in step 9b.\n\n![image](tutorial/images/import-movies-1.png?raw=true)\n\nOnce the file has been upload notive the `Upload Successful` message in green. You can now click `NEXT`\n\n✅ **Step 9d: Define target table**\n\n- Locate the field Table Name and make sure it is set to `movies_by_genre`\n\n![image](tutorial/images/import-movies-2.png?raw=true)\n\n- In `Keys and Clustering` section enter `genre` as the partition key.\n\n![image](tutorial/images/import-movies-4.png?raw=true)\n\nYou can now click on `NEXT` to move forward.\n\n✅ **Step 9e: Define target database**\n\n![image](tutorial/images/import-movies-3.png?raw=true)\n\nSelect the database we are currently using:\n\n| Field | Value |\n| --- | --- |\n| **Target Database** | `workshops` |\n| **Target Keyspace** | `netflix` |\n\nand click next to start the process asynchronously.\n\n✅ **Step 9f: Wait for the batch to import your data**\n\nAfter a few seconds (about 30s) ,you will get an email informing you that the batch has been scheduled.\n\n![image](tutorial/images/import-movies-5.png?raw=true)\n\nAs you can see the operation here is asynchronous. About a minute later your will get another email to tell you the data has been inserted.\n\n![image](tutorial/images/import-movies-6.png?raw=true)\n\n**Congratulations, the Database is SET !!!**\n\n[🏠 Back to Table of Contents](#table-of-contents)\n\n# Part 2 - Build Front-End\n\n## 1. Launch GitPod IDE\n- Click the button to launch the GitPod IDE.\n\n* _Supported by \u003cimg src=\"tutorial/images/chrome-logo.svg\" height=\"20\"/\u003e Chrome and \u003cimg src=\"tutorial/images/firefox-logo.svg\" height=\"20\"/\u003e Firefox_\n\n[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/TravelXML/NETFLIX-CLONE-WITH-ASTRADB-GRAPHQL)\n\n   \nℹ️ _It may take minutes (approx. 3-5) for GitPod to fully initialize._\n\n\n## 2. Serverless Functions\n\nTake a look at `functions/getGenres.js`\n\n``` javascript\nconst fetch = require('node-fetch')\n\nexports.handler = async function (event) {\n\n  const body = JSON.parse(event.body)\n  const url = process.env.ASTRA_GRAPHQL_ENDPOINT\n  const query = `\n    query getAllGenres {\n      reference_list (\n        value: { label: \"genre\"},\n        options: {\n          pageSize: ${JSON.stringify(body.pageSize)},\n          pageState: ${JSON.stringify(body.pageState)}\n        }\n      ) {\n        values {\n          value\n        }\n        pageState\n      }\n    }\n  `\n\n  const response = await fetch(url, {\n    method: 'POST',\n    headers: {\n      \"Content-Type\": \"application/json\",\n      \"x-cassandra-token\": process.env.ASTRA_DB_APPLICATION_TOKEN\n    },\n    body: JSON.stringify({ query })\n  })\n\n  try {\n    const responseBody = await response.json()\n    return {\n      statusCode: 200,\n      body: JSON.stringify(responseBody)\n    }\n  } catch (e) {\n    console.log(e)\n    return {\n      statusCode: 500,\n      body: JSON.stringify(e)\n    }\n  }\n}\n```\n\nYou'll notice the familiar GraphQL query \"getAllGenres\" we used previously in the playground. It's been modified a bit to utilize paging.\n\n``` javascript\noptions: {\n  pageSize: ${JSON.stringify(body.pageSize)},\n  pageState: ${JSON.stringify(body.pageState)}\n}\n```\n\nThis section allows us to pass in the desired page size and current page state from the front-end.\n\n``` javascript\n{\n  values {\n    value\n  }\n  pageState\n}\n```\n\nAnd, in addition to the values of the query, we are also returning the page state from the query.\n\nThe serverless function `functions/getMovies.js` works in much the same way, though we pass in the specific genre we want, and are hardcoding the page size to 6.\n\n``` javascript\nquery {\n  movies_by_genre (\n    value: { genre: ${JSON.stringify(genre)}},\n    orderBy: [year_DESC],\n    options: { pageSize: 6, pageState: ${JSON.stringify(pageState)} }\n  ) {\n    values {\n      year,\n      title,\n      duration,\n      synopsis,\n      thumbnail\n    }\n    pageState\n  }\n}\n```\n\n## 3. Fetching from the Front-End\n\nLet's take a look at how we fetch these serverless functions from the front-end. Start in `src/App.js`\n\nWe have a fetch method defined that will retrieve a page of genres by calling the `getGenres` serverless function.\n\n``` javascript\nconst fetchData = async () =\u003e {\n  if (! isFetching)  {\n    setIsFetching(true)\n    const response = await fetch(\"/.netlify/functions/getGenres\", {\n      method: \"POST\",\n      body: JSON.stringify({pageState, pageSize}),\n    })\n    const responseBody = await response.json()\n    setPageState(responseBody.data.reference_list.pageState)\n    setGenres(gs =\u003e (gs || []).concat(responseBody.data.reference_list.values))\n    setIsFetching(false)\n  }\n}\n```\n\nWe pass in the current `pageState` and `pageSize` state variables and receive a response from the serverless function. We then set the `pageState` var to the new pagestate, and set the `genres` state variable to the received data. (Note that we are concatenating the new data to the var, since we want to keep all previously fetched data, not replace).\n\nWhen we render the page, generate a `\u003cSection\u003e` component for each genre, and set a `\u003cdiv\u003e` to detect a mouseEnter to load the next page of genres.\n\n``` javascript\n\u003c\u003e\n  \u003cNavBar /\u003e\n  \u003cHeroSection /\u003e\n  {genres \u0026\u0026 (\n    \u003cdiv className=\"container\"\u003e\n      {Object.values(genres).map((genre) =\u003e (\n        \u003cSection key={genre.value} genre={genre.value} /\u003e\n      ))}\n    \u003c/div\u003e\n  )}\n  \u003cdiv\n    className=\"page-end\"\n    onMouseEnter={() =\u003e {\n      setRequestedPage( np =\u003e np + 1 )\n    }}\n  /\u003e\n\u003c/\u003e\n```\n\nThe `\u003cSection\u003e` component works in the same way, though we will fully replace the data in the `movies` variable.\n\n``` javascript\nconst fetchData = async () =\u003e {\n  const response = await fetch(\"/.netlify/functions/getMovies\", {\n    method: \"POST\",\n    body: JSON.stringify({ genre: genre, pageState: pageState }),\n  })\n  const responseBody = await response.json()\n  setMovies(responseBody.data.movies_by_genre.values)\n  setPageState(responseBody.data.movies_by_genre.pageState)\n}\n```\n\nNow that we know how the front-end works, let's launch our app!\n\n## 4. Install the Netlify CLI (Command Line Interface)\n * In the `workshop-graphql-netflix` directory run the following command to install the netlify-cli\n ```\n npm install -g netlify-cli\n```\n\n * \u003cdetails\u003e\u003csummary\u003eShow me!\u003c/summary\u003e\n    \u003cimg src=\"tutorial/images/netlify-install-cli.png?raw=true\" /\u003e\n    \u003c/details\u003e\n\n## 5. Retrieve application token to securely connect to the database\n\nUse the token you previously generated. If you no longer have the token and did not download a .csv, you can generate a new token using [the instructions above](#2-create-a-security-token)\n\nYou will also need the GraphQL Endpoint for your keyspace.\nFirst, go to the Astra DB connect page for your database.\n![graphql-endpoint-1](tutorial/images/graphql-keyspace-url-01.png)\nThen scroll down to find the endpoint for your keyspace.\n![graphql-endpoint-1](tutorial/images/graphql-keyspace-url-02.png)\n\n## 6. Configure Environment Variables and Install Dependencies\n\n✅ Create `.env` file (do _not_ leave curly brackets)\n\n```ini\nASTRA_DB_APPLICATION_TOKEN=REPLACE_ME\nASTRA_GRAPHQL_ENDPOINT=REPLACE_ME\n```\n\n![env-file](tutorial/images/env_file.png)\n\n\n👩‍💻  Install all the packages\n\n```bash\nnpm install\n```\n\n## 7. Launch your app\n  * Run the application\n  ```\n  netlify dev\n  ```\n  * The application should automatically launch in the GitPod preview pane\n\n\n# Want to Deploy the Netflix Clone?\n\nFollow these steps to Deploy the Netflix clone to your own Netlify site!\n\n\n## 1. Deploy to Netlify\n\n- \u003cdetails\u003e\u003csummary\u003e What does the netlify deploy button do?\u003c/summary\u003eThe Netlify deploy button will:\u003cul\u003e\n    \u003cli\u003eCreate a new repository for you on Github\u003c/li\u003e\n    \u003cli\u003eCreate a site on Netlify\u003c/li\u003e\n    \u003cli\u003eLink the two together.\u003c/li\u003e\u003c/ul\u003e\n\u003c/details\u003e\n\n- Click the button to deploy\n\n  [![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/TravelXML/NETFLIX-CLONE-WITH-ASTRADB-GRAPHQL)\n * \u003cdetails\u003e\u003csummary\u003eShow me!\u003c/summary\u003e\n    \u003cimg src=\"tutorial/images/deploy-to-netlify.gif?raw=true\" /\u003e\n    \u003c/details\u003e\n\nThis will take a few minutes.\n\n  * If there is an existing account in Netlify, make sure the Netlify account settings show that it's connected to the appropriate git repository,\n    \u003cdetails\u003e\n    \u003csummary\u003eShow me! \u003c/summary\u003e\n    \u003cimg src=\"tutorial/images/netlify-connect-01.png\" /\u003e\n    \u003c/details\u003e\n\n  * Click on `Site deploy in progress` within the Netlify UI,\n    \u003cdetails\u003e\n    \u003csummary\u003eShow me! \u003c/summary\u003e\n    \u003cimg src=\"tutorial/images/deploy-1.png\" /\u003e\n    \u003c/details\u003e\n\n  * Click the top deploy link to see the build process.\n    \u003cdetails\u003e\n    \u003csummary\u003eShow me! \u003c/summary\u003e\n    \u003cimg src=\"tutorial/images/deploy-2.png\" /\u003e\n    \u003c/details\u003e\n\n  * Wait until the build complete `Netlify Build Complete`,  **When you see Pushing to repository** you're ready to move on.\n    \u003cdetails\u003e\n    \u003csummary\u003eShow me! \u003c/summary\u003e\n    \u003cimg src=\"tutorial/images/deploy-3.png\" /\u003e\n    \u003c/details\u003e\n\n  * Scroll up to the top and click on the site name (it'll be after {yourlogin}'s Team next to the Netlify button).\n    \u003cdetails\u003e\n    \u003csummary\u003eShow me! \u003c/summary\u003e\n    \u003cimg src=\"tutorial/images/deploy-4.png\" /\u003e\n    \u003c/details\u003e\n\n## 2. Access your GitHub repository\n\n  * Click on the `GitHub` in `Deploys from GitHub` to get back to your new repository.  Scroll to where you were in the README.\n    \u003cdetails\u003e\n    \u003csummary\u003eShow me! \u003c/summary\u003e\n    \u003cimg src=\"tutorial/images/deploy-5.png\" /\u003e\n    \u003c/details\u003e\n\n## 3. Follow Part 2 in **YOUR** Repository\n\nUse this link to open Gitpod from **YOUR** repository!\n[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/from-referrer/)\n\n## 4. Connect Netlify to your site\n\nExecute each of the commands below to link your code to your Netlify deployment.\n\n✅ **Step 4a:**  we'll need to **STOP** the `netlify dev` command if you still have it running. In the terminal where you executed the netlify command, issue a `CTRL+C` (control key + the C key) in order to stop the process.\n\n✅ **Step 4b:** Enter the following command to pop up a browser to authenticate with netlify\n\n  ```\n  netlify login\n  ```\n\n*👁️ Expected output*\n```\nOpening https://app.netlify.com/authorize?....\n⠋ Waiting for authorization...^C\n```\n\n✅ **Step 4c:** Open the link in a new WINDOW for the link to work, and authorize Netlify CLi to access Netlify on your behalf.\n\n  \u003e When using GitPod the preview pane **will not display this properly.** You must click the \"open in a new window\" button in the very top right of the preview pane._\n\n*👁️ Expected output*\n\n```\nYou are now logged into your Netlify account!\nRun netlify status for account details\nTo see all available commands run: netlify help\ngitpod /workspace/appdev-week3-graphql $\n```\n\n✅ **Step 4d:** link your workspace to the associated site with the following command\n\n```\nnetlify link\n```\n\n*👁️ Expected output*\n\n![image](tutorial/images/netlify-link.png?raw=true)\n\n✅ **Step 4e:** take the .env file upload it to netlify\n \n  ```\n  netlify env:import .env\n  ```\n\n\u003c!--\n  * Will be used to allow you to execute `netlify open`\n  ```\n  netlify sites:list\n  ```\n--\u003e\n\n## 5. Deploy to production\nNow that you've hooked everything up, time to deploy to production.\n\n  * Run\n  ```\n  netlify build\n  ```\n\n  * Then run\n  ```\n  netlify deploy --prod\n  ```\n\n  * Then finally run\n  ```\n  netlify open:site\n  ```\n \n  You've deployed your app to Netlify!\n  ![Netlify Setup Example](./tutorial/images/prodDeploy.png?raw=true)\n \n  Finally open [https://serverlessnetflixclone.netlify.app/](https://serverlessnetflixclone.netlify.app/)\n \n  Enjoy Coding!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftravelxml%2Fnetflix-clone-with-astradb-graphql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftravelxml%2Fnetflix-clone-with-astradb-graphql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftravelxml%2Fnetflix-clone-with-astradb-graphql/lists"}