- 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.json
configured 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
users
table ininit.db
purchases
resolver inUser
GraphQL 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
curl
inpsql/Dockerfile
) UUID.v7 as apostgres extension
ininit.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/hGet
and storing items as a JSON string (I implemented caching in GoLang before). In our caseitems
can changequantity
that means we would need amutex
duringpurchase()
, and preventhSet
while 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
items
only has some fields/rows compared to the Skinport API's json response - Implement password hashing/salting via
bcrypt
OR using aPSQL function
- Use Cookies/JWT for sessions. So I just used user's UUID defined prior in a variable in
WHERE
SQL queries. In real world we would get current user'suserId
(from cookie/jwt) and pass it throughApolloContext
to 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.
cd
into 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: "user@mail.com", 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_db
THENSELECT 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