75 | )
76 | }
77 |
78 | export default Upload
--------------------------------------------------------------------------------
/functions/addData.js:
--------------------------------------------------------------------------------
1 | const { getCollection } = require("./utils/astraClient");
2 |
3 | exports.handler = async function () {
4 | const posts = await getCollection();
5 | const data = [
6 | {
7 | id: 0,
8 | name: "Mo Farooq",
9 | username: "mofarooq32",
10 | avatar: "https://i.imgur.com/9KYq7VG.png",
11 | is_followed: true,
12 | video: "https://i.imgur.com/FTBP02Y.mp4",
13 | caption: "These ducks are MEGA cute",
14 | likes: 10,
15 | comments: 2,
16 | timestamp: "2019-03-10T09:08:31.020Z",
17 | button_visible: true,
18 | },
19 | {
20 | id: 1,
21 | name: "Tim Salowski",
22 | username: "timmytam",
23 | avatar: "https://i.imgur.com/rWYtZa6.png",
24 | is_followed: false,
25 | video: "https://i.imgur.com/1A7AKoF.mp4",
26 | caption: "When your fries give you attitude #getInMyBelly",
27 | likes: 12,
28 | comments: 2,
29 | timestamp: "2020-03-10T09:08:31.020Z",
30 | button_visible: true,
31 | },
32 | {
33 | id: 2,
34 | name: "Angela Lee",
35 | username: "angiecakes",
36 | avatar: "https://i.imgur.com/eX3hkoc.png",
37 | is_followed: true,
38 | video: "https://i.imgur.com/al6MLay.mp4",
39 | caption: "Happiest of Birthdays my Angel",
40 | likes: 2,
41 | comments: 4,
42 | timestamp: "2020-04-10T09:08:31.020Z",
43 | button_visible: true,
44 | },
45 | {
46 | id: 3,
47 | name: "Nina Xen",
48 | username: "nina_lina",
49 | avatar: "https://i.imgur.com/IigY4Hm.png",
50 | is_followed: false,
51 | video: "https://i.imgur.com/Kzvbeup.mp4",
52 | caption: "The new normal",
53 | likes: 10,
54 | comments: 2,
55 | timestamp: "2020-05-10T09:08:31.020Z",
56 | button_visible: true,
57 | },
58 | {
59 | id: 0,
60 | name: "Lana Del Mont",
61 | username: "lana_del_away",
62 | avatar: "https://i.imgur.com/jONHmE5.png",
63 | is_followed: true,
64 | video: "https://i.imgur.com/H9UX0Jm.mp4",
65 | caption: "Art is for everyone",
66 | likes: 231,
67 | comments: 20,
68 | timestamp: "2020-09-10T09:08:31.020Z",
69 | button_visible: true,
70 | },
71 | ];
72 |
73 | try {
74 | for (let i = 0; i < data.length; i++) {
75 | await posts.create(data[i].id.toString(), data[i]);
76 | }
77 |
78 | return {
79 | statusCode: 200,
80 | headers: {
81 | 'Content-type': 'application/json',
82 | },
83 | };
84 | } catch (e) {
85 | console.error(e);
86 | return {
87 | statusCode: 500,
88 | body: JSON.stringify(e),
89 | };
90 | }
91 | };
92 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | When contributing to this repository, please first discuss the change you wish to make via issue,
4 | email, or any other method with the owners of this repository before making a change.
5 |
6 | Please note we have a [Code of Conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with the project.
7 |
8 | ## Found an Issue?
9 | If you find a bug in the source code or a mistake in the documentation, you can help us by
10 | [submitting an issue](#submit-issue) to the GitHub Repository. Even better, you can
11 | [submit a Pull Request](#submit-pr) with a fix.
12 |
13 | ## Want a Feature?
14 | You can *request* a new feature by [submitting an issue](#submit-issue) to the GitHub
15 | Repository. If you would like to *implement* a new feature, please submit an issue with
16 | a proposal for your work first, to be sure that we can use it.
17 |
18 | * **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
19 |
20 | ## Contribution Guidelines
21 |
22 | ### Submitting an Issue
23 | Before you submit an issue, search the archive, maybe your question was already answered.
24 |
25 | If your issue appears to be a bug, and hasn't been reported, open a new issue.
26 | Help us to maximize the effort we can spend fixing issues and adding new
27 | features, by not reporting duplicate issues. Providing the following information will increase the
28 | chances of your issue being dealt with quickly:
29 |
30 | * **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
31 | * **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
32 | * **Reproduce the Error** - provide a live example or a unambiguous set of steps
33 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
34 | causing the problem (line of code or commit)
35 |
36 | ### Submitting a Pull Request (PR)
37 | Before you submit your Pull Request (PR) consider the following guidelines:
38 |
39 | * Search the repository (https://github.com/bechbd/[repository-name]/pulls) for an open or closed PR that relates to your submission. You don't want to duplicate effort.
40 |
41 | * Create a fork of the repo
42 | * Navigate to the repo you want to fork
43 | * In the top right corner of the page click **Fork**:
44 | 
45 |
46 | * Make your changes in the forked repo
47 | * Commit your changes using a descriptive commit message
48 | * In GitHub, create a pull request: https://help.github.com/en/articles/creating-a-pull-request-from-a-fork
49 | * If we suggest changes then:
50 | * Make the required updates.
51 | * Rebase your fork and force push to your GitHub repository (this will update your Pull Request):
52 |
53 | ```shell
54 | git rebase master -i
55 | git push -f
56 | ```
57 |
58 | That's it! Thank you for your contribution!
--------------------------------------------------------------------------------
/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import FollowersColumn from '../components/FollowersColumn'
3 | import Card from '../components/Card'
4 | import MiniCard from '../components/MiniCard'
5 | import axios from 'axios'
6 |
7 | const Home = () => {
8 | const [users, setUsers] = useState(null)
9 | const [userToToggle, setUserToToggle] = useState(null)
10 |
11 | let descendingUsers
12 | let topFiveNotFollowing
13 | let topFiveFollowing
14 |
15 | //auto populating with dummy data
16 | const addData = async () => {
17 | await axios.post('/.netlify/functions/addData')
18 | }
19 |
20 | //fetch all the tik-tok posts to your feed
21 | const fetchData = async () => {
22 | const results = await axios.get('/.netlify/functions/posts')
23 | console.log(results.data)
24 | setUsers(results.data)
25 | }
26 |
27 | //toggle user from followed to unfollowed
28 | if (userToToggle) {
29 | const newValue = userToToggle.is_followed ? false : true
30 | const data = {is_followed: newValue}
31 |
32 | axios.put('/.netlify/functions/edit', {userId: userToToggle.id, data: data })
33 | .then(res => res.json())
34 | .then(json => console.log(json))
35 | .catch(err => console.error('error:' + err))
36 | .then(() => fetchData())
37 | setUserToToggle(null)
38 | }
39 |
40 | useEffect(() => {
41 | addData()
42 | fetchData()
43 | }, [])
44 |
45 | if (users) {
46 | descendingUsers = users.sort((a, b) => a.id < b.id ? 1 : -1)
47 | const following = users.filter(user => user.is_followed === true)
48 | const descendingFollowing = following.sort((a, b) => a.likes < b.likes ? 1 : -1)
49 | topFiveFollowing = descendingFollowing.slice(0, 5)
50 |
51 | const notFollowing = users.filter((user) => user.is_followed === false)
52 | const descendingNotFollowing = notFollowing.sort((a, b) => a.likes < b.likes ? 1 : -1)
53 | topFiveNotFollowing = descendingNotFollowing.slice(0, 5)
54 | }
55 |
56 | return (
57 | <>
58 | {descendingUsers && (
59 |
27 |
28 |
29 |
30 | **🔵 API:** is a backend serving real time data through either REST or GraphQL, endpoints to interact with fetch, ajax,axios
31 |
32 |
42 |
43 |
44 |
45 | **🔵 Markup:** can be either plain old HTML or static content like markdown. This is the nature of markup that will determine the static page generator technology
46 |
47 |
57 |
58 |
59 |
60 | **🔵 Static page generator**
61 |
62 | They apply data and content to templates, and generate a view of a page which can be served to the visitors of a site.
63 |
64 | The greatest difference between a static site generator and a traditional web application stack, is that instead of waiting until a page is requested and then generating its view on demand each time, a static site generator does this in advance so that the view is ready to serve ahead of time. And it does so for every possible view of a site at build time.
65 |
66 | 
67 |
68 | It improves performance and high compatibility with its rendering. *Automates code splitting, image optimization, inlining critical styles, lazy-loading, prefetching resources, and more to ensure your site is fully optimized. No manual tuning required.*
69 |
70 | You can find a pretty exhaustive list [here](https://jamstack.org/generators/).
71 |
72 | **🔵 CDN:** : geographically distributed group of servers which work together to provide fast delivery of Internet content.
73 |
74 | A CDN allows for the quick transfer of assets needed for loading Internet content including HTML pages, javascript files, stylesheets, images, and videos. The popularity of CDN services continues to grow, and today the majority of web traffic is served through CDNs, including traffic from major sites like Facebook, Netflix, and Amazon.
75 |
76 | 
77 |
78 |
79 | **🔵 Logical Architecture**
80 |
81 | The core principles of **pre-rendering**, and **decoupling**, enable sites and applications to be delivered with greater confidence and resilience than ever before.
82 |
83 | 
84 |
85 | **🔵 Pre-rendering:**
86 |
87 | 
88 |
89 | **🔵 Decoupling:**
90 |
91 | 
92 |
93 | **🔵 Move to CDN:**
94 |
95 | 
96 |
97 | ## 2. Why this is cool ?
98 |
99 | 
100 |
101 | ### 🔐 2.1 - Security
102 |
103 | > *Do you remember `/wp-admin.php` ? Me too.* The elder Cedrick
104 |
105 | The Jamstack removes multiple moving parts and systems from the hosting infrastructure resulting in fewer servers and systems to harden against attack.
106 |
107 | Serving pages and assets as pre-generated files allows **read-only hosting** reducing attack vectors even further. Meanwhile dynamic tools and services can be provided by vendors with teams dedicated to securing their specific systems and providing high levels of service.
108 |
109 | 
110 |
111 | ### 🌐 2.2 - Scalalibility
112 |
113 | > *Have you ever Ddos Amazon CloudFront ? Neither have I* the elder Cedrick.
114 |
115 | When sites can be served entirely from a CDN there is no complex logic or workflow to determine what assets can be cached and when.
116 |
117 | With Jamstack sites everything can be cached in a content delivery network. With simpler deployments, built-in redundancy and **incredible load capacity.**
118 |
119 | 
120 |
121 | ### 🚀 2.3 - Performance
122 |
123 | 
124 |
125 | Page loading speeds have an impact on user experience and conversion. Jamstack sites remove the need to generate page views on a server at request time by instead generating pages ahead of time during a build.
126 |
127 | With all the pages are already available on a CDN close to the user and ready to serve, very high performance is possible without introducing expensive or complex infrastructure.
128 |
129 | 
130 |
131 | ### 🆘 2.4 - Maintainability
132 |
133 | 
134 |
135 | When hosting complexity is reduced, so are maintenance tasks. A pre-generated site, being served directly from a simple host or directly from a CDN does not need a team of experts to "keep the lights on".
136 |
137 | The work was done during the build, so now the generated site is stable and can be hosted without servers which might require patching, updating and maintain.
138 |
139 | 
140 |
141 | ### 📦 2.5 - Portability
142 |
143 | 
144 |
145 | Jamstack sites are pre-generated. That means that you can host them from a wide variety of hosting services and have greater ability to move them to your preferred host. Any simple static hosting solution should be able to serve a Jamstack site.
146 |
147 | Bye-bye infrastructure lock-in.
148 |
149 | ### 💡 2.6 - Developer Experience
150 |
151 | 
152 |
153 | Let us show you this one today
154 |
155 | ## 3. Introduction to Netlify
156 |
157 | > *Source [https://www.netlify.com](https://www.netlify.com/)*
158 |
159 | ### 3.1 Netlify in a nutshell
160 |
161 | **Decoupling the frontend from the backend**: Unlike the large legacy apps, Jamstack projects neatly separate the frontend pages and UI from the backend apps and databases. Freed from backend servers, the frontend can then be deployed globally, directly to a CDN.
162 |
163 | **Dynamic content via APIs**: The global frontend uses Javascript and APIs to talk to backend services, allowing pages to be enhanced and personalized.
164 |
165 | *overview of netlify*
166 | 
167 |
168 | ### 3.2 Soooooooooo What about today ?
169 |
170 | - We will have our code in GITHUB.
171 |
172 | - Netlify is integrated with GITHUB, on a new commit it will BUILD and deploy the SITE on the CDN.
173 |
174 | - To code and commit to github we will use an IDE. You can use your own or we will provide you one in the Cloud called GITPOD.
175 |
176 | - The application we will deploy is BattleStax. This is not only static content but also a REST API to retrieve Data from a DB. The DB is DataStax Astra.
177 |
178 |
179 | 
180 |
181 | ## 4. Want to learn more ?
182 |
183 |
184 | **Angular vs VueJS vs React**
185 | 1. 🎥 [Angular vs React vs Vue [2020 Update]](https://www.youtube.com/watch?v=lYWYWyX04JI)
186 | 2. 🎥 [React vs. Angular vs. Vue: Which Should You Choose](https://www.youtube.com/watch?v=xDhzYQ4VyCw)
187 | 1. 📄 [Angular vs Vue vs React: choosing the best framework in 2020](https://www.educative.io/blog/react-angular-vue-comparison)
188 | 2. 📄 [React vs Angular vs Vue.js — What to choose in 2020? (updated in 2020)](https://medium.com/techmagic/reactjs-vs-angular5-vs-vue-js-what-to-choose-in-2018-b91e028fa91d)
189 | 3. 📄 [Angular vs React vs Vue 2020](https://athemes.com/guides/angular-vs-react-vs-vue/)
190 |
191 | **Static site Generator (SSG)**
192 | 1. 📄 [What is a Static Site Generator? And 3 ways to find the best one](https://www.netlify.com/blog/2020/04/14/what-is-a-static-site-generator-and-3-ways-to-find-the-best-one/)
193 | 2. 📄 [List of static generators](https://jamstack.org/generators/)
194 |
195 |
196 | **Content Delivery Network (CDN)**
197 | 1. 🎥 [What is Content Delivery Network, by Ryan Sumner (4:32 min)](https://www.youtube.com/watch?v=Bsq5cKkS33I)
198 | 2. 🎥 [What is a CDN and why Developers should Care about using one (GOTO 2016) by Artur Bergman (32:10 min)](https://www.youtube.com/watch?v=farO15_0NUQ)
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/tutorial/images/firefox-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Astra DB TikTok Clone Workshop
3 |
4 | [](https://github.com/datastaxdevs/workshop-social-media-tiktok)
5 | [](http://www.apache.org/licenses/LICENSE-2.0)
6 | [](https://discord.com/widget?id=685554030159593522&theme=dark)
7 |
8 | ⏲️ **Duration :** 2 hours
9 |
10 | 🎓 **Level** Beginner to Intermediate
11 |
12 | A simple Tik-Tok clone running on Astra DB that leverages the Document API. You can see the Demo [here](https://fanciful-licorice-ea1437.netlify.app)
13 |
14 | 
15 |
16 | > [🔖 Accessing HANDS-ON](#-start-hands-on)
17 |
18 | ## 📋 Table of contents
19 |
20 | - **HouseKeeping**
21 | - [1. Objectives](#1---objectives)
22 | - [2. Frequently asked questions](#2---frequently-asked-questions)
23 | - [3. Materials for the Session](#3---materials-for-the-session)
24 | - [4. Homework](#4---homework)
25 | - **[LAB 1 - Getting Started with Database](#lab-1---getting-started-with-database)**
26 | - [1.1 - Create Astra Account](#11---getting-started-with-database)
27 | - [1.2 - Create Astra Database](#11---getting-started-with-database)
28 | - **[LAB 2 - Document API](#lab-2---document-api)**
29 | - [2.1 - Using Document API](#21-using-document-api)
30 | - [2.2 - Create Astra Credentials](#22---create-astra-credentials)
31 | - **[LAB 3 - IDE Setup](#lab-3---ide-setup)**
32 | - [3.1 - Netlify site setup](#31---netlify-site-setup)
33 | - [3.2 - Launch GitPod](#32---launch-gitpod)
34 | - [3.3 - Astra CLI Setup](#33---astra-cli-setup)
35 | - [3.4 - Netlify CLI Setup](#34---netlify-cli-setup)
36 | - [3.5 - Launch the application](#35-launch-your-app)
37 | - **[LAB 4 - Coding Against DB](#lab-4---coding-against-db)**
38 | - [4.1 - Document API](#41---document-api)
39 | - [4.2 - AstraJS Client](#42---astrajs-client)
40 | - [4.3 - Serverless configuration](#43---serverless-configuration)
41 | - [4.4 - React Component](#44---react-component)
42 | - **[LAB 5 - Netlify Deployments](#lab-5---netlify-deployments)**
43 | - [5.1 - Connect Netlify to your site](#51---connect-netlify-to-your-site)
44 | - [5.2 - Deploy to production](#52---deploy-to-production)
45 |
46 | ## Housekeeping
47 |
48 | ### 1 - Objectives
49 |
50 | - 🎯 How to build a frontend application using React Components
51 |
52 | - 🎯 How to build a backend with Javascript without Express.
53 |
54 | - 🎯 Learn how to use the @astrajs document API to quickly and easily interact with JSON documents
55 |
56 | - 🎯 Learn what is gitpod and how you can use it in your projects
57 |
58 | ### 2 - Frequently asked questions
59 |
60 |
61 |
62 | 1️⃣ Can I run this workshop on my computer?
63 |
64 |
There is nothing preventing you from running the workshop on your own machine. If you do so, you will need the following:
65 |
66 |
git installed on your local system
67 |
[node 15 and npm 7 or later](https://www.whitesourcesoftware.com/free-developer-tools/blog/update-node-js/)
68 |
69 |
70 | In this readme, we try to provide instructions for local development as well - but keep in mind that the main focus is development on Gitpod, hence we can't guarantee live support about local development in order to keep on track with the schedule. However, we will do our best to give you the info you need to succeed.
71 |
72 |
73 |
74 | 2️⃣ What other prerequisites are there?
75 |
76 |
77 |
You will need an Github account
78 |
You will need an Astra account don't worry, we'll work through that in the workshop
79 |
You will need enough real estate on screen, we will ask you to open a few windows and it would not fit on mobiles (tablets should be OK)
80 |
81 |
82 |
83 |
84 |
85 |
86 | 3️⃣ Do I need to pay for anything for this workshop?
87 |
88 | No. All tools and services we provide here are FREE. FREE not only during the session but also after.
89 |
90 |
91 |
92 | 4️⃣ Will I get a certificate if I attend this workshop?
93 |
94 | 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)*
95 |
96 |
97 |
98 | ### 3 - Materials for the Session
99 |
100 | 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:
101 |
102 | - [Slide deck](./slides/slides.pdf)
103 | - [Discord chat](https://bit.ly/cassandra-workshop)
104 | - [Questions and Answers](https://community.datastax.com/)
105 | - [What is JamStack?](jamstack.md)
106 | - [Video tutorial with Ania Kubow](#video-tutorial-with-ania-kubow)
107 |
108 | ### 4 - Homework
109 |
110 |
111 |
112 | Don't forget to complete your work and get your verified skill badge! Finish and submit your homework!
113 |
114 | 1. Complete the practice steps from this repository as described below. Take a screenshot and show us your deployed production TikTok clone up in Netlify.
115 | 2. (Optional extra credit) Watch the 2 hour Ania video [HERE](#video-tutorial-with-ania-kubow), build the app yourself, and show us the completed app.
116 | 3. Submit your homework [here](https://docs.google.com/forms/d/1BV5qJstc2Z8CV4XamolOLe5UjuDFoIunbMgpi4_iiys)
117 |
118 | That's it, you are done! Expect an email next week!
119 |
120 | # 🏁 Start Hands-on
121 |
122 | ## LAB 1 - Getting Started with Database
123 |
124 | ### 1.1 - Getting Started with Database
125 |
126 | _**`ASTRA`** is the simplest way to run both Cassandra and Pulsar with zero operations at all - just push the button and get your clusters. No credit card required_
127 |
128 | #### `✅.1.1.a`- Create Astra Account
129 |
130 | > ↗️ _Right Click and select open as a new Tab..._
131 | >
132 | > [](https://astra.dev/yt-12-14)
133 |
134 | #### `✅.1.1.b`- Create Astra Database
135 |
136 | - On the home page spot one of the 3 [Create Database] button. They are all doing the same thing.
137 |
138 | 
139 |
140 | - Use the following values when creating the database:
141 |
142 | | # | Field Name | Field Value |
143 | |----|--------------------|---------------------------------|
144 | | 1 | **Database Name** | `workshops` |
145 | | 2 | **Keyspace Name** | `tiktok_keyspace` |
146 | | 3 | **Cloud Provider** | `Google Cloud Plaform` |
147 | | 4 | **Area** | `North America` |
148 | | 5 | **Region** | `Moncks Corner, South Carolina` |
149 |
150 | > 🖥️ `Output`
151 | >
152 | > 
153 |
154 | - Now click `[Create Database button]` that became blue.
155 | - The database is initializing, wait for the DB the move from `[PENDING]` to `[ACTIVE]`
156 |
157 | > 🖥️ `Output`
158 | >
159 | > 
160 |
161 | - Click `[Go to Database]`
162 |
163 | #### `✅.1.1.c`- Database was already existing
164 |
165 | Here are some special situations you might encounter.
166 |
167 | > ℹ️ **Hibernated Database:**
168 | >
169 | > If the DB workshops already exists but is hibernated (you have not use it for a while):
170 | > - Click the `[Resume Database]` button on the top right-hand corner.
171 | >
172 | > 
173 |
174 | > ℹ️ **Database already exists, create keyspace `tiktok_keyspace`**
175 | >
176 | > If DB exists and is active but `tiktok_keyspace` keyspace is not present you need to create the keyspace.
177 | >
178 | > - Click button `[Add Keyspace]` on the database dashboard (bottom right-hand corner)
179 | > - Provide the keyspace name `tiktok_keyspace`
180 | > - Click button `[Save]`. The database will switch in maintenance mode for a few seconds, you are set.
181 | >
182 | > 
183 |
184 | ## LAB 2 - Document API
185 |
186 | ### 2.1 Using Document API
187 |
188 | #### `✅.2.1.a`- Open Swagger User Interface
189 |
190 | - (1) - Select your database in the left panel (if needed)
191 | - (2) - Select the tab `Connect`
192 | - (3) - Select the `Document API` bloc
193 | - (4) - In `Launch Swagger UI` right-click on the link to open in a new TAB
194 |
195 | 
196 |
197 | - You should access this screen
198 |
199 | > 🖥️ `Swagger UI`
200 | >
201 | > 
202 |
203 | #### `✅.2.1.b`- Lists Collections
204 |
205 | - (1) - Select the resource `GET/v2/namespaces/{namespace-id}/collections`
206 |
207 | 
208 |
209 | - (2) - Click the `[Try It Out]` button
210 |
211 | 
212 |
213 | - (3) - Populate the form with the following values
214 |
215 | |Field| Value|
216 | |---|---|
217 | |**X-Cassandra-Token**| _autopopulated_ |
218 | |**namespace-id**| `tiktok_keyspace` |
219 |
220 | - (4) - Click on `[Execute]` button
221 |
222 | The output is empty (expected):
223 |
224 | ```json
225 | []
226 | ```
227 |
228 | #### `✅.2.1.c`- Create Collection `story`
229 |
230 | - (1) - Select the resource `POST/v2/namespaces/{namespace-id}/collections`
231 |
232 | - (2) - Click the `[Try It Out]` button
233 |
234 | - (3) - Populate the form with the following values
235 |
236 | |Field| Value|
237 | |---|---|
238 | |**X-Cassandra-Token**| _autopopulated_ |
239 | |**namespace-id**| `tiktok_keyspace` |
240 | |**body**| `{"name":"story"}` |
241 |
242 | - (4) - Click on `[Execute]` button
243 |
244 | - (5) - You can see the output with `201` (created) code
245 |
246 | 
247 |
248 | - (6) - Following the steps in previous section list collections again, you should get
249 |
250 | > 🖥️ `Output`
251 | > ```json
252 | > {
253 | > "data": [
254 | > {
255 | > "name": "story",
256 | > "upgradeAvailable": false
257 | > }
258 | > ]
259 | >}
260 | >```
261 |
262 | #### `✅.2.1.d`- Create a first document
263 |
264 | With a document oriented API there is no strict schema to comply with. As such let us decide what a story could look like.
265 |
266 | - (1) - Select the resource `POST/v2/namespaces/{namespace-id}/collections/{collection-id}` _Create a new Document_
267 |
268 | - (2) - Click the `[Try It Out]` button
269 |
270 | - (3) - Populate the form with the following values
271 |
272 | |Field| Value|
273 | |---|---|
274 | |**X-Cassandra-Token**| _autopopulated_ |
275 | |**namespace-id**| `tiktok_keyspace` |
276 | |**collection-id**| `story` |
277 |
278 | **body:**
279 | ```json
280 | {
281 | "name": "Mo Farooq",
282 | "username": "mofarooq32",
283 | "avatar": "https://i.imgur.com/9KYq7VG.png",
284 | "is_followed": true,
285 | "video": "https://i.imgur.com/FTBP02Y.mp4",
286 | "caption": "These ducks are MEGA cute",
287 | "likes": 10,
288 | "comments": 2,
289 | "button_visible": true
290 | }
291 | ```
292 |
293 | - (4) - Click on `[Execute]` button
294 |
295 | - (5) - Should get a HTTP `201` (Created) and the output. A unique identifier has been created for our document.
296 |
297 | > 🖥️ `Output`
298 | > ```json
299 | > {
300 | > "documentId": "8aa07632-4ffb-46e5-9d78-b32e21847221"
301 | > }
302 | > ```
303 |
304 | #### `✅.2.1.e`- Search documents in a collections
305 |
306 | - (1) - Select the resource `GET /v2/namespaces/{namespace-id}/collections/{collection-id}` _Search documents in a collection_
307 |
308 | - (2) - Click the `[Try It Out]` button
309 |
310 | - (3) - Populate the form with the following values
311 |
312 | |Field| Value|
313 | |---|---|
314 | |**X-Cassandra-Token**| _autopopulated_ |
315 | |**namespace-id**| `tiktok_keyspace` |
316 | |**collection-id**| `story` |
317 | |**where**| `{"username": {"$eq": "mofarooq32"}}` |
318 |
319 | - (4) - Click on `[Execute]` button
320 |
321 | - (5) - You should get a result
322 |
323 | > 🖥️ `Output`
324 | > ```json
325 | > {
326 | > "data": {
327 | > "8aa07632-4ffb-46e5-9d78-b32e21847221": {
328 | > "avatar": "https://i.imgur.com/9KYq7VG.png",
329 | > "button_visible": true,
330 | > "caption": "These ducks are MEGA cute",
331 | > "comments": 2,
332 | > "is_followed": true,
333 | > "likes": 10,
334 | > "name": "Mo Farooq",
335 | > "username": "mofarooq32",
336 | > "video": "https://i.imgur.com/FTBP02Y.mp4"
337 | > }
338 | > }
339 | >}
340 | >```
341 | >
342 |
343 | #### `✅.2.1.f`- Update a document
344 |
345 | - (1) - Select the resource `PUT /v2/namespaces/{namespace-id}/collections/{collection-id}/{document-id}` _Create or update a document with the provided document-id_
346 |
347 | - (2) - Click the `[Try It Out]` button
348 |
349 | - (3) - Populate the form with the following values
350 |
351 | |Field| Value|
352 | |---|---|
353 | |**X-Cassandra-Token**| _autopopulated_ |
354 | |**namespace-id**| `tiktok_keyspace` |
355 | |**collection-id**| `story` |
356 | |**document-id**| document you got before here `8aa07632-4ffb-46e5-9d78-b32e21847221` |
357 |
358 | **body:**
359 | ```json
360 | {
361 | "name": "New Name",
362 | "username": "mofarooq32",
363 | "avatar": "https://i.imgur.com/9KYq7VG.png",
364 | "is_followed": true,
365 | "video": "https://i.imgur.com/FTBP02Y.mp4",
366 | "caption": "These ducks are MEGA cute",
367 | "likes": 10,
368 | "comments": 2,
369 | "button_visible": true
370 | }
371 | ```
372 |
373 | - (4) - Click on `[Execute]` button
374 |
375 | - (5) - You should get an updated document
376 |
377 | #### `✅.2.1.g`- Delete a document
378 |
379 | - (1) - Select the resource `DELETE /v2/namespaces/{namespace-id}/collections/{collection-id}/{document-id}
380 | ` _ Delete a document_
381 |
382 | - (3) - Populate the form with the following values
383 |
384 | |Field| Value|
385 | |---|---|
386 | |**X-Cassandra-Token**| _autopopulated_ |
387 | |**namespace-id**| `tiktok_keyspace` |
388 | |**collection-id**| `story` |
389 | |**document-id**| document you got before here `8aa07632-4ffb-46e5-9d78-b32e21847221` |
390 |
391 | - (4) - Click on `[Execute]` button
392 |
393 | - (5) - You should get a result code of `204`
394 |
395 | > 🖥️ `Output`
396 | > ```
397 | > Code 204
398 | > access-control-allow-credentials: true
399 | > access-control-allow-origin: https://50b31120-2303-4f45-a9dd-1cfb03e24ff1-us-east1.apps.astra.datastax.com
400 | > access-control-expose-headers: Date
401 | > date: Mon,12 Dec 2022 18:12:43 GMT
402 | > vary: Origin
403 | > ```
404 |
405 | ### 2.2 - Create Astra Credentials
406 |
407 | When using swagger in the user interface, you are already authenticated against the API. When using a third party application you will need a token.
408 |
409 | #### `✅.2.2.a`- Create Astra Credentials
410 |
411 | > ℹ️ _Skip this step is you already have a token. You can reuse the same token in our other workshops, too._
412 |
413 | - (1) - Go the `Organization Settings`
414 | - (2) - Go to `Token Management`
415 | - (3) - Pick the role `Database Admnistrator` on the select box
416 | - (4) - Click `Generate token`
417 |
418 | 
419 |
420 | #### `✅.2.2.b`- Download Astra Credentials
421 |
422 | - Click the **`Download CSV`** button. You are going to need these values here in a moment.
423 |
424 | 
425 |
426 | > **⚠️ Important**
427 | > ```
428 | > The instructor will show you on screen how to create a token
429 | > but will have to destroy to token immediately for security reasons.
430 | > ```
431 |
432 | Notice the clipboard icon at the end of each value.
433 | - `Client ID:` We will *not* use this during this workshop
434 | - `Client Secret:` We will *not* use this during this workshop
435 | - `Token:` ***This is your token!*** We will use it as a api Key to interact with APIS
436 |
437 | ## LAB 3 - IDE Setup
438 |
439 | ### 3.1 - Netlify Site Setup
440 |
441 | - (1) Click the button to deploy.
442 |
443 | > ↗️ _Right Click and select open as a new Tab..._
444 | >
445 | > [](https://app.netlify.com/start/deploy?repository=https://github.com/datastaxdevs/workshop-astra-tik-tok)
446 |
447 | - (2) - Authenticate with your github Account
448 |
449 | - (3) - Select an account and the github repository where to clone
450 |
451 | 
452 |
453 | - (4) - In netlify user interface click on `Site deploy in progress`
454 |
455 | >
456 |
457 | - (5) - Click the top deploy link to see the build process.
458 |
459 | >
460 |
461 | - (6) - Wait until the build complete `Netlify Build Complete`, **When you see Pushing to repository** you're ready to move on.
462 |
463 | >
464 |
465 | - (7) Scroll up to the top and click on the site name (it'll be after {yourlogin}'s Team next to the Netlify button).
466 |
467 | >
468 |
469 | - (8) - Click on the `GitHub` in `Deploys from GitHub` to get back to your new repository. Scroll to where you were in the README.
470 |
471 | >
472 |
473 | ### 3.2 - Launch GitPod
474 |
475 | #### `✅.3.2.a`- Open YOUR GITHUB REPOSITORY README
476 |
477 | - Click the button to launch the GitPod IDE from **YOUR** repository.
478 |
479 | #### WAIT! Before moving on ensure you are working out of YOUR repository, not the datastaxdevs repository.
480 |
481 | 
482 |
483 | If you are still using the `datastaxdevs` repo please ensure to follow the previous step, [step3](#3-clone-your-github-repository) to get to your repo.
484 |
485 | #### `✅.3.2.b`- Open Gitpod IDE
486 |
487 | > Last time, be certain to click this when you MOVED TO YOUR REPOSITORY (not `datastaxdevs`)
488 | >
489 | > ↗️ _Right Click and select open as a new Tab..._
490 | >
491 | > [](https://gitpod.io/from-referrer/)
492 |
493 | #### `✅.3.2.c`- Validating your not using `datastaxdevs`
494 |
495 | - From your GitPod terminal execute the following command
496 |
497 | ```bash
498 | git remote -v
499 | ```
500 |
501 | > 🖥️ `Output`
502 | > ```
503 | > origin https://github.com/clun/workshop-astra-tik-tok.git (fetch)
504 | > origin https://github.com/clun/workshop-astra-tik-tok.git (push)
505 | >If the result returned from the command displays **`datastaxdevs`** then you are not in the correct repository. If this is the case please [repeat step 3 above](#3-access-your-github-repository), otherwise just move on to the next step.
506 | > ```
507 | >
508 | ### 3.3 - Astra CLI Setup
509 |
510 | #### `✅.3.3.a`- Save your token
511 |
512 | Locate an open terminal and enter the following command replacing `` by the one we created before starting with `AstraCS:..` it should be in the CSV we download before
513 |
514 | ```
515 | astra setup -t
516 | ```
517 |
518 | #### `✅.3.3.b`- Validate your configuration
519 |
520 | - In the terminal panel in gitpod enter the following command:
521 |
522 | ```
523 | astra user list
524 | ```
525 |
526 | > 🖥️ `Output`
527 | >
528 | > ```
529 | > gitpod /workspace/workshop-astra-tik-tok (master) $ astra user list
530 | > +--------------------------------------+-----------------------------+---------------------+
531 | > | User Id | User Email | Status |
532 | > +--------------------------------------+-----------------------------+---------------------+
533 | > | b665658a-ae6a-4f30-a740-2342a7fb469c | cedrick.lunven@datastax.com | active |
534 | > +--------------------------------------+-----------------------------+---------------------+
535 | > ```
536 |
537 | #### `✅.3.3.c`- List Database to see `workshops`
538 |
539 | - In the terminal panel in gitpod enter the following command:
540 |
541 | ```
542 | astra db list
543 | ```
544 |
545 | > 🖥️ `Output`
546 | >
547 | > ```
548 | > +---------------------+--------------------------------------+---------------------+----------------+
549 | > | Name | id | Default Region | Status |
550 | > +---------------------+--------------------------------------+---------------------+----------------+
551 | > | mtg | dde308f5-a8b0-474d-afd6-81e5689e3e25 | eu-central-1 | ACTIVE |
552 | > | workshops | 50b31120-2303-4f45-a9dd-1cfb03e24ff1 | us-east1 | ACTIVE |
553 | > +---------------------+--------------------------------------+---------------------+----------------+
554 | > ```
555 |
556 | #### `✅.3.3.d`- Get db details
557 |
558 | - In the terminal panel in gitpod enter the following command:
559 |
560 | ```
561 | astra db get workshops
562 | ```
563 |
564 | > 🖥️ `Output`
565 | >
566 | > ```
567 | > gitpod /workspace/workshop-astra-tik-tok (master) $ astra db get workshops
568 | > +------------------------+-----------------------------------------+
569 | > | Attribute | Value |
570 | > +------------------------+-----------------------------------------+
571 | > | Name | workshops |
572 | > | id | 50b31120-2303-4f45-a9dd-1cfb03e24ff1 |
573 | > | Status | ACTIVE |
574 | > | Default Cloud Provider | GCP |
575 | > | Default Region | us-east1 |
576 | > | Default Keyspace | tiktok_keyspace |
577 | > | Creation Time | 2022-12-12T11:14:58Z |
578 | > | | |
579 | > | Keyspaces | [0] tiktok_keyspace |
580 | > | | |
581 | > | | |
582 | > | Regions | [0] us-east1 |
583 | > | | |
584 | > +------------------------+-----------------------------------------+
585 | > ```
586 |
587 | #### `✅.3.3.e`- Create configuration file
588 |
589 | - Create `.env` file
590 |
591 | ```
592 | astra db create-dotenv workshops -k tiktok_keyspace -r us-east1
593 | ```
594 |
595 | - Show content
596 |
597 | ```
598 | cat .env
599 | ```
600 |
601 | > 🖥️ `Output`
602 | >
603 | > ```
604 | > ASTRA_DB_APPLICATION_TOKEN="AstraCS:gfYSGwpaFNGmUZnZTvaCp......"
605 | > ASTRA_DB_GRAPHQL_URL="https://.....-us-east1.apps.astra.datastax.com/api/graphql/tiktok_keyspace"
606 | > ASTRA_DB_GRAPHQL_URL_ADMIN="https://.....-us-east1.apps.astra.datastax.com/api/graphql-admin"
607 | > ASTRA_DB_GRAPHQL_URL_PLAYGROUND="https://.....-us-east1.apps.astra.datastax.com/api/playground"
608 | > ASTRA_DB_GRAPHQL_URL_SCHEMA="https://.....-us-east1.apps.astra.datastax.com/api/graphql-schema"
609 | > ASTRA_DB_ID="....."
610 | > ASTRA_DB_KEYSPACE="tiktok_keyspace"
611 | > ASTRA_DB_REGION="us-east1"
612 | > ASTRA_DB_REST_URL="https://.....-us-east1.apps.astra.datastax.com/api/rest"
613 | > ASTRA_DB_REST_URL_SWAGGER="https://.....-us-east1.apps.astra.datastax.com/api/rest/swagger-ui/"
614 | > ASTRA_DB_SECURE_BUNDLE_PATH="/home/gitpod/.astra/scb/scb_....._us-east1.zip"
615 | > ASTRA_DB_SECURE_BUNDLE_URL="secured_url"
616 | > ASTRA_ORG_ID="f9460f14-9879-4ebe-83f2-48d3f3dce13c"
617 | > ASTRA_ORG_NAME="cedrick.lunven@datastax.com"
618 | > ASTRA_ORG_TOKEN="AstraCS:gfYSGwpaFNGmUZnZT....."
619 | > ```
620 |
621 | ### 3.4 - Netlify CLI Setup
622 |
623 | #### `✅.3.4.a`- Install the package
624 |
625 | In the `workshop-astra-tik-tok` directory run the following command to install the netlify-cli
626 |
627 | ```
628 | npm install -g netlify-cli
629 | ```
630 |
631 | > 🖥️ `Output`
632 | >
633 | >
634 |
635 |
636 | ### 3.5 Launch your app
637 |
638 | #### `✅.3.5.a`- Start application
639 |
640 | ```
641 | netlify dev
642 | ```
643 |
644 | The application should automatically launch in the GitPod preview pane. You might see an error in the log for this firt launch, some data is inserted to the database.
645 |
646 | > 🖥️ `Output`
647 |
648 | ```
649 | ◈ Netlify Dev ◈
650 | ◈ Ignored general context env var: LANG (defined in process)
651 | ◈ Injected .env file env var: ASTRA_DB_APPLICATION_TOKEN
652 | ◈ Injected .env file env var: ASTRA_DB_GRAPHQL_URL
653 | ◈ Injected .env file env var: ASTRA_DB_GRAPHQL_URL_ADMIN
654 | ◈ Injected .env file env var: ASTRA_DB_GRAPHQL_URL_PLAYGROUND
655 | ◈ Injected .env file env var: ASTRA_DB_GRAPHQL_URL_SCHEMA
656 | ◈ Injected .env file env var: ASTRA_DB_ID
657 | ◈ Injected .env file env var: ASTRA_DB_KEYSPACE
658 | ◈ Injected .env file env var: ASTRA_DB_REGION
659 | ◈ Injected .env file env var: ASTRA_DB_REST_URL
660 | ◈ Injected .env file env var: ASTRA_DB_REST_URL_SWAGGER
661 | ◈ Injected .env file env var: ASTRA_DB_SECURE_BUNDLE_PATH
662 | ◈ Injected .env file env var: ASTRA_DB_SECURE_BUNDLE_URL
663 | ◈ Injected .env file env var: ASTRA_ORG_ID
664 | ◈ Injected .env file env var: ASTRA_ORG_NAME
665 | ◈ Injected .env file env var: ASTRA_ORG_TOKEN
666 | ◈ Loaded function add http://localhost:8888/.netlify/functions/add.
667 | ◈ Loaded function addData http://localhost:8888/.netlify/functions/addData.
668 | ◈ Loaded function edit http://localhost:8888/.netlify/functions/edit.
669 | ◈ Loaded function posts http://localhost:8888/.netlify/functions/posts.
670 | ◈ Functions server is listening on 36661
671 | ◈ Setting up local development server
672 |
673 | ────────────────────────────────────────────────────────────────
674 | Netlify Build
675 | ────────────────────────────────────────────────────────────────
676 |
677 | ❯ Version
678 | @netlify/build 28.4.5
679 |
680 | ❯ Flags
681 | {}
682 |
683 | ❯ Current directory
684 | /workspace/workshop-astra-tik-tok
685 |
686 | ❯ Config file
687 | /workspace/workshop-astra-tik-tok/netlify.toml
688 |
689 | ❯ Context
690 | dev
691 |
692 | ────────────────────────────────────────────────────────────────
693 | 1. Run command for local development
694 | ────────────────────────────────────────────────────────────────
695 |
696 | ◈ Starting Netlify Dev with Create React App
697 |
698 | > tik-tok-stargate@0.1.0 start
699 | > react-scripts start
700 |
701 | ℹ 「wds」: Project is running at http://10.0.5.2/
702 | ℹ 「wds」: webpack output is served from
703 | ℹ 「wds」: Content not from webpack is served from /workspace/workshop-astra-tik-tok/public
704 | ℹ 「wds」: 404s will fallback to /
705 | Starting the development server...
706 |
707 | Compiled successfully!
708 |
709 | You can now view tik-tok-stargate in the browser.
710 |
711 | Local: http://localhost:3000
712 | On Your Network: http://10.0.5.2:3000
713 |
714 | Note that the development build is not optimized.
715 | To create a production build, use npm run build.
716 |
717 | ✔ Waiting for framework port 3000. This can be configured using the 'targetPort' property in the netlify.toml
718 |
719 | (dev.command completed in 9.4s)
720 |
721 | ┌─────────────────────────────────────────────────┐
722 | │ │
723 | │ ◈ Server now ready on http://localhost:8888 │
724 | │ │
725 | └─────────────────────────────────────────────────┘
726 |
727 | ⠦ Setting up the Edge Functions environment. This may take a couple of minutes.Request from ::ffff:192.168.9.75: POST /.netlify/functions/addData
728 | ⠧ Setting up the Edge Functions environment. This may take a couple of minutes.Request from ::ffff:192.168.9.75: GET /.netlify/functions/posts
729 | ⠙ Setting up the Edge Functions environment. This may take a couple of minutes.Response with status 200 in 341 ms.
730 | ⠦ Setting up the Edge Functions environment. This may take a couple of minutes.Response with status 200 in 1609 ms.
731 | ✔ Setting up the Edge Functions environment. This may take a couple of minutes.
732 | ```
733 |
734 | 
735 |
736 | ## LAB 4 - Coding Against DB
737 |
738 | ### 4.1 - Document API
739 |
740 | Using same instruction as #2.1 execute the following operation with the Document Api using swagger UI.
741 |
742 | #### `✅.4.1.a`- Reopen Swagger
743 |
744 | Now that we have locally deployed our TikTok app, let's take a look at this in our database. Head to your [Astra DB dashboard](astra.datastax.com) and click the `Connect` button next to your database ('workshops').
745 |
746 | 
747 |
748 | Then scroll down to the section called 'Launching SwaggerUI' and click the link. We'll be using SwaggerUI to make api calls to our database and see the results.
749 |
750 | 
751 |
752 | #### `✅.4.1.a`- List Collections
753 |
754 | Open up the first section labelled "List collections in namespace" and click the button "Try it out".
755 |
756 | 
757 |
758 | - Execture with `[Execute]` button
759 |
760 | > 🖥️ `Output`
761 | >
762 | > ```json
763 | > {
764 | > "data": [
765 | > {
766 | > "name": "story",
767 | > "upgradeAvailable": false
768 | > },
769 | > {
770 | > "name": "tktkposts",
771 | > "upgradeAvailable": false
772 | > }
773 | > ]
774 | > }
775 | > ```
776 |
777 | #### `✅.4.1.b`- List Documents of `tktkposts`
778 |
779 | - Open resource `GET /v2/namespaces/{namespace-id}/collections/{collection-id}` _Search documents in a collection_
780 |
781 | 
782 |
783 | - Populate the form with the following values
784 |
785 | |Field| Value|
786 | |---|---|
787 | |**X-Cassandra-Token**| _autopopulated_ |
788 | |**namespace-id**| `tiktok_keyspace` |
789 | |**collection-id**| `tktkposts` |
790 |
791 | Let the rest of the fields untouched. You can see that every query is paged and default page size is `3`.And we see all of the documents stored in our database.
792 |
793 | 
794 |
795 | > 🖥️ `Output`
796 | >
797 | > ```json
798 | > {
799 | > "pageState": "ATIA8H_____wf____w==",
800 | > "data": {
801 | > "0": {
802 | > "avatar": "https://i.imgur.com/jONHmE5.png",
803 | > "button_visible": true,
804 | > "caption": "Art is for everyone",
805 | > "comments": 20,
806 | > "id": 0,
807 | > "is_followed": true,
808 | > "likes": 231,
809 | > "name": "Lana Del Mont",
810 | > "timestamp": "2020-09-10T09:08:31.020Z",
811 | > "username": "lana_del_away",
812 | > "video": "https://i.imgur.com/H9UX0Jm.mp4"
813 | > },
814 | > "2": {
815 | > "avatar": "https://i.imgur.com/eX3hkoc.png",
816 | > "button_visible": true,
817 | > "caption": "Happiest of Birthdays my Angel",
818 | > "comments": 4,
819 | > "id": 2,
820 | > "is_followed": true,
821 | > "likes": 2,
822 | > "name": "Angela Lee",
823 | > "timestamp": "2020-04-10T09:08:31.020Z",
824 | > "username": "angiecakes",
825 | > "video": "https://i.imgur.com/al6MLay.mp4"
826 | > },
827 | > "3": {
828 | > "avatar": "https://i.imgur.com/IigY4Hm.png",
829 | > "button_visible": true,
830 | > "caption": "The new normal",
831 | > "comments": 2,
832 | > "id": 3,
833 | > "is_followed": false,
834 | > "likes": 10,
835 | > "name": "Nina Xen",
836 | > "timestamp": "2020-05-10T09:08:31.020Z",
837 | > "username": "nina_lina",
838 | > "video": "https://i.imgur.com/Kzvbeup.mp4"
839 | > }
840 | > }
841 | > }
842 | > ```
843 |
844 | ### 4.2 - AstraJS Client
845 |
846 | #### `✅.4.2.1` - Initialization
847 |
848 | We are using the `@astrajs/collections` library to make the connection using the Document API. To do so, we start by creating a `client`.
849 |
850 | (See: [functions/utils/astraClient.js](./functions/utils/astraClient.js))
851 |
852 | ```javascript
853 | const { createClient } = require("@astrajs/collections");
854 |
855 | let astraClient = null;
856 |
857 | const getAstraClient = async () => {
858 | if (astraClient === null) {
859 | astraClient = await createClient(
860 | {
861 | astraDatabaseId: process.env.ASTRA_DB_ID,
862 | astraDatabaseRegion: process.env.ASTRA_DB_REGION,
863 | applicationToken: process.env.ASTRA_DB_APPLICATION_TOKEN,
864 | },
865 | 30000
866 | );
867 | }
868 | return astraClient;
869 | };
870 | ```
871 |
872 | Here we are defining a new method called `getAstraClient` that uses the `createClient` method from our `astrajs` library to create a connection to our database. We then provide it the needed database credentials we added to our environment variables earlier;
873 |
874 | - `ASTRA_DB_ID` _(unique identifier for a db)_
875 | - `ASTRA_DB_REGION` _(cloud region, here `us-east1`)_
876 | - `ASTRA_DB_APPLICATION_TOKEN` _(credentials)_
877 |
878 | Then we return the `astraClient` we can then use in our API calls.
879 |
880 | We also need to create a document collection to store our data.
881 |
882 | ``` javascript
883 | const getCollection = async () => {
884 | const documentClient = await getAstraClient();
885 | return documentClient
886 | .namespace(process.env.ASTRA_DB_KEYSPACE)
887 | .collection("tktkposts");
888 | };
889 | ```
890 |
891 | In this method, we are using our previously created `getAstraClient` method to initialize the database connection, and then create a collection in the keyspace we defined in our environment variables;
892 |
893 | - `ASTRA_DB_KEYSPACE` (for us `tiktok_keyspace`)
894 |
895 | We will call the collection **tktkposts**.
896 |
897 | #### `✅.4.2.b` - Create document with `@astrajs/collections`
898 |
899 | For our TikTok app, we will not be dealing with the Document API directly. Instead `@astrajs/collections` does that for us, and provides us with easy to use methods.
900 |
901 | If you want a comprehensive list of the capabilities of `@astrajs/collections`, check out this documentation: [AstraJS Collections](https://docs.datastax.com/en/astra/docs/astra-collection-client.html)
902 |
903 | The `create` method is used when we want to add documents to our collection. For example, in **`functions/add.js`** we get our collection from the database using our `getCollection` method.
904 |
905 | ``` javascript
906 | const users = await getCollection();
907 | ```
908 |
909 | Then we use the `create` method to create a document, providing the _id_ and _body_ of the document.
910 |
911 | ``` javascript
912 | try {
913 | const user = await users.create(id, event.body);
914 | return {
915 | statusCode: 200,
916 | body: JSON.stringify(user),
917 | };
918 | }
919 | ```
920 |
921 | #### `✅.4.2.c` - Update document with `@astrajs/collections`
922 |
923 | The `update` method is used to update portions of existing documents. Take a look at **`functions/edit.js`**. Again we use `getCollection()` to get our collection from the database, then we use the `update` method, provide it with an id for the document we want to edit, and the data that needs updating.
924 |
925 | ``` javascript
926 | try {
927 | users.update(body.userId, body.data);
928 | return {
929 | statusCode: 200,
930 | };
931 | }
932 | ```
933 |
934 | #### `✅.4.2.d` - Search document with `@astrajs/collections`
935 |
936 | And finally the `find` method is used to retrieve documents. In **`functions/posts.js`** we are again using `getCollections()` and using the `find` method on the result.
937 |
938 | ``` javascript
939 | try {
940 | const res = await users.find({});
941 | return {
942 | statusCode: 200,
943 | body: JSON.stringify(Object.keys(res).map((i) => res[i])),
944 | };
945 | }
946 | ```
947 |
948 | In this case, we are passing an empty object to retrieve all documents. In a real-world scenario, we would pass a qualifier to get only the documents relevant to a specific user.
949 |
950 | ### 4.3 - Serverless configuration
951 |
952 | Take a look at `netlify.toml`.
953 |
954 | ```init
955 | [build]
956 | command = "npm run build"
957 | functions = "functions"
958 | publish = "build"
959 | ```
960 |
961 | This is the configuration file we include in our codebase that tells Netlify how to build our app. In our case it's really simple. First we give the `build` command to build our app: `npm run build`. Then we tell Netlify where to find our serverless functions, and finally where to find the resulting app after build.
962 |
963 | So Netlify will create endpoints for our serverless functions based on the files it finds in our functions folder.
964 |
965 | For example, we have a function called `posts.js`. As we saw before, this function returns all of the current posts in our database. Netlify will see that file in our `functions` directory and dynamically create an endpoint at [/.netlify/functions/posts](./functions/posts.js)
966 |
967 | ```javascript
968 | // Declaring 'getCollection'
969 | const { getCollection } = require("./utils/astraClient");
970 |
971 | // Function exported as a REST API
972 | exports.handler = async function () {
973 | // Accessing the collection tkt
974 | const tktkpostsCollection = await getCollection();
975 | try {
976 | // Access POST
977 | const res = await tktkpostsCollection.find({});
978 | return {
979 | // Return POSTS in the body
980 | statusCode: 200,
981 | body: JSON.stringify(Object.keys(res).map((i) => res[i])),
982 |
983 | [...]
984 | ```
985 |
986 | ✅ We can see these functions in our Netlify account.
987 | - Go to netlify.com and sign in.
988 | - Select your site from the list.
989 | - Select the "Functions" tab at the top.
990 |
991 | 
992 |
993 | From here we can see all our functions and get direct links as well as watch real time logs.
994 |
995 | We can also see this in action by manually going to the endpoint on our Netlify site: `[your-site-url]/.netlify/functions/posts`.
996 |
997 | 
998 |
999 | ### 4.4 - React Component
1000 |
1001 | The front end leverages on React. The code is organized in pages and each pages import a list of components.
1002 |
1003 | #### `✅.4.4.a` - React Router
1004 |
1005 | There are 2 pages `updload` and `Home` and describe in [index.js](./src/index.js)
1006 |
1007 | ```xml
1008 |
1009 |
1010 |
1011 |
1012 | ```
1013 |
1014 | 
1015 |
1016 | #### `✅.4.4.b` - Upload Page
1017 |
1018 | Access through the `cloud` icon of directly on `/upload` it is a static HTML form to create new posts.
1019 |
1020 | 
1021 |
1022 | As you can see [Upload.js](./src/pages/Upload.js) there are no component used.
1023 |
1024 | ```html
1025 |