- Made with Ruby on Rails and GraphQL
- Validate auth token for each request
- Currently generating tokens myself but in a production environment I'd use something like JWT)
- Access-role scoped Queries
- only an
Admin_User
can create or delete a product
- only an
- Create & sign in with Users
- using bcrypt gem to encrypt passwords
- each user has their own token which uniquely identifies them and their access-scope
- Unit-tests for basic functionality located in
test/graphql/resolvers
- Creating user, signing in with a user, creating/purchasing/deleting products
- Purchase products through cart
- flow goes: createCart -> addProductsToCart -> checkoutCart
The demo is available at azfaarshopify2019.herokuapp.com.
PS: since Heroku automatically sleeps free-tier applications it might take a minute to connect
This section will walk you through the functionality of the API. The Documentation
section further below will go more in depth about the specifics of the API
When you click the demo link you should see a page like:
The disclaimer is that, if you skipped through the documentation, you'll know that all all queries except the createUser or signinUser will return an authorization error because
Click the /graphiql
link to proceed
This page is exposed for the purposes of demonstration and so that you can interact with the API easily.
-
Currently, you are not signed in as anyone. If you try to make a query you will the following error:
"Not Authorized to make this request."
-
Before we can start using the API we have to
sign in
. There is support in the code to add more auth providers but for purposes of demonstration this application is using email & password for authentication. In a production environment we could have used google or another third party as an OAUTH provider-
There are two USER_ROLES
PUBLIC_USER
: can only "get" information from the APIADMIN_USER
: has all privileges of the API (i.e creating a product, deleting a product)
-
To create a user type the following:
mutation { createUser ( name:"First Name", authProvider: { email:{ email:"example@example.com", password: "password" } }, role: [ADMIN_USER] # Alternatively, [PUBLIC_USER] ) { email id name role } }
-
Now we signin with the following:
mutation { signinUser(email: { email: "example@example.com", password: "password" }) { token user { email id name role } } }
The token need not be saved anywhere, its already saved to the session. The API returns the token for the purposes of demonstration
-
Now that we're signed in, lets try the same query as before!
{ allProducts { title price inventory_count } }
-
-
Types of Queries
-
Notice how the
Wireless mouse
product has inventory 0? We can filter that out with the following:{ allProducts(available_inventory_only: true) { title price inventory_count id } }
-
We can also get Products one at a time through their ID:
{ getProduct(id: 5){ id title price inventory_count } }
-
We can try
getCart
but since we haven't created a cart yet, we should expect an error. Let's try it:{ getCart { cart_status { id name } id items { price title } subtotal } }
-
-
Mutators
-
Let's begin by creating an active cart first.
mutation { createCart { cart_status { id name } id items{ id title price } subtotal } }
and we get:
The cart will stay "In Progress" until we
checkout
the cart, and then it'll change to "Completed" -
We can create a product with:
mutation { createProduct( title: "mirror" price: 5.0 inventory_count: 1 ) { title id price inventory_count } }
- To demonstrate purchasing a product without having to go through creating a cart -> adding items to a cart -> completing a cart, I added a single
purchaseCart
function. We can also purchase products through the cart which we will do later. Let's purchase this product twice, to see what will happen when the inventory becomes 0.
mutation { purchaseProduct(id: 9){ title inventory_count id price } }
notice how the
inventory_count
, which was 1 previously, decrements to 0: Running this again gives us an expected error as you cannot purchase a product with no inventory!- Let's delete this product we just created.
mutation { deleteProduct(id: 9){ title price inventory_count } }
Lets just run it again to make sure it's deleted:
- Now for purchasing products through the cart. First we must add products to the cart:
mutation { addToCart(product_ids: [5,6,7]){ subtotal items { title price inventory_count } } }
- Finally, let's purchase the cart
mutation { purchaseCart { subtotal cart_status { name } items { price title } } }
Notice how the
cart_status
is now completed. If we run the same query again we can verify that the cart is no longer in use:- We can verify that the inventory_count has changed by running
allProducts
Query again
-