├── CODEOWNERS ├── docker-compose.yml ├── spec └── support │ └── jasmine.json ├── src └── server.ts ├── package.json ├── REQUIREMENTS.md ├── .github └── workflows │ └── manual.yml ├── LICENSE.txt ├── README.md └── tsconfig.json /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @udacity/active-public-content -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.9' 2 | 3 | services: 4 | postgres: 5 | image: postgres 6 | ports: 7 | - '5432:5432' 8 | env_file: 9 | - .env 10 | volumes: 11 | - 'postgres:/var/lib/postgresql/data' 12 | 13 | volumes: 14 | postgres: 15 | -------------------------------------------------------------------------------- /spec/support/jasmine.json: -------------------------------------------------------------------------------- 1 | { 2 | "spec_dir": "spec", 3 | "spec_files": [ 4 | "../**/tests/*[s]pec.ts" 5 | ], 6 | "helpers": [ 7 | "helpers/**/*.js" 8 | ], 9 | "reporters": [ 10 | { 11 | "name": "jasmine-spec-reporter#SpecReporter", 12 | "options": { 13 | "displayStacktrace": "all" 14 | } 15 | } 16 | ], 17 | "stopSpecOnExpectationFailure": false, 18 | "random": true 19 | } 20 | -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | import express, { Request, Response } from 'express' 2 | import bodyParser from 'body-parser' 3 | 4 | const app: express.Application = express() 5 | const address: string = "0.0.0.0:3000" 6 | 7 | app.use(bodyParser.json()) 8 | 9 | app.get('/', function (req: Request, res: Response) { 10 | res.send('Hello World!') 11 | }) 12 | 13 | app.listen(3000, function () { 14 | console.log(`starting app on: ${address}`) 15 | }) 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "storefront_backend", 3 | "version": "0.1.0", 4 | "description": "", 5 | "main": "server.ts", 6 | "scripts": { 7 | "start": "node src/server.ts", 8 | "watch": "tsc-watch --esModuleInterop src/server.ts --outDir ./dist --onSuccess \"node ./dist/server.js\"", 9 | "test": "jasmine-ts", 10 | "tsc": "tsc" 11 | }, 12 | "author": "Udacity", 13 | "license": "ISC", 14 | "dependencies": { 15 | "express": "^4.17.1", 16 | "body-parser": "^1.19.0", 17 | "typescript": "^4.1.3", 18 | "pg": "^8.5.1" 19 | }, 20 | "devDependencies": { 21 | "@types/express": "^4.17.9", 22 | "@types/jasmine": "^3.6.3", 23 | "@types/pg": "^7.14.7", 24 | "jasmine": "^3.6.4", 25 | "jasmine-spec-reporter": "^6.0.0", 26 | "jasmine-ts": "^0.3.0", 27 | "ts-node": "^9.1.1", 28 | "tsc-watch": "^4.2.9" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /REQUIREMENTS.md: -------------------------------------------------------------------------------- 1 | # API Requirements 2 | The company stakeholders want to create an online storefront to showcase their great product ideas. Users need to be able to browse an index of all products, see the specifics of a single product, and add products to an order that they can view in a cart page. You have been tasked with building the API that will support this application, and your coworker is building the frontend. 3 | 4 | These are the notes from a meeting with the frontend developer that describe what endpoints the API needs to supply, as well as data shapes the frontend and backend have agreed meet the requirements of the application. 5 | 6 | ## API Endpoints 7 | #### Products 8 | - Index 9 | - Show 10 | - Create [token required] 11 | - [OPTIONAL] Top 5 most popular products 12 | - [OPTIONAL] Products by category (args: product category) 13 | 14 | #### Users 15 | - Index [token required] 16 | - Show [token required] 17 | - Create N[token required] 18 | 19 | #### Orders 20 | - Current Order by user (args: user id)[token required] 21 | - [OPTIONAL] Completed Orders by user (args: user id)[token required] 22 | 23 | ## Data Shapes 24 | #### Product 25 | - id 26 | - name 27 | - price 28 | - [OPTIONAL] category 29 | 30 | #### User 31 | - id 32 | - firstName 33 | - lastName 34 | - password 35 | 36 | #### Orders 37 | - id 38 | - id of each product in the order 39 | - quantity of each product in the order 40 | - user_id 41 | - status of order (active or complete) 42 | 43 | -------------------------------------------------------------------------------- /.github/workflows/manual.yml: -------------------------------------------------------------------------------- 1 | # Workflow to ensure whenever a Github PR is submitted, 2 | # a JIRA ticket gets created automatically. 3 | name: Manual Workflow 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on pull request events but only for the master branch 8 | pull_request_target: 9 | types: [opened, reopened] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | jobs: 15 | test-transition-issue: 16 | name: Convert Github Issue to Jira Issue 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@master 21 | 22 | - name: Login 23 | uses: atlassian/gajira-login@master 24 | env: 25 | JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} 26 | JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} 27 | JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} 28 | 29 | - name: Create NEW JIRA ticket 30 | id: create 31 | uses: atlassian/gajira-create@master 32 | with: 33 | project: CONUPDATE 34 | issuetype: Task 35 | summary: | 36 | Github PR ND0067 C2 | Repo: ${{ github.repository }} | PR# ${{github.event.number}} 37 | description: | 38 | Repo link: https://github.com/${{ github.repository }} 39 | PR no. ${{ github.event.pull_request.number }} 40 | PR title: ${{ github.event.pull_request.title }} 41 | PR description: ${{ github.event.pull_request.description }} 42 | In addition, please resolve other issues, if any. 43 | fields: '{"components": [{"name":"nd0067 - Full Stack JavaScript Developer"}], "customfield_16449":"https://classroom.udacity.com/", "customfield_16450":"Resolve the PR", "labels": ["github"], "priority":{"id": "4"}}' 44 | 45 | - name: Log created issue 46 | run: echo "Issue ${{ steps.create.outputs.issue }} was created" 47 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2012 - 2020, Udacity, Inc. 2 | 3 | Udacity hereby grants you a license in and to the Educational Content, including 4 | but not limited to homework assignments, programming assignments, code samples, 5 | and other educational materials and tools (as further described in the Udacity 6 | Terms of Use), subject to, as modified herein, the terms and conditions of the 7 | Creative Commons Attribution-NonCommercial- NoDerivs 3.0 License located at 8 | http://creativecommons.org/licenses/by-nc-nd/4.0 and successor locations for 9 | such license (the "CC License") provided that, in each case, the Educational 10 | Content is specifically marked as being subject to the CC License. 11 | 12 | Udacity expressly defines the following as falling outside the definition of 13 | "non-commercial": 14 | (a) the sale or rental of (i) any part of the Educational Content, (ii) any 15 | derivative works based at least in part on the Educational Content, or (iii) 16 | any collective work that includes any part of the Educational Content; 17 | (b) the sale of access or a link to any part of the Educational Content without 18 | first obtaining informed consent from the buyer (that the buyer is aware 19 | that the Educational Content, or such part thereof, is available at the 20 | Website free of charge); 21 | (c) providing training, support, or editorial services that use or reference the 22 | Educational Content in exchange for a fee; 23 | (d) the sale of advertisements, sponsorships, or promotions placed on the 24 | Educational Content, or any part thereof, or the sale of advertisements, 25 | sponsorships, or promotions on any website or blog containing any part of 26 | the Educational Material, including without limitation any "pop-up 27 | advertisements"; 28 | (e) the use of Educational Content by a college, university, school, or other 29 | educational institution for instruction where tuition is charged; and 30 | (f) the use of Educational Content by a for-profit corporation or non-profit 31 | entity for internal professional development or training. 32 | 33 | THE SERVICES AND ONLINE COURSES (INCLUDING ANY CONTENT) ARE PROVIDED "AS IS" AND 34 | "AS AVAILABLE" WITH NO REPRESENTATIONS OR WARRANTIES OF ANY KIND, EITHER 35 | EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 36 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. YOU 37 | ASSUME TOTAL RESPONSIBILITY AND THE ENTIRE RISK FOR YOUR USE OF THE SERVICES, 38 | ONLINE COURSES, AND CONTENT. WITHOUT LIMITING THE FOREGOING, WE DO NOT WARRANT 39 | THAT (A) THE SERVICES, WEBSITES, CONTENT, OR THE ONLINE COURSES WILL MEET YOUR 40 | REQUIREMENTS OR EXPECTATIONS OR ACHIEVE THE INTENDED PURPOSES, (B) THE WEBSITES 41 | OR THE ONLINE COURSES WILL NOT EXPERIENCE OUTAGES OR OTHERWISE BE UNINTERRUPTED, 42 | TIMELY, SECURE OR ERROR-FREE, (C) THE INFORMATION OR CONTENT OBTAINED THROUGH 43 | THE SERVICES, SUCH AS CHAT ROOM SERVICES, WILL BE ACCURATE, COMPLETE, CURRENT, 44 | ERROR- FREE, COMPLETELY SECURE OR RELIABLE, OR (D) THAT DEFECTS IN OR ON THE 45 | SERVICES OR CONTENT WILL BE CORRECTED. YOU ASSUME ALL RISK OF PERSONAL INJURY, 46 | INCLUDING DEATH AND DAMAGE TO PERSONAL PROPERTY, SUSTAINED FROM USE OF SERVICES. 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Storefront Backend Project 2 | 3 | ## Getting Started 4 | 5 | This repo contains a basic Node and Express app to get you started in constructing an API. To get started, clone this repo and run `yarn` in your terminal at the project root. 6 | 7 | ## Required Technologies 8 | Your application must make use of the following libraries: 9 | - Postgres for the database 10 | - Node/Express for the application logic 11 | - dotenv from npm for managing environment variables 12 | - db-migrate from npm for migrations 13 | - jsonwebtoken from npm for working with JWTs 14 | - jasmine from npm for testing 15 | 16 | ## Steps to Completion 17 | 18 | ### 1. Plan to Meet Requirements 19 | 20 | In this repo there is a `REQUIREMENTS.md` document which outlines what this API needs to supply for the frontend, as well as the agreed upon data shapes to be passed between front and backend. This is much like a document you might come across in real life when building or extending an API. 21 | 22 | Your first task is to read the requirements and update the document with the following: 23 | - Determine the RESTful route for each endpoint listed. Add the RESTful route and HTTP verb to the document so that the frontend developer can begin to build their fetch requests. 24 | **Example**: A SHOW route: 'blogs/:id' [GET] 25 | 26 | - Design the Postgres database tables based off the data shape requirements. Add to the requirements document the database tables and columns being sure to mark foreign keys. 27 | **Example**: You can format this however you like but these types of information should be provided 28 | Table: Books (id:varchar, title:varchar, author:varchar, published_year:varchar, publisher_id:string[foreign key to publishers table], pages:number) 29 | 30 | **NOTE** It is important to remember that there might not be a one to one ratio between data shapes and database tables. Data shapes only outline the structure of objects being passed between frontend and API, the database may need multiple tables to store a single shape. 31 | 32 | ### 2. DB Creation and Migrations 33 | 34 | Now that you have the structure of the databse outlined, it is time to create the database and migrations. Add the npm packages dotenv and db-migrate that we used in the course and setup your Postgres database. If you get stuck, you can always revisit the database lesson for a reminder. 35 | 36 | You must also ensure that any sensitive information is hashed with bcrypt. If any passwords are found in plain text in your application it will not pass. 37 | 38 | ### 3. Models 39 | 40 | Create the models for each database table. The methods in each model should map to the endpoints in `REQUIREMENTS.md`. Remember that these models should all have test suites and mocks. 41 | 42 | ### 4. Express Handlers 43 | 44 | Set up the Express handlers to route incoming requests to the correct model method. Make sure that the endpoints you create match up with the enpoints listed in `REQUIREMENTS.md`. Endpoints must have tests and be CORS enabled. 45 | 46 | ### 5. JWTs 47 | 48 | Add JWT functionality as shown in the course. Make sure that JWTs are required for the routes listed in `REQUIUREMENTS.md`. 49 | 50 | ### 6. QA and `README.md` 51 | 52 | Before submitting, make sure that your project is complete with a `README.md`. Your `README.md` must include instructions for setting up and running your project including how you setup, run, and connect to your database. 53 | 54 | Before submitting your project, spin it up and test each endpoint. If each one responds with data that matches the data shapes from the `REQUIREMENTS.md`, it is ready for submission! 55 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "ES2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | "lib": ["es2015", "dom"], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | // "outDir": "./", /* Redirect output structure to the directory. */ 18 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 43 | 44 | /* Module Resolution Options */ 45 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 46 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 47 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 48 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 49 | // "typeRoots": [], /* List of folders to include type definitions from. */ 50 | // "types": [], /* Type declaration files to be included in compilation. */ 51 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 52 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 53 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 54 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 55 | 56 | /* Source Map Options */ 57 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 58 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 59 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 60 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 61 | 62 | /* Experimental Options */ 63 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 64 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 65 | 66 | /* Advanced Options */ 67 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 68 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 69 | } 70 | } 71 | --------------------------------------------------------------------------------