Skip to content

Commit

Permalink
Contains changes for updates to module (#7)
Browse files Browse the repository at this point in the history
* Adds the abiilty to get the connection string

* Refactor to more complete api

* Fix readme

* Fix base API project

* Split db creation into 2 parts

* Remove line

* lowercase file extension

* chmod=+x GET_CONNECTION_STRING.sh

* Upgrade to new Cosmos DB SDK

* 2 minutes

Co-authored-by: Nick Walker <nickwalk@microsoft.com>
  • Loading branch information
burkeholland and nickwalkmsft authored Dec 5, 2020
1 parent 8f0a8ed commit e0a1892
Show file tree
Hide file tree
Showing 21 changed files with 314 additions and 45 deletions.
5 changes: 5 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"ms-azuretools.vscode-azurefunctions"
]
}
12 changes: 12 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Node Functions",
"type": "node",
"request": "attach",
"port": 9229,
"preLaunchTask": "func: host start"
}
]
}
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"azureFunctions.deploySubpath": "api",
"azureFunctions.postDeployTask": "npm install",
"azureFunctions.projectLanguage": "TypeScript",
"azureFunctions.projectRuntime": "~3",
"debug.internalConsoleOptions": "neverOpen",
"azureFunctions.preDeployTask": "npm prune"
}
43 changes: 43 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "func",
"command": "host start",
"problemMatcher": "$func-node-watch",
"isBackground": true,
"dependsOn": "npm build",
"options": {
"cwd": "${workspaceFolder}/api"
}
},
{
"type": "shell",
"label": "npm build",
"command": "npm run build",
"dependsOn": "npm install",
"problemMatcher": "$tsc",
"options": {
"cwd": "${workspaceFolder}/api"
}
},
{
"type": "shell",
"label": "npm install",
"command": "npm install",
"options": {
"cwd": "${workspaceFolder}/api"
}
},
{
"type": "shell",
"label": "npm prune",
"command": "npm prune --production",
"dependsOn": "npm build",
"problemMatcher": [],
"options": {
"cwd": "${workspaceFolder}/api"
}
}
]
}
24 changes: 2 additions & 22 deletions DB_SETUP/CREATE_DATABASE.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,5 @@ echo "Beginning database creation process..."
groupName=$(az group list --query "[0].name" -o tsv)

echo "Creating Cosmos DB database $accountName in Resource Group $groupName..."
echo "This can take up to 10 minutes. Feel free to continue with the Learn Module. Just make sure to keep this terminal running."
az cosmosdb create -n $accountName -g $groupName -o none

echo "Creating 'tailwind' database in $accountName..."
az cosmosdb sql database create -a $accountName -g $groupName -n $databaseName -o none

echo "Creating 'products' collection in 'tailwind' database..."
az cosmosdb sql container create -g $groupName -a $accountName -d $databaseName -n $containerName -p /brand/name -o none

echo "Preparing to import data..."

endpoint=https://$accountName.documents.azure.com:443
key=$(az cosmosdb list-keys -g $groupName -n $accountName --query "primaryMasterKey" -o json)

echo "Installing Node modules..."

npm i --silent

echo "Populating database..."
node ./POPULATE_DATABASE.js --endpoint $endpoint --key $key --databaseName $databaseName --containerName $containerName

echo "Finished! Your database, $accountName, is now ready."
echo "This can take up to 10 minutes. Feel free to continue with the Learn Module."
az cosmosdb create -n $accountName -g $groupName -o none
30 changes: 30 additions & 0 deletions DB_SETUP/GET_CONNECTION_STRING.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
databaseName=tailwind
containerName=products

# Get the connection string
echo "Getting connection string. This might take up to two minutes as we prepare the database..."

# Get the account name, which is randomized
accountName=$(az cosmosdb list --query "[0].name" -o tsv)

# Get the group name, which is preassigned
groupName=$(az group list --query "[0].name" -o tsv)

# Create the database
az cosmosdb sql database create -a $accountName -g $groupName -n $databaseName -o none

# Add products data
az cosmosdb sql container create -g $groupName -a $accountName -d $databaseName -n $containerName -p /brand/name -o none

endpoint=https://$accountName.documents.azure.com:443
key=$(az cosmosdb keys list -g $groupName -n $accountName --type keys --query "primaryMasterKey" -o json)

## silent npm install
npm install > "/dev/null" 2>&1

node ./POPULATE_DATABASE.js --endpoint $endpoint --key $key --databaseName $databaseName --containerName $containerName

echo "This is your connection string. Copy it to your clipboard..."
az cosmosdb keys list -n $accountName -g $groupName --type connection-strings --query "connectionStrings[0].connectionString" -o tsv


22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
page_type: sample
languages:
- javascript
- javascript
products:
- azure
- azure
description: "Products Manager application for Serverless API Learn Module"
urlFragment: "mslearn-build-api-azure-functions"
---
Expand All @@ -24,15 +24,15 @@ This is a sample web application frontend for the Serverless API Learn Module.

Outline the file contents of the repository. It helps users navigate the codebase, build configuration and any related assets.

| File/folder | Description |
| ----------------- | ---------------------------------------------------------- |
| `frontend` | The frontend website for the Products Manager application. |
| `api` | An empty folder where the user will create the API project |
| `.gitignore` | Define what to ignore at commit time. |
| `CHANGELOG.md` | List of changes to the sample. |
| `CONTRIBUTING.md` | Guidelines for contributing to the sample. |
| `README.md` | This README file. |
| `LICENSE` | The license for the sample. |
| File/folder | Description |
| ----------------- | ----------------------------------------------------------------------------- |
| `frontend` | The frontend website for the Products Manager application. |
| `api` | A base Azure Functions project where the user will finish out the API project |
| `.gitignore` | Define what to ignore at commit time. |
| `CHANGELOG.md` | List of changes to the sample. |
| `CONTRIBUTING.md` | Guidelines for contributing to the sample. |
| `README.md` | This README file. |
| `LICENSE` | The license for the sample. |

## Prerequisites

Expand Down
20 changes: 20 additions & 0 deletions api/CreateProduct/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
],
"scriptFile": "../dist/CreateProduct/index.js"
}
21 changes: 21 additions & 0 deletions api/CreateProduct/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import productsService from "../services/productsService";

const httpTrigger: AzureFunction = async function (
context: Context,
req: HttpRequest,
): Promise<void> {
let response;

try {
const product = req.body;
const result = await productsService.create(product);
response = { body: result, status: 200 };
} catch (err) {
response = { body: err.message, status: 500 };
}

context.res = response;
};

export default httpTrigger;
3 changes: 3 additions & 0 deletions api/CreateProduct/sample.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "Azure"
}
20 changes: 20 additions & 0 deletions api/DeleteProduct/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
],
"scriptFile": "../dist/DeleteProduct/index.js"
}
22 changes: 22 additions & 0 deletions api/DeleteProduct/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import productsService from "../services/productsService";

const httpTrigger: AzureFunction = async function (
context: Context,
req: HttpRequest,
): Promise<void> {
let response;

try {
const id = req.params.id;
const brand = req.body.brand;
const result = await productsService.delete(id, brand.name);
response = { body: result, status: 200 };
} catch (err) {
response = { body: err.message, status: 500 };
}

context.res = response;
};

export default httpTrigger;
3 changes: 3 additions & 0 deletions api/DeleteProduct/sample.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "Azure"
}
1 change: 0 additions & 1 deletion api/README.MD

This file was deleted.

20 changes: 20 additions & 0 deletions api/UpdateProduct/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
],
"scriptFile": "../dist/UpdateProduct/index.js"
}
21 changes: 21 additions & 0 deletions api/UpdateProduct/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { AzureFunction, Context, HttpRequest } from "@azure/functions";
import productsService from "../services/productsService";

const httpTrigger: AzureFunction = async function (
context: Context,
req: HttpRequest,
): Promise<void> {
let response;

try {
const product = req.body;
const result = await productsService.update(product);
response = { body: result, status: 200 };
} catch (err) {
response = { body: err.message, status: 500 };
}

context.res = response;
};

export default httpTrigger;
3 changes: 3 additions & 0 deletions api/UpdateProduct/sample.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "Azure"
}
20 changes: 20 additions & 0 deletions api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "api",
"version": "1.0.0",
"description": "",
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"prestart": "npm run build",
"start": "func start",
"test": "echo \"No tests yet...\""
},
"dependencies": {
"@azure/cosmos": "^3.9.3"
},
"devDependencies": {
"@azure/functions": "^1.0.2-beta2",
"@types/node": "^14.14.10",
"typescript": "^3.3.3"
}
}
40 changes: 40 additions & 0 deletions api/services/productsService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { CosmosClient } from "@azure/cosmos";

// Set connection string from CONNECTION_STRING value in local.settings.json
const CONNECTION_STRING = process.env.CONNECTION_STRING;

const productService = {
init() {
try {
this.client = new CosmosClient(CONNECTION_STRING);
this.database = this.client.database("tailwind");
this.container = this.database.container("products");
} catch (err) {
console.log(err.message);
}
},
async create(productToCreate) {
const { resource } = await this.container.items.create(productToCreate);
return resource;
},
async read(): Promise<string> {
const iterator = this.container.items.readAll();
const { resources } = await iterator.fetchAll();
return JSON.stringify(resources);
},
async update(product) {
const { resource } = await this.container.item(
product.id,
product.brand.name,
)
.replace(product);
return resource;
},
async delete(id, brandName) {
const result = await this.container.item(id, brandName).delete();
},
};

productService.init();

export default productService;
Loading

0 comments on commit e0a1892

Please sign in to comment.