- Users to login
- Change password
- Show all items in DB
- Purchase an item and return all the purchases made with the new balance (SQL update
$new_balance=$previous_balance-$item_pice)
tsconfig.jsonconfigured to be in strict mode- Use Docker “secrets” for important things like passwords, DB URLs, etc..
- .dockerignore for "secrets"
- For user balance: I used “micro-dollar” a concept used in financial industry to store money in a SQL database:
$amount * 1m - Utilise Postgres.js pipelining via transaction in
purchase() - Allowed currencies enum (USD, EUR, RUB, etc..) see
userstable ininit.db purchasesresolver inUserGraphQL type, so we can douser(id: **) { name, purchases { id, name, minPrice, tradable }}- Password hashing/salting (not implemented yet in Node, but I laid the foundation and left links to my research in SQL comments)
- Installed (via
curlinpsql/Dockerfile) UUID.v7 as apostgres extensionininit.db(UUID.v7 allows us toORDER BY id DESC) - Graceful shutdown for GraphQL (using
ApolloServerPluginDrainHttpServer()) - Built endpoints 1,2,3,4 accessed by GraphQL's playground
- Tests via Jest
- Caching bcz it's not as simple as using
hSet/hGetand storing items as a JSON string (I implemented caching in GoLang before). In our caseitemscan changequantitythat means we would need amutexduringpurchase(), and preventhSetwhile value is being changed. So we would need to use something like Redlock. Here's more Redlock stuff. - Write a script to scan the Skinport API to include/insert all of “items” into the items table, so I just wrote some INSERTs in
/psql/init.db - The table
itemsonly has some fields/rows compared to the Skinport API's json response - Implement password hashing/salting via
bcryptOR using aPSQL function - Use Cookies/JWT for sessions. So I just used user's UUID defined prior in a variable in
WHERESQL queries. In real world we would get current user'suserId(from cookie/jwt) and pass it throughApolloContextto use in our database/redis/etc.. - GraphQL custom error handling & error logging
- Show balance only to the account owner
- Also look at the code comments as I describe what I would do in production :)
These concepts are from my previous projects/experience, and the reasoning is: it’s easier to expand to a new machine by just copying the folders like /redis or /psql in case we need more disk space for Postgres or more RAM/Memory for Redis.
cdinto the pulled/downloaded project directory- Duplicate 2 more tabs in your terminal (you should now have 3 tabs)
- Tab 1:
cd psql>>docker compose up - Tab 2:
cd redis>>docker compose up - Tab 3:
cd server/docker>>docker compose up - Great! Now visit localhost/graphql to run some GraphQL queries 🚀
query { login(email: "[email protected]", password: "12345") { id, name, lang, currency, balance } }
mutation {
editUser(input: {password: "123456789"}) { id, name, lang, balance }
}
Try to run Endpoint 1 login query again = ❌ Error
To see password change in DB: RUN (in your terminal)
psql postgres://main:maindb-pas-36754321@localhost:28802/main_dbTHENSELECT passhash from users;.
query { items {
id,
name,
currency,
minPrice,
maxPrice,
quantity,
itemPage,
tradable,
createdAt
}}
Note: only 1 item in items table
mutation {
purchase(itemId: "0192f17a-ec4b-7a06-8923-01c011ca1912") {
id,
name,
balance,
purchases {
id,
name,
quantity
}
}
}
Run query multiple times, and see user's balance decrease