- Notifications
You must be signed in to change notification settings - Fork204
LoopBack 4 Example: Online Shopping APIs
License
loopbackio/loopback4-example-shopping
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
This project aims to represent an online ecommerce platform APIs to validate /test the LoopBack 4 framework readiness for GA. Seeloopbackio/loopback-next#1476 for more information.
Node.js >= 8.9.0 and running instances of a MongoDB and Redis server arerequired for the app to start. The Redis server is used for the shopping cart,while MongoDB is used for the rest of the models in the app.
Docker is required for running tests, make sure it is running if you want to runthe tests.
Do the following to clone and start the project.
In case you have Docker installed on your system and don't want to manuallyinstall MongoDB and Redis, you can runnpm run docker:start
to download theirimages and start the servers. Otherwise, you can skip this command.
$ git clone https://github.com/loopbackio/loopback4-example-shopping.git$cd loopback4-example-shopping$ npm i$ npm run docker:start$ npm start
The main app will be running athttp://localhost:3000. The shopping website(Shoppy) is athttp://localhost:3000/shoppy.html, and the API Explorer athttp://localhost:3000/explorer/.
You will also seeRecommendation server is running at http://localhost:3001.
,it is the server to which theservices/recommender.service
service willconnect to get the recommendations for a user.
The app will be pre-populated with some products and users when it starts; andall existing products, users, shopping cart and orders will be deleted too. Ifyou don't want to reset the database, setdatabaseSeeding
tofalse
in theapplication configuration object.
This repository comes with integration, unit, acceptance and end-to-end (e2e)tests. To execute these, see instructions below.
Note
: prior to running the e2e tests the application must be running. On adifferent terminal do:
$ npm start
then on another terminal do the following to execute e2e tests:
$ npm run test:ui
For other tests:
$ npmtest
This app has the following models:
User
- representing the users of the system.UserCredentials
- representing sensitive credentials like a password.Product
- a model which is mapped to a remote service byservices/recommender.service
.ShoppingCartItem
- a model for representing purchases.ShoppingCart
- a model to represent a user's shopping cart, can containmany items (items
) of the typeShoppingCartItem
.Order
- a model to represent an order by user, can have many products(products
) of the typeShoppingCartItem
.KeyAndPassword
- a model to represent the user's password reset requestEmailTemplate
- a model to represent the email request template forNodemailerNodeMailer
- a model to represent the response from Nodemailer aftersending reset password emailEnvelope
- a model to represent the envelope portion of the response fromNodemailer after sending reset password emailResetPasswordInit
- a model to represent the request for initial passwordreset step
ShoppingCart
andOrder
are marked as belonging to theUser
model by theuse of the@belongsTo
model decorator. Correspondingly, theUser
model ismarked as having manyOrder
s using the@hasMany
model decorator. Althoughpossible, ahasMany
relation forUser
toShoppingCart
has not be createdin this particular app to limit the scope of the example.
User
is also marked as having oneUserCredentials
model using the@hasOne
decorator. ThebelongsTo
relation forUserCredentials
toUser
has not beencreated to keep the scope smaller.
Controllers expose API endpoints for interacting with the models and more.
In this app, there are four controllers:
ping
- a simple controller to checking the status of the app.user-management
- controller for creating user, fetching user info,updating user info, and logging in.shopping-cart
- controller for creating, updating, deleting shopping carts,and getting the details about a shopping cart.user-order
- controller for creating, updating, deleting orders, andgetting the details about an order.product
- controller for managing products catalog
Services are modular components that can be plugged into a LoopBack applicationin various locations to contribute additional capabilities and features to theapplication.
This app has five services:
services/recommender.service
- responsible for connecting to a "remote"server and getting recommendations for a user. The API endpoint atGET /users/{userId}/recommend
, is made possible by this service.services/user-management.service
- responsible for verifying if user existsand the submitted password matches that of the existing user.services/hash.password.bcryptjs
- responsible for generating and comparingpassword hashes.services/validator
- responsible for validating email and password when anew user is created.services/jwt.service
- responsible for generating and verifying JSON WebToken.services/email.service
- responsible for sending reset password email
Note: This app contains alogin
endpoint for the purpose of spike and demo,the authentication for the CRUD operations and navigational endpoints of modelUser is still in progress.
The endpoint for logging in a user is aPOST
request to/users/login
.
Once the credentials are extracted, the logging-in implementation at thecontroller level is just a four step process. This level of simplicity is madepossible by the use of theUserService
service provided by@loopback/authentication
.
const user = await this.userService.verifyCredentials(credentials)
- verifythe credentials.const userProfile = this.userService.convertToUserProfile(user)
- generateuser profile object.const token = await this.jwtService.generateToken(userProfile)
- generateJWT based on the user profile object.return {token}
- send the JWT.
You can see the details inpackages/shopping/src/controllers/user-management.controller.ts
.
Endpoint authorization is done using@loopback/authorization.Use the@authorize
decorator to protect access to controller methods.
All controller methods without the@authorize
decorator will be accessible toeveryone. To restrict access, specify the roles in theallowedRoles
property.Here are two examples to illustrate the point.
Unprotected controller method (no@authorize
decorator), everyone can accessit:
asyncfind( @param.query.object('filter',getFilterSchemaFor(Product))filter?:Filter<Product>,):Promise<Product[]>{ ...}
Protected controller method, onlyadmin
andcustomer
can access it:
@authorize({allowedRoles:['admin','customer'],voters:[basicAuthorization],})asyncset( @inject(SecurityBindings.USER)currentUserProfile:UserProfile, @param.path.string('userId')userId: string, @requestBody({description:'update user'})user:User,):Promise<void>{ ...}
There are three roles in this app:admin
,support
, andcustomer
. You cango through the controller methods inuser-controller.tsandshopping-cart.controller.tsto see which roles are given access to which methods.
The authorization implementation is done via voter functions. In this app, thereis just a single voter function - 'basicAuthorization'. It implements thefollowing rules:
- No access if the user was created without a
roles
property. - No access if the user's role in not in the
allowedRoles
authorizationmetadata. - User can access only model's belonging to themselves.
admin
andsupport
roles bypass model ownership check.
For more details about authorization in LoopBack 4, refer tohttps://loopback.io/doc/en/lb4/Loopback-component-authorization.html.
By default, the JWTs will be signed using HS256 with a 64 character long stringof random hex digits as secret. To use your own secret, set environment variableJWT_SECRET to the value of your own secret. You will want to use your own secretif running multiple instances of the application or want to generate or validatethe JWTs in a different application.
You can see the details inpackages/shopping/src/application.ts
.
This repository includes a forgot password and reset password functionality thatillustrates how shoppers can reset their password in the case they forgot them.Shoppers can either reset their password while logged in or locked out of theapplication. For this functionality we use Nodemailer. Please seehttps://nodemailer.com/usage/using-gmail/ if you're planning to use Nodemailerwith Gmail. Additionally, to manage environment variables we usedotenv
,therefore, you must create a.env
file in the root of the project with thebelow contents:
SMTP_PORT=587SMTP_SERVER=smtp.gmail.comAPPLICATION_URL=http://localhost:3000/ <endpoint-to-the-page-with-reset-password-form>SMTP_USERNAME=<gmail-username-for-account-used-to-send-email>SMTP_PASSWORD=<gmail-password-for-account-used-to-send-email>PASSWORD_RESET_EMAIL_LIMIT=2
There is a tutorial which shows how to apply the JWT strategy to secure yourendpoint with@loopback/authentication@2.x
. You can check more details inhttps://loopback.io/doc/en/lb4/Authentication-tutorial.html
Please check thetry it outsection in the tutorial.
The example application can be packaged as multiple Docker containers anddeployed to a cloud environment as a Kubernetes cluster.
Please check outDeploy Shopping Application as Cloud-native Microservices.
You can findinstructions, Dockerfiles and resourcedefinition files for building and deploying on Red Hat OpenShift ContainerPlatform in the openshift directory.
This project usesDCO. Be sure to sign offyour commits using the-s
flag or addingSigned-off-By: Name<Email>
in thecommit message.
Example
git commit -s -m "feat: my commit message"
Other LoopBack 4 Guidelines apply. See the following resources to get youstarted:
Seeall contributors.
About
LoopBack 4 Example: Online Shopping APIs
Topics
Resources
License
Code of conduct
Security policy
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Uh oh!
There was an error while loading.Please reload this page.