• Stars
    star
    357
  • Rank 114,807 (Top 3 %)
  • Language
    TypeScript
  • License
    Other
  • Created over 5 years ago
  • Updated 11 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

LoopBack 4 Example: Online Shopping APIs

@loopback/example-shopping

Continuous Integration Status

This project aims to represent an online ecommerce platform APIs to validate / test the LoopBack 4 framework readiness for GA. See loopbackio/loopback-next#1476 for more information.

Shopping example overview diagram

Pre-requisites

Node.js >= 8.9.0 and running instances of a MongoDB and Redis server are required 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 run the tests.

Installation

Do the following to clone and start the project.

In case you have Docker installed on your system and don't want to manually install MongoDB and Redis, you can run npm run docker:start to download their images 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

Usage

The main app will be running at http://localhost:3000. The shopping website (Shoppy) is at http://localhost:3000/shoppy.html, and the API Explorer at http://localhost:3000/explorer/.

Shoppy website

You will also see Recommendation server is running at http://localhost:3001., it is the server to which the services/recommender.service service will connect to get the recommendations for a user.

The app will be pre-populated with some products and users when it starts; and all existing products, users, shopping cart and orders will be deleted too. If you don't want to reset the database, set databaseSeeding to false in the application configuration object.

Tests

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 a different terminal do:

$ npm start

then on another terminal do the following to execute e2e tests:

$ npm run test:ui

For other tests:

$ npm test

Models

This app has the following models:

  1. User - representing the users of the system.
  2. UserCredentials - representing sensitive credentials like a password.
  3. Product - a model which is mapped to a remote service by services/recommender.service.
  4. ShoppingCartItem - a model for representing purchases.
  5. ShoppingCart - a model to represent a user's shopping cart, can contain many items (items) of the type ShoppingCartItem.
  6. Order - a model to represent an order by user, can have many products (products) of the type ShoppingCartItem.
  7. KeyAndPassword - a model to represent the user's password reset request
  8. EmailTemplate - a model to represent the email request template for Nodemailer
  9. NodeMailer - a model to represent the response from Nodemailer after sending reset password email
  10. Envelope - a model to represent the envelope portion of the response from Nodemailer after sending reset password email
  11. ResetPasswordInit - a model to represent the request for initial password reset step

ShoppingCart and Order are marked as belonging to the User model by the use of the @belongsTo model decorator. Correspondingly, the User model is marked as having many Orders using the @hasMany model decorator. Although possible, a hasMany relation for User to ShoppingCart has not be created in this particular app to limit the scope of the example.

User is also marked as having one UserCredentials model using the @hasOne decorator. The belongsTo relation for UserCredentials to User has not been created to keep the scope smaller.

Controllers

Controllers expose API endpoints for interacting with the models and more.

In this app, there are four controllers:

  1. ping - a simple controller to checking the status of the app.
  2. user-management - controller for creating user, fetching user info, updating user info, and logging in.
  3. shopping-cart - controller for creating, updating, deleting shopping carts, and getting the details about a shopping cart.
  4. user-order - controller for creating, updating, deleting orders, and getting the details about an order.
  5. product - controller for managing products catalog

Services

Services are modular components that can be plugged into a LoopBack application in various locations to contribute additional capabilities and features to the application.

This app has five services:

  1. services/recommender.service - responsible for connecting to a "remote" server and getting recommendations for a user. The API endpoint at GET /usersโ€‹/{userId}โ€‹/recommend, is made possible by this service.
  2. services/user-management.service - responsible for verifying if user exists and the submitted password matches that of the existing user.
  3. services/hash.password.bcryptjs - responsible for generating and comparing password hashes.
  4. services/validator - responsible for validating email and password when a new user is created.
  5. services/jwt.service - responsible for generating and verifying JSON Web Token.
  6. services/email.service - responsible for sending reset password email

Authentication

Note: This app contains a login endpoint for the purpose of spike and demo, the authentication for the CRUD operations and navigational endpoints of model User is still in progress.

Login

The endpoint for logging in a user is a POST request to /users/login.

Once the credentials are extracted, the logging-in implementation at the controller level is just a four step process. This level of simplicity is made possible by the use of the UserService service provided by @loopback/authentication.

  1. const user = await this.userService.verifyCredentials(credentials) - verify the credentials.
  2. const userProfile = this.userService.convertToUserProfile(user) - generate user profile object.
  3. const token = await this.jwtService.generateToken(userProfile) - generate JWT based on the user profile object.
  4. return {token} - send the JWT.

You can see the details in packages/shopping/src/controllers/user-management.controller.ts.

Authorization

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 to everyone. To restrict access, specify the roles in the allowedRoles property. Here are two examples to illustrate the point.

Unprotected controller method (no @authorize decorator), everyone can access it:

async find(
  @param.query.object('filter', getFilterSchemaFor(Product))
  filter?: Filter<Product>,
): Promise<Product[]> {
  ...
}

Protected controller method, only admin and customer can access it:

@authorize({
  allowedRoles: ['admin', 'customer'],
  voters: [basicAuthorization],
})
async set(
  @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, and customer. You can go through the controller methods in user-controller.ts and shopping-cart.controller.ts to see which roles are given access to which methods.

The authorization implementation is done via voter functions. In this app, there is just a single voter function - 'basicAuthorization'. It implements the following rules:

  1. No access if the user was created without a roles property.
  2. No access if the user's role in not in the allowedRoles authorization metadata.
  3. User can access only model's belonging to themselves.
  4. admin and support roles bypass model ownership check.

For more details about authorization in LoopBack 4, refer to https://loopback.io/doc/en/lb4/Loopback-component-authorization.html.

JWT secret

By default, the JWTs will be signed using HS256 with a 64 character long string of random hex digits as secret. To use your own secret, set environment variable JWT_SECRET to the value of your own secret. You will want to use your own secret if running multiple instances of the application or want to generate or validate the JWTs in a different application.

You can see the details in packages/shopping/src/application.ts.

Reset Password

This repository includes a forgot password and reset password functionality that illustrates 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 the application. For this functionality we use Nodemailer. Please see https://nodemailer.com/usage/using-gmail/ if you're planning to use Nodemailer with Gmail. Additionally, to manage environment variables we use dotenv, therefore, you must create a .env file in the root of the project with the below contents:

SMTP_PORT=587
SMTP_SERVER=smtp.gmail.com
APPLICATION_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

Tutorial

There is a tutorial which shows how to apply the JWT strategy to secure your endpoint with @loopback/[email protected]. You can check more details in https://loopback.io/doc/en/lb4/Authentication-tutorial.html

Trying It Out

Please check the try it out section in the tutorial.

Deploy to Cloud as Microservices

The example application can be packaged as multiple Docker containers and deployed to a cloud environment as a Kubernetes cluster.

Please check out Deploy Shopping Application as Cloud-native Microservices.

Build and deploy on Red Hat OpenShift

You can find instructions, Dockerfiles and resource definition files for building and deploying on Red Hat OpenShift Container Platform in the openshift directory.

Contributing

This project uses DCO. Be sure to sign off your commits using the -s flag or adding Signed-off-By: Name<Email> in the commit message.

Example

git commit -s -m "feat: my commit message"

Other LoopBack 4 Guidelines apply. See the following resources to get you started:

Team

See all contributors.

License

MIT

LoopBack

More Repositories

1

loopback-next

LoopBack makes it easy to build modern API applications that require complex integrations.
TypeScript
4,550
star
2

loopback-datasource-juggler

Connect Loopback to various Data Sources
JavaScript
278
star
3

loopback.io

LoopBack project site - now with documentation!
HTML
253
star
4

loopback-connector-mongodb

The official MongoDB connector for the LoopBack framework.
JavaScript
188
star
5

loopback-connector-mysql

Loopback Connector for MySQL
JavaScript
125
star
6

loopback-connector-postgresql

PostgreSQL connector for LoopBack.
JavaScript
117
star
7

loopback-connector-soap

LoopBack's SOAP based Web Services Connector
JavaScript
81
star
8

loopback-connector-rest

Connect Loopback to a REST API
JavaScript
75
star
9

loopback-connector-mssql

LoopBack connector for Microsoft SQL Server
JavaScript
52
star
10

strong-error-handler

Error handler for use in development (debug) and production environments.
JavaScript
39
star
11

loopback-connector

Building blocks for LoopBack connectors
JavaScript
34
star
12

loopback-connector-oracle

Connect Loopback to Oracle
JavaScript
28
star
13

loopback-connector-kv-redis

The official Redis KeyValue connector for LoopBack.
JavaScript
19
star
14

loopback-connector-cloudant

LoopBack Connector for IBM Cloudant
JavaScript
19
star
15

loopback4-extension-grpc

gRPC Extension for LoopBack 4
TypeScript
17
star
16

loopback-connector-db2

LoopBack Connector for IBM DB/2
JavaScript
17
star
17

loopback-connector-grpc

LoopBack connector for gRPC (experimental)
JavaScript
16
star
18

loopback-connector-sqlite3

SQLite3 Connector for LoopBack
JavaScript
13
star
19

loopback-connector-cassandra

Cassandra connector for the LoopBack framework.
JavaScript
13
star
20

loopback-connector-couchdb2

LoopBack Connector for Couchdb
JavaScript
12
star
21

loopback4-example-kafka

A LoopBack 4 example application for Kafka integration
TypeScript
10
star
22

loopback-connector-openapi

LoopBack connector for OpenAPI spec (2.0 and 3.0.x) compliant services
JavaScript
7
star
23

security

[WORK IN PROGRESS] A centralised repository for all security-related matters on the LoopBack Project.
TypeScript
4
star
24

loopback-ibmdb

Common set of functions for all IBM connectors that are based on the ibm_db module
JavaScript
4
star
25

loopback-connector-ibmi

JavaScript
2
star
26

loopback-connector-dashdb

Loopback connector for dashDB
JavaScript
2
star
27

explorer.loopback.io

Hosted API Explorer
HTML
2
star