Final Project
GIFTR
Due before 5:00 pm on Friday April 17, 2019.
This is the final deadline. There will be no extensions.
Counts for 30% of your MAD9124 final grade.
Joint Project
The final project will be a two part joint assignment between MAD9124 and MAD9022. You will build a complete full-stack solution. The web service API portion will be graded for MAD9124, and the front-end application functionality, design, and usability will be graded for MAD9022.
Review the MAD9022 - Web Client project details.
The Brief
Using Node.js, Express, Mongoose and MongoDB, you will build the RESTful API web service for a prototype of a fictitious application to track gift ideas for your friends. This initial proof of concept (PoC) will have limited capabilities but should demonstrate the potential of a full-scale application.
Each registered user can create a list of people for whom they are collecting gift ideas. The user can then add one or more gift ideas for each person on their list.
The person and their gift ideas can be shared with one or more other registered users. Those users can view and update the gift ideas, but cannot delete the user. Only the owner can delete a Person from their list.
Your PoC will allow authenticated users to perform basic CRUD operations on two primary resources: people and gifts. The Person
model represent the people for whom you are collecting gift ideas and will have an array of embedded Gift
models. It will also have a belongsTo relationship to the owning User
model.
The API will also allow for Person objects to be "shared" with other User(s). This sharing feature may or may not be implemented on the client side.
The PoC will also need to support user registration, authentication and password updates. Since this is at the proof of concept stage, the App will be free, so the registration process does not need to consider credit cards for payments.
Core Requirements
Implement basic user user management functions
- registration
- authentication with JWT
- change password
- get current logged-in user
Protected API routes require a valid JWT in the
Authorization
header.Middleware functions should be employed to avoid repetitive route handler code.
Single resource requests should return any related resources as fully populated embedded documents.
Resource list requests should return an array of the primary resource objects only, without populating any related objects.
All requests containing user/client supplied data should be sanitized to protect against XSS and Query Injection attacks.
All schema validation errors should be caught and returned to the client in the standard JSON:API error format.
Response Payload
- All responses will be in the form of a JSON formatted object.
- This payload object must include one of (but not both at the same time) a
data
property or anerrors
property. - For "list" routes, the
data
property must be populated an array of zero or more of the requested resource objects. - For "retrieve" routes, the
data
property must be populated with a single resource object. - If the requested single resource, or sub-resource (embedded document) does not exist, a 404 error response should be sent.
- Error responses will conform to the JSON:API standard.
Example Data Response
GET /auth/users/me
{
"data": {
"firstName": "Yo-Yo",
"lastName": "Ma",
"email": "me@yoyoma.com"
}
}
Example Errors Response
POST /auth/users
{
"errors": [
{
"status": "Bad Request",
"code": "400",
"title": "Validation Error",
"detail": "minnie.mouse@disney is not a valid email address.",
"source": {"pointer": "/data/attributes/email"}
}
]
}
Auth Routes
The user management actions will be exposed separately from the main API routes and will use the /auth
route prefix.
Action | Method | Resource Path | Example Request Payload |
---|---|---|---|
Register User | POST | /auth/users | { "firstName": "Yo-Yo", "lastName": "Ma", "email": "me@yo-yoma.com", "password": "myPassword" } |
Get Logged-in User | GET | /auth/users/me | |
Update Password | PATCH | /auth/users/me | { "password": "newPassword" } |
Login User | POST | /auth/tokens | { "email": "me@yo-yoma.com", "password": "myPassword" } |
API Routes
The primary application capabilities will be grouped under the /api
resource route prefix. Some routes will be unrestricted, while others will be limited to authorized users. Access to routes relating to creating, updating or deleting gift ideas for a particular Person object will be limited to authenticated users who are either the owner
or in the sharedWith
list for that Person. Deleting a Person object will be restricted exclusively to its owner
.
The client application must send a valid JWT in the Authorization
header property for all /api
routes.
Person Routes
Action | Method | Resource Path | Notes |
---|---|---|---|
List all people | GET | /api/people | Gift ideas not populated |
Get details for a person | GET | /api/people/:id | Gift ideas fully populated |
Create a person | POST | /api/people | |
Replace a person | PUT | /api/people/:id | |
Update a person | PATCH | /api/people/:id | |
Remove a person | DELETE | /api/people/:id | Only the owner |
Users should only see and be able to act on their own people.
All gift ideas for a given person should be returned as an array of embedded documents with the requested Person object.
Gift Routes
Action | Method | Resource Path | Notes |
---|---|---|---|
Create a gift | POST | /api/people/:id/gifts | |
Update a gift | PATCH | /api/people/:id/gifts/:giftId | |
Remove a gift | DELETE | /api/people/:id/gifts/:giftId |
Users should only see and be able to act on gifts associated to their people.
Resource Schema
There are three required model classes. Their schema requirements are listed below.
Remember
Mongoose will automatically create the _id
property for all objects.
Person
Property | Type | Required | Max (length/value) | Default |
---|---|---|---|---|
name | String | true | 254 | |
birthDate | Date | true | ||
owner | ObjectId, ref: 'User' | true | Current user | |
sharedWith | [ ObjectId, ref: 'User' ] | |||
gifts | [ Gift ] | |||
imageUrl | String | 1024 | ||
createdAt | Date | Date.now() | ||
updatedAt | Date | Date.now() |
The createdAt
and updatedAt
properties should be set automatically by the database. Any client supplied data for these two properties should be discarded.
The gifts
property takes an array of zero or more Gift sub-documents.
The sharedWith
property takes an array of zero or more User IDs.
The owner
property takes a single User ID.
Gift
Property | Type | Required | Min | Max | Default |
---|---|---|---|---|---|
name | String | true | 4 | 64 | |
price | Number (integer in cents) | 100 | 1000 | ||
imageUrl | String | 1024 | |||
store | Object | ||||
store.name | String | 254 | |||
store.productURL | String | 1024 |
User
Property | Type | Required | Max Length | Default | Unique |
---|---|---|---|---|---|
firstName | String | true | 64 | ||
lastName | String | true | 64 | ||
String | true | 512 | true | ||
password | String | true | 70 |
The email
property must be a correctly formatted email, and must be unique in the database. This check should be done with a custom schema validator function.
The password
property must be encrypted using the bcrypt
library. This should be done in a schema.pre('save')
method. The password
property should always be redacted from response data and never returned to the client.
Logistics
- Accept this GitHub Classroom assignment invitation.
- Clone the repo to your laptop.
- Update the
package.json
file. - Install dependencies with NPM.
- Build the project on your laptop.
- Test each route with Postman, making sure to test both valid and invalid data.
- Make git commits as you complete each requirement.
- When everything is complete, push the final commit back up to GitHub
- Submit both two URLs on Brightspace: the GitHub repo URL and the URL to your deployed AWS API.
Remember
Pay attention to clean code practices.