dtetreau251 / serverless

GNU General Public License v3.0
0 stars 1 forks source link

Deepsecrets #17

Closed dtetreau251 closed 3 years ago

ghost commented 3 years ago

Week 3 Step 7 ⬤⬤⬤⬤⬤⬤⬤◯◯ | 🕐 Estimated completion: 20-30 minutes

Leaky secrets

Store a message from Twilio in CosmosDB and return the most recent message

✅ Task:

❗ Make sure to return your message in this format:

Thanks 😊! Stored your secret "insert_user's_message". 😯 Someone confessed that: "the_most_recent_message"

🚧 Test Your Work

To test your work, send your Twilio number a text message. Once you do so, if you navigate to your Cosmos database account, go to Data Explorer, and the dropdowns underneath your new SecretStorer database, you should see an item that contains a message with your text message!

image

Important Note: If you are triggering the function for the first time, you may see an error message like the one below:

image

Don't worry! Try sending another text message, and everything should work fine the second time around. This error occurs because you don't have anything stored in CosmosDB yet.

💡 Yay! This means you've successfully connected Twilio with your Azure Cosmos database and Function.


1. Create your Cosmos Databases

Before we do anything else, we'll want to create our Cosmos DB account.

:question: How do I create my Cosmos DB account? 1. Navigate to your Azure Portal and click on `Azure Cosmos DB` under Azure Services. ![image](https://user-images.githubusercontent.com/49426183/120911257-90857400-c63a-11eb-9046-d9a7401e24af.png) 2. Click `Create Azure Cosmos DB Account`. ![image](https://user-images.githubusercontent.com/49426183/120911303-405ae180-c63b-11eb-98eb-6a1fedcad05c.png) 3. Under `Select API Option`, choose `Core (SQL) - Recommended`. ![image](https://user-images.githubusercontent.com/49426183/120911316-5d8fb000-c63b-11eb-8466-f7bfc938d1f8.png) 4. Fill in your account name, leave default options as they are, and click `Review + create`. ![image](https://user-images.githubusercontent.com/49426183/120911344-b52e1b80-c63b-11eb-82ff-e6b5f2e9075a.png) 5. Click `Create` a final time. ![image](https://user-images.githubusercontent.com/49426183/120911368-e7d81400-c63b-11eb-9855-686d444eb1ec.png) 6. Once deployment is complete, click `Go to resource`. ![image](https://user-images.githubusercontent.com/49426183/120911461-83698480-c63c-11eb-8260-b622013485a3.png)

1. Install @azure/cosmos

Now that your Azure Cosmos DB account is created, we should install the npm package @azure/cosmos.

🔧 1. Configuration

First, we need to instantiate a variable CosmosClient from the @azure/cosmos package we just downloaded.

const CosmosClient = require("@azure/cosmos").CosmosClient;

Create a config object that contains all of the sensitive information that we need to manipulate our data.

Call it config, and place keys for endpoint, key, databaseId, containerId, and partitionKey.

:question: What should my config object look like? Here is an example of the config object. Make sure your databaseId, containerId, and partitionKey are correct. ```js const config = { endpoint: process.env.ENDPOINT, key: process.env.KEY, databaseId: "SecretStorer", containerId: "secrets", partitionKey: {kind: "Hash", paths: ["/secrets"]} }; ```

2. The create Function

Now, we want to write an asynchronous create function that takes in the parameter of client (this will be our CosmosClient).

This function will:

⭐️ Use the client to create a database with an id of config.databaseId if it does not exist. ```js const { database } = await client.databases.createIfNotExists({ id: config.databaseId }); ```
⭐️ Use the client to create a container inside the database of ID config.databaseId. This container will have an ID of config.containerId and a key of config.partitionKey. ```js const { container } = await client .database(config.databaseId) .containers.createIfNotExists( { id: config.containerId, key: config.partitionKey }, { offerThroughput: 400 } ); ```

:bulb: Hint: The config.[value] variables are accessed from the config object you created earlier.

📜 2. The createDocument Function

Next, we need to create another asynchronous function called createDocument that will take in a parameter of newItem.

This function will create a new document within the database container that contains the newItem data.

In its entirety, the function will:

⭐️ Use the global config object to create the database and container if they do not exist. (Hint: this uses the create function we just implemented!) ```js var { endpoint, key, databaseId, containerId } = config; const client = new CosmosClient({endpoint, key}); const database = client.database(databaseId); const container = database.container(containerId); await create(client, databaseId, containerId); ```
⭐️ Create and execute a query that uses SQL language to fetch the most recent data document. This SQL query requests for the "top 1" document when it is orderd by `c._ts`, or the timestamp, in descending order. ```js const querySpec = { query: "SELECT top 1 * FROM c order by c._ts desc" }; ``` Using the query `querySpec`, it will use the `container` we created to fetch the most recent document! ```js const { resources: items } = await container.items.query(querySpec).fetchAll(); ```
⭐️ Create an document for your database that contains the information passed through the parameter `newItem`. ```js const {resource: createdItem} = await container.items.create(newItem); ```

Finally, it should return your items object from the function which contains the most recent message.

3. The Main Function

Instead of directly passing queryObject.Body (the SMS message) to context.res:

:question: How do I create a new document with queryObject.Body? ```js const queryObject = querystring.parse(req.body); let message = queryObject.Body; let document = {"message" : message} let items = await createDocument(document) ```

Your response message can then look something like:

const responseMessage = `Thanks 😊! Stored your secret "${message}". 😯 Someone confessed that: ${JSON.stringify(items[0].message)}`
ghost commented 3 years ago

Week 3 Step 8 ⬤⬤⬤⬤⬤⬤⬤⬤◯ | 🕐 Estimated completion: 10-20 minutes

Exposed!!

✅ Task:

Modify the deepsecrets Azure Function to

❗ Make sure to return your message in this format:

Thanks 😊! Stored your secret "insert_user's_message". 😯 Someone confessed that: "a_random_secret"

🚧 Test Your Work

To test your work, send your Twilio number a text message. You should still receive a text back that contains a message similar to the one below, but now the second secret returned will be random, and no longer the most recent secret stored!

Thanks 😊! Stored your secret "insert_user's_message". 😯 Someone confessed that: "a_random_secret"

💡 Yay! This means you've successfully queried for and returned a random secret.


1. Modifying the SQL Query

In your createDocument function, you'll first want to modify the original SQL query to now query for all secrets inside your container.

:question: How do I select all secrets? ```js const querySpec = { query: "SELECT * from c" }; ```

2. Selecting a Random Item

Next, you'll want to select a random secret by:

  1. Generating a random integer that is strictly less than the length of the array of secrets. (Hint: use Math.floor() and Math.random())
  2. Returning the secret at an index of this random number.
:question: How do I generate a random number for the index? The `Math.floor()` function returns the [floor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor) of the given number - ie. the largest integer less than or equal to a given number. In the example below, the generated random number will never be greater than `items.length`. ```js var random_value = Math.floor(items.length * Math.random()); ```

:bulb: Make sure to change your responseMessage to return the correct index of items.

ghost commented 3 years ago

📝 Week 3 Livestream Feedback

Please complete after you've viewed the Week 3 livestream! If you haven't yet watched it but want to move on, just close this issue and come back to it later.

Comment your feedback:

Help us improve BitCamp Serverless - thank you for your feedback! Here are some questions you may want to answer:

:camping: To move on, comment your feedback.

dtetreau251 commented 3 years ago

How was the content? Good! Did it help you? Yes! It was great learning about databases. Was it too challenging or too easy? Just right. Did it help you complete the week's homework? Yes. How was the pace? Was it hard to follow along? No. Just verbiage changes needed at times in the instructions to make things more clear. Did we go too slow? No. If you could add/improve something to/in the livestream, what would it be? Refine instructions

ghost commented 3 years ago

Providing Feedback

What was confusing about this week? If you could change or add something to this week, what would you do? Your feedback is valued and appreciated!

dtetreau251 commented 3 years ago

What was confusing about this week? ENDPOINT and KEY should be COSMOS_ENDPOINT and COSMOS_KEY in instructions If you could change or add something to this week, what would you do? Refine verbiage.

ghost commented 3 years ago

⏰ Time to merge!

Go ahead and merge this branch to main to move on. Great work finishing this section!

merge

⚠️ If you receive a Conflicts error, simply press Resolve conflicts and you should be good to merge!