Notes on AWS
Possible understandings
Use Cases
Game Scoring
Use key like Pig-Game-JoeSmith Resident or Pig-Game-JoeUUID, store a JSON scorecard of your choosing.
Visitor Log
Suppose we wanted to keep a visitor log by visitor name, storing time and such. We’d naively want to have a key of name,time
or maybe just time
. We could use a full standard time-stamp lke 2018-08-03T142136Z
, with JSON or text info about that arrival, but how would we ever find anything?
There is an operation Query
, and another,, Scan
that can return a batch of records.
aws dynamodb scan \
--table-name Movies \
--projection-expression "title" \
--filter-expression 'contains(info.genres,:gen)' \
--expression-attribute-values '{":gen":{"S":"Sci-Fi"}}' \
--page-size 100 \
--debug
From https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Scan.html#Scan.Pagination
We could produce a general scan/continue scan operation somehow? You get back LastEvaluatedKey
and can provide ExclusiveStartKey
. There may be a PageSize
option to limit the number of records returned. There is also Limit
to limit the number processed (whether or not returned). Could be expensive.
Query
is used when you have a primary key with a subordinate sort key. That might make more sense for a visitor record with PK the avatar UUID and sort key the arrival timestamp. Then you could get all records for a given AV.
Possibly we should have our database include a sort key which would generally be blank but possibly used in some applications. For GetItem
you provide both PK and SK. Note also that PK (and SK?) can be composite items, apparently.
For our purposes perhaps we want a string PK and SK. PK and SK can each be only one attribute but can be of any type? Note below that both are of type S, and we’d surely use that. We’d recommend that most people use a fixed SK, probably empty string.
GetItem
requires PK and SK and returns an item. Query
, I think, can take PK and return all the SKs.
{
TableName : "KeyValue",
KeySchema: [
{
AttributeName: "Artist",
KeyType: "HASH", //Partition key
},
{
AttributeName: "SongTitle",
KeyType: "RANGE" //Sort key
}
],
AttributeDefinitions: [
{
AttributeName: "Artist",
AttributeType: "S"
},
{
AttributeName: "SongTitle",
AttributeType: "S"
}
],
ProvisionedThroughput: {
ReadCapacityUnits: 1,
WriteCapacityUnits: 1
}
}
Ban Log
Probably store PK = PerpID, SK = timestamp. Need query to access?
Notes en route
New api movies 6ri69o9kw5 resources/ qznvakztog
Adding ron again:
User name,Password,Access key ID,Secret access key,Console login link
ronjeffries@acm.org,,AKIAJRRAFBZ3YUWCTKBA,gmgDsPaqdg4Xajy50y5mx+Y51zBex/4Pz6MDOpxB,https://454572464863.signin.aws.amazon.com/console
Role arn:aws:iam::454572464863:role/aws_api_policy_vtrans
I think this is right and it seems to go thru.
Role trusted entities include apigateway.
Everything (I think) is in us-east-1 (VA)
Still getting resource not found. Bug was bad name favorite-movies not movies:
{
"TableName": "movies",
"Key": {
"name": {
"S": "$input.params('name')"
}
}
}
Works now. Wonder how I can dump the whole thing.
Record everything tomorrow.
Apparently we must next deploy the API to a stage … whatever those things mean …
I’m following this: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-from-example-console.html
Deployed current API Gateway
Invoke URL: https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001
Following that gives: {"message":"Missing Authentication Token"}
(makes sense)
Deployment stage is vt-001, various descriptions.
Doc says to expand the stage (triangle) and select the GET, get new invoke URL:
https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001/{name}
Pasting https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001/{ron}
returns
{}
Wow, pasting https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001/ron
returns
{"Item":{"name":{"S":"ron"},"title":{"S":"shrek"}}}
https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001/jan
returns
{"Item":{"name":{"S":"jan"},"title":{"S":"star wars"}}}
This should work in SL just fine. Let’s try it.
// http access to AWS API Gateway
// JR 2018-08-01
// https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001/{name}
string API = "https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001/jan";
key Query;
default {
touch_start(integer num_detected) {
if ( llDetectedKey(0) != llGetOwner() ) return;
Query = llHTTPRequest(API, [], "");
}
http_response(key request_id, integer status, list metadata, string body) {
if ( request_id == Query ) {
string r = llDumpList2String([status, body], "\n");
llOwnerSay(r);
}
}
}
And it works!!
Followed Knape to put in a PUT.
{
"TableName": "movies",
"Item": {
"name": {
"S": "$input.params('name')"
},
"title": {
"S": "$input.path('$.title')"
}
}
}
Works in test! Now to deploy. To vt-001 again:
Get: https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001/{name}
(same)
Put: https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001/{name}
(same)
Apparently, and sensibly, the addresses do not change on deployment. (Otherwise, all one’s apps would break on a new version.)
Difference will be GET/PUT in the call (and stuff in the body).
Remaining questions:
- How to do JSON?
- Can we create new tables and new fields this way?
- How do we find out the magical JSON meanings?
// http access to AWS API Gateway
// JR 2018-08-01
// https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001/{name}
string Short_API = "https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001/";
key Query;
default {
state_entry() {
llListen(33, "", llGetOwner(), "");
}
listen(integer channel, string name, key id, string msg) {
string api = Short_API + msg;
Query = llHTTPRequest(api, [], "");
}
touch_start(integer num_detected) {
if ( llDetectedKey(0) != llGetOwner() ) return;
Query = llHTTPRequest(Short_API + "fred", [], "");
}
http_response(key request_id, integer status, list metadata, string body) {
if ( request_id == Query ) {
string r = llDumpList2String([status, body], "\n");
llOwnerSay(r);
string v = llJsonGetValue(body, ["Item", "title", "S"]);
llOwnerSay("title is " + v);
}
}
}
// http write to AWS API Gateway
// JR 2018-08-01
// https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001/{name}
string Short_API = "https://53jm8kpora.execute-api.us-east-1.amazonaws.com/vt-001/";
key Query;
default {
state_entry() {
llListen(34, "", llGetOwner(), "");
}
listen(integer channel, string name, key id, string msg) {
list name_value = llCSV2List(msg);
string name = llStringTrim(llList2String(name_value, 0),STRING_TRIM);
string value = llStringTrim(llList2String(name_value, 1),STRING_TRIM);
string body = llList2Json(JSON_OBJECT, ["title", value]);
string api = Short_API + name;
llOwnerSay(llDumpList2String([api, body], "\n"));
Query = llHTTPRequest(api, [HTTP_METHOD, "PUT", HTTP_MIMETYPE, "application/json"], body);
}
http_response(key request_id, integer status, list metadata, string body) {
if ( request_id == Query ) {
string r = llDumpList2String([status, body], "\n");
llOwnerSay(r);
}
}
}
Deploying key-aux-value: https://tz70gb4ih6.execute-api.us-east-1.amazonaws.com/vt-kv-1
https://tz70gb4ih6.execute-api.us-east-1.amazonaws.com/vt-kv-1/query?key=bill
{"Count":3,"Items":[{"value":{"S":"this is bill's first value"},"vt_aux":{"S":"001"},"vt_key":{"S":"bill"}},{"value":{"S":"here is bill's #2 value"},"vt_aux":{"S":"002"},"vt_key":{"S":"bill"}},{"value":{"S":"here is bill number four"},"vt_aux":{"S":"004"},"vt_key":{"S":"bill"}}],"ScannedCount":3}