Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,26 @@ It will also auto-generate user votes over time for the questions there.

If you're curious about the technologies used in the server and client,
see their respective `README.md` files.

To run tests against a DynamoDB instance running [locally](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html), make sure
you got [`docker`](https://docs.docker.com/engine/install/) and
[`AWS CLI`](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html#getting-started-install-instructions) installed, then hit:

```console
$ cd server
$ make dynamodb
$ make test/e2e
```

Now, to develop against a local instance of DynamoDB, hit:

```console
$ make run
```

You can also spin a [Web UI](https://github.com/aaronshaf/dynamodb-admin?tab=readme-ov-file)
for your local Dynamodb with:

```console
$ make dynamodb/admin
```
3 changes: 2 additions & 1 deletion server/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/target
/target
/dynamodb-data
66 changes: 66 additions & 0 deletions server/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
DYNAMODB_CONTAINER_NAME=dynamodb-local
DYNAMODB_ADMIN_CONTAINER_NAME=dynamodb-admin
ENDPOINT_URL=http://localhost:8000

.PHONY: fmt
fmt:
cargo fmt

.PHONY: check
check:
cargo fmt --check
cargo clippy --all-features
cargo d --no-deps --all-features

.PHONY: run
run:
USE_DYNAMODB=1 AWS_ENDPOINT_URL=${ENDPOINT_URL} cargo run

.PHONY: test/e2e
test/e2e:
AWS_ENDPOINT_URL=${ENDPOINT_URL} cargo t -- --ignored

.PHONY: dynamodb
dynamodb:
Comment thread
jonhoo marked this conversation as resolved.
Outdated
@./run-dynamodb-local.sh ${DYNAMODB_CONTAINER_NAME} ${ENDPOINT_URL}

.PHONY: dynamodb/admin
dynamodb/admin:
@docker ps | grep ${DYNAMODB_ADMIN_CONTAINER_NAME} > /dev/null && \
echo "Already running. Use 'make dynamodb/admin/kill' first." && \
exit 0

echo "🚀 Spinning up a container with DynamoDB Admin..."
@(docker run -d --rm --net host --name ${DYNAMODB_ADMIN_CONTAINER_NAME} aaronshaf/dynamodb-admin) > /dev/null
echo "🔎 DynamoDB Admin is available at http://localhost:8001"

.PHONY: dynamodb/admin/kill
dynamodb/admin/kill:
@docker ps | grep ${DYNAMODB_ADMIN_CONTAINER_NAME} > /dev/null && \
docker stop ${DYNAMODB_ADMIN_CONTAINER_NAME} > /dev/null && \
echo "🧹 Done!" && exit 0
echo "Container '${DYNAMODB_ADMIN_CONTAINER_NAME}' not found.

.PHONY: dynamodb/list
dynamodb/list:
@aws dynamodb list-tables --endpoint-url ${ENDPOINT_URL} | jq .TableNames

.PHONY: dynamodb/describe/events
dynamodb/describe/events:
@aws dynamodb describe-table --table-name events --endpoint-url ${ENDPOINT_URL} | jq .Table

.PHONY: dynamodb/describe/questions
dynamodb/describe/questions:
@aws dynamodb describe-table --table-name questions --endpoint-url ${ENDPOINT_URL} | jq .Table

.PHONY: dynamodb/describe/gsi
dynamodb/describe/questions/gsi:
@aws dynamodb describe-table --table-name questions --endpoint-url ${ENDPOINT_URL} | jq .Table.GlobalSecondaryIndexes

.PHONY: dynamodb/kill
.ONESHELL: dynamodb/kill
dynamodb/kill:
@docker ps | grep ${DYNAMODB_CONTAINER_NAME} > /dev/null && \
docker stop ${DYNAMODB_CONTAINER_NAME} > /dev/null && \
echo "🧹 Done!" && exit 0
echo "Container '${DYNAMODB_CONTAINER_NAME}' not found."
55 changes: 55 additions & 0 deletions server/run-dynamodb-local.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env bash

DYNAMODB_CONTAINER_NAME=$1
ENDPOINT_URL=$2
Comment thread
jonhoo marked this conversation as resolved.
Outdated

docker ps | grep ${DYNAMODB_CONTAINER_NAME} >/dev/null &&
echo "Already running. Use 'make dynamodb/kill' first." &&
exit 0

echo "🖴 Preparing volumes for DynamoDB..."
rm -rf dynamodb-data
mkdir dynamodb-data

echo "🚀 Spinning up a container with DynamoDB..."
(
docker run --rm -d -v ./dynamodb-data:/home/dynamodblocal/data -p 127.0.0.1:8000:8000 \
-w /home/dynamodblocal --name ${DYNAMODB_CONTAINER_NAME} amazon/dynamodb-local:latest \
-jar DynamoDBLocal.jar -sharedDb -dbPath ./data
) >/dev/null

while ! (aws dynamodb list-tables --endpoint-url ${ENDPOINT_URL} >/dev/null 2>&1); do
echo "⏳ Waiting for the database to start accepting connections..."
done

echo "🗒️ Creating 'events' table..."
aws dynamodb create-table \
--table-name events \
--attribute-definitions AttributeName=id,AttributeType=S \
--key-schema AttributeName=id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST \
--endpoint-url ${ENDPOINT_URL} >/dev/null
aws dynamodb update-time-to-live \
--table-name events \
--time-to-live-specification Enabled=true,AttributeName=expire \
--endpoint-url ${ENDPOINT_URL} >/dev/null

echo "🗒️ Creating 'questions' table and 🚄 GSI..."
aws dynamodb create-table \
--table-name questions \
--attribute-definitions AttributeName=id,AttributeType=S \
AttributeName=eid,AttributeType=S \
AttributeName=votes,AttributeType=N \
--key-schema AttributeName=id,KeyType=HASH \
--global-secondary-indexes 'IndexName=top,KeySchema=[{AttributeName=eid,KeyType=HASH},{AttributeName=votes,KeyType=RANGE}],Projection={ProjectionType=INCLUDE,NonKeyAttributes=[answered,hidden]}' \
--billing-mode PAY_PER_REQUEST \
--endpoint-url ${ENDPOINT_URL} >/dev/null
aws dynamodb update-time-to-live \
--table-name questions \
--time-to-live-specification Enabled=true,AttributeName=expire \
--endpoint-url ${ENDPOINT_URL} >/dev/null

echo "✅ Done!"
echo
echo "💡To get details on a table, run 'make dynamodb/describe/<table_name>'"
echo "💡To spin up a Web UI for your local DynamoDB instance, hit 'make dynamodb/admin'"
11 changes: 4 additions & 7 deletions server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,10 @@ async fn main() -> Result<(), Error> {
.with_env_filter(EnvFilter::from_default_env())
.without_time(/* cloudwatch does that */).init();

#[cfg(debug_assertions)]
let backend = {
let backend = if !cfg!(debug_assertions) || std::env::var_os("USE_DYNAMODB").is_some() {
let config = aws_config::load_from_env().await;
Backend::Dynamo(aws_sdk_dynamodb::Client::new(&config))
} else {
use rand::prelude::SliceRandom;
use serde::Deserialize;
use std::time::Duration;
Expand Down Expand Up @@ -202,11 +204,6 @@ async fn main() -> Result<(), Error> {
});
state
};
#[cfg(not(debug_assertions))]
let backend = {
let config = aws_config::load_from_env().await;
Backend::Dynamo(aws_sdk_dynamodb::Client::new(&config))
};

let app = Router::new()
.route("/api/event", post(new::new))
Expand Down