{"id":19165711,"url":"https://github.com/loopbackio/loopback4-example-shopping","last_synced_at":"2025-05-15T13:07:41.666Z","repository":{"id":38039249,"uuid":"143919985","full_name":"loopbackio/loopback4-example-shopping","owner":"loopbackio","description":"LoopBack 4 Example: Online Shopping APIs","archived":false,"fork":false,"pushed_at":"2025-05-08T05:42:45.000Z","size":32201,"stargazers_count":367,"open_issues_count":22,"forks_count":206,"subscribers_count":32,"default_branch":"master","last_synced_at":"2025-05-08T06:29:05.455Z","etag":null,"topics":["hacktoberfest","loopback4","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/loopbackio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-08-07T19:49:38.000Z","updated_at":"2025-04-14T15:55:53.000Z","dependencies_parsed_at":"2024-02-26T22:52:53.416Z","dependency_job_id":"5c580ee2-734c-4305-a1e8-0249cc7538b7","html_url":"https://github.com/loopbackio/loopback4-example-shopping","commit_stats":{"total_commits":1485,"total_committers":21,"mean_commits":70.71428571428571,"dds":"0.14141414141414144","last_synced_commit":"af15cf5e6a5d309c61da2ee9e522533ee9def980"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loopbackio%2Floopback4-example-shopping","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loopbackio%2Floopback4-example-shopping/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loopbackio%2Floopback4-example-shopping/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loopbackio%2Floopback4-example-shopping/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/loopbackio","download_url":"https://codeload.github.com/loopbackio/loopback4-example-shopping/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254346624,"owners_count":22055808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest","loopback4","typescript"],"created_at":"2024-11-09T09:29:05.228Z","updated_at":"2025-05-15T13:07:36.658Z","avatar_url":"https://github.com/loopbackio.png","language":"TypeScript","readme":"# @loopback/example-shopping\n\n![Continuous Integration Status](https://github.com/loopbackio/loopback4-example-shopping/workflows/Continous%20Integration/badge.svg)\n\nThis project aims to represent an online ecommerce platform APIs to validate /\ntest the LoopBack 4 framework readiness for GA. See\nhttps://github.com/strongloop/loopback-next/issues/1476 for more information.\n\n![Shopping example overview diagram](example-shopping.png)\n\n## Pre-requisites\n\nNode.js \u003e= 8.9.0 and running instances of a MongoDB and Redis server are\nrequired for the app to start. The Redis server is used for the shopping cart,\nwhile MongoDB is used for the rest of the models in the app.\n\nDocker is required for running tests, make sure it is running if you want to run\nthe tests.\n\n## Installation\n\nDo the following to clone and start the project.\n\nIn case you have Docker installed on your system and don't want to manually\ninstall MongoDB and Redis, you can run `npm run docker:start` to download their\nimages and start the servers. Otherwise, you can skip this command.\n\n```sh\n$ git clone https://github.com/loopbackio/loopback4-example-shopping.git\n$ cd loopback4-example-shopping\n$ npm i\n$ npm run docker:start\n$ npm start\n```\n\n## Usage\n\nThe main app will be running at http://localhost:3000. The shopping website\n(Shoppy) is at http://localhost:3000/shoppy.html, and the API Explorer at\nhttp://localhost:3000/explorer/.\n\n![Shoppy website](shoppy.png)\n\nYou will also see `Recommendation server is running at http://localhost:3001.`,\nit is the server to which the `services/recommender.service` service will\nconnect to get the recommendations for a user.\n\nThe app will be pre-populated with some products and users when it starts; and\nall existing products, users, shopping cart and orders will be deleted too. If\nyou don't want to reset the database, set `databaseSeeding` to `false` in the\napplication configuration object.\n\n### Tests\n\nThis repository comes with integration, unit, acceptance and end-to-end (e2e)\ntests. To execute these, see instructions below.\n\n`Note`: prior to running the e2e tests the application must be running. On a\ndifferent terminal do:\n\n```sh\n$ npm start\n```\n\nthen on another terminal do the following to execute e2e tests:\n\n```sh\n$ npm run test:ui\n```\n\nFor other tests:\n\n```sh\n$ npm test\n```\n\n## Models\n\nThis app has the following models:\n\n1. `User` - representing the users of the system.\n2. `UserCredentials` - representing sensitive credentials like a password.\n3. `Product` - a model which is mapped to a remote service by\n   `services/recommender.service`.\n4. `ShoppingCartItem` - a model for representing purchases.\n5. `ShoppingCart` - a model to represent a user's shopping cart, can contain\n   many items (`items`) of the type `ShoppingCartItem`.\n6. `Order` - a model to represent an order by user, can have many products\n   (`products`) of the type `ShoppingCartItem`.\n7. `KeyAndPassword` - a model to represent the user's password reset request\n8. `EmailTemplate` - a model to represent the email request template for\n   Nodemailer\n9. `NodeMailer` - a model to represent the response from Nodemailer after\n   sending reset password email\n10. `Envelope` - a model to represent the envelope portion of the response from\n    Nodemailer after sending reset password email\n11. `ResetPasswordInit` - a model to represent the request for initial password\n    reset step\n\n`ShoppingCart` and `Order` are marked as belonging to the `User` model by the\nuse of the `@belongsTo` model decorator. Correspondingly, the `User` model is\nmarked as having many `Order`s using the `@hasMany` model decorator. Although\npossible, a `hasMany` relation for `User` to `ShoppingCart` has not be created\nin this particular app to limit the scope of the example.\n\n`User` is also marked as having one `UserCredentials` model using the `@hasOne`\ndecorator. The `belongsTo` relation for `UserCredentials` to `User` has not been\ncreated to keep the scope smaller.\n\n## Controllers\n\nControllers expose API endpoints for interacting with the models and more.\n\nIn this app, there are four controllers:\n\n1. `ping` - a simple controller to checking the status of the app.\n2. `user-management` - controller for creating user, fetching user info,\n   updating user info, and logging in.\n3. `shopping-cart` - controller for creating, updating, deleting shopping carts,\n   and getting the details about a shopping cart.\n4. `user-order` - controller for creating, updating, deleting orders, and\n   getting the details about an order.\n5. `product` - controller for managing products catalog\n\n## Services\n\nServices are modular components that can be plugged into a LoopBack application\nin various locations to contribute additional capabilities and features to the\napplication.\n\nThis app has five services:\n\n1. `services/recommender.service` - responsible for connecting to a \"remote\"\n   server and getting recommendations for a user. The API endpoint at\n   `GET /users​/{userId}​/recommend`, is made possible by this service.\n2. `services/user-management.service` - responsible for verifying if user exists\n   and the submitted password matches that of the existing user.\n3. `services/hash.password.bcryptjs` - responsible for generating and comparing\n   password hashes.\n4. `services/validator` - responsible for validating email and password when a\n   new user is created.\n5. `services/jwt.service` - responsible for generating and verifying JSON Web\n   Token.\n6. `services/email.service` - responsible for sending reset password email\n\n## Authentication\n\n_Note: This app contains a `login` endpoint for the purpose of spike and demo,\nthe authentication for the CRUD operations and navigational endpoints of model\nUser is still in progress._\n\n### Login\n\nThe endpoint for logging in a user is a `POST` request to `/users/login`.\n\nOnce the credentials are extracted, the logging-in implementation at the\ncontroller level is just a four step process. This level of simplicity is made\npossible by the use of the `UserService` service provided by\n`@loopback/authentication`.\n\n1. `const user = await this.userService.verifyCredentials(credentials)` - verify\n   the credentials.\n2. `const userProfile = this.userService.convertToUserProfile(user)` - generate\n   user profile object.\n3. `const token = await this.jwtService.generateToken(userProfile)` - generate\n   JWT based on the user profile object.\n4. `return {token}` - send the JWT.\n\nYou can see the details in\n[`packages/shopping/src/controllers/user-management.controller.ts`](https://github.com/loopbackio/loopback4-example-shopping/blob/master/packages/shopping/src/controllers/user-management.controller.ts).\n\n### Authorization\n\nEndpoint authorization is done using\n[@loopback/authorization](https://github.com/strongloop/loopback-next/tree/master/packages/authorization).\nUse the `@authorize` decorator to protect access to controller methods.\n\nAll controller methods without the `@authorize` decorator will be accessible to\neveryone. To restrict access, specify the roles in the `allowedRoles` property.\nHere are two examples to illustrate the point.\n\nUnprotected controller method (no `@authorize` decorator), everyone can access\nit:\n\n```ts\nasync find(\n  @param.query.object('filter', getFilterSchemaFor(Product))\n  filter?: Filter\u003cProduct\u003e,\n): Promise\u003cProduct[]\u003e {\n  ...\n}\n```\n\nProtected controller method, only `admin` and `customer` can access it:\n\n```ts\n@authorize({\n  allowedRoles: ['admin', 'customer'],\n  voters: [basicAuthorization],\n})\nasync set(\n  @inject(SecurityBindings.USER)\n  currentUserProfile: UserProfile,\n  @param.path.string('userId') userId: string,\n  @requestBody({description: 'update user'}) user: User,\n): Promise\u003cvoid\u003e {\n  ...\n}\n```\n\nThere are three roles in this app: `admin`, `support`, and `customer`. You can\ngo through the controller methods in\n[user-controller.ts](/packages/shopping/src/controllers/user-management.controller.ts)\nand\n[shopping-cart.controller.ts](/master/packages/shopping/src/controllers/shopping-cart.controller.ts)\nto see which roles are given access to which methods.\n\nThe authorization implementation is done via voter functions. In this app, there\nis just a single voter function - 'basicAuthorization'. It implements the\nfollowing rules:\n\n1. No access if the user was created without a `roles` property.\n2. No access if the user's role in not in the `allowedRoles` authorization\n   metadata.\n3. User can access only model's belonging to themselves.\n4. `admin` and `support` roles bypass model ownership check.\n\nFor more details about authorization in LoopBack 4, refer to\nhttps://loopback.io/doc/en/lb4/Loopback-component-authorization.html.\n\n### JWT secret\n\nBy default, the JWTs will be signed using HS256 with a 64 character long string\nof random hex digits as secret. To use your own secret, set environment variable\nJWT_SECRET to the value of your own secret. You will want to use your own secret\nif running multiple instances of the application or want to generate or validate\nthe JWTs in a different application.\n\nYou can see the details in\n[`packages/shopping/src/application.ts`](./packages/shopping/src/application.ts).\n\n### Reset Password\n\nThis repository includes a forgot password and reset password functionality that\nillustrates how shoppers can reset their password in the case they forgot them.\nShoppers can either reset their password while logged in or locked out of the\napplication. For this functionality we use Nodemailer. Please see\nhttps://nodemailer.com/usage/using-gmail/ if you're planning to use Nodemailer\nwith Gmail. Additionally, to manage environment variables we use `dotenv`,\ntherefore, you must create a `.env` file in the root of the project with the\nbelow contents:\n\n```dotenv\nSMTP_PORT=587\nSMTP_SERVER=smtp.gmail.com\nAPPLICATION_URL=http://localhost:3000/ \u003cendpoint-to-the-page-with-reset-password-form\u003e\nSMTP_USERNAME=\u003cgmail-username-for-account-used-to-send-email\u003e\nSMTP_PASSWORD=\u003cgmail-password-for-account-used-to-send-email\u003e\nPASSWORD_RESET_EMAIL_LIMIT=2\n```\n\n### Tutorial\n\nThere is a tutorial which shows how to apply the JWT strategy to secure your\nendpoint with `@loopback/authentication@2.x`. You can check more details in\nhttps://loopback.io/doc/en/lb4/Authentication-tutorial.html\n\n### Trying It Out\n\nPlease check the\n[try it out](https://loopback.io/doc/en/lb4/Authentication-tutorial.html#try-it-out)\nsection in the tutorial.\n\n## Deploy to Cloud as Microservices\n\nThe example application can be packaged as multiple Docker containers and\ndeployed to a cloud environment as a Kubernetes cluster.\n\nPlease check out\n[Deploy Shopping Application as Cloud-native Microservices](kubernetes/README.md).\n\n## Build and deploy on Red Hat OpenShift\n\nYou can find [instructions](openshift/README.md), Dockerfiles and resource\ndefinition files for building and deploying on Red Hat OpenShift Container\nPlatform in the openshift directory.\n\n## Contributing\n\nThis project uses [DCO](https://developercertificate.org/). Be sure to sign off\nyour commits using the `-s` flag or adding `Signed-off-By: Name\u003cEmail\u003e` in the\ncommit message.\n\n**Example**\n\n```\ngit commit -s -m \"feat: my commit message\"\n```\n\nOther LoopBack 4 Guidelines apply. See the following resources to get you\nstarted:\n\n- [Contributing Guidelines](https://github.com/strongloop/loopback-next/blob/master/docs/CONTRIBUTING.md)\n- [Developing LoopBack](./DEVELOPING.md)\n\n## Team\n\nSee\n[all contributors](https://github.com/loopbackioo/loopback4-example-shopping/graphs/contributors).\n\n## License\n\n[MIT](LICENSE)\n\n[![LoopBack](\u003chttps://github.com/strongloop/loopback-next/raw/master/docs/site/imgs/branding/Powered-by-LoopBack-Badge-(blue)-@2x.png\u003e)](http://loopback.io/)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floopbackio%2Floopback4-example-shopping","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Floopbackio%2Floopback4-example-shopping","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floopbackio%2Floopback4-example-shopping/lists"}