Udacity Full-Stack Web Developer Nanodegree Program Capstone Project
the app is deployed here
create a .env file and save the following variables
AUTH0_DOMAIN={your_domain_name}.auth0.com
API_AUDIENCE={your_api_audience}
DATABASE_URL=postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...] #example: postgresql://postgres@localhost:5432/invitdb
With Postgres running, create a database and optionally populate it with database.psql
file provided by running:
createdb dbname
psql dbname < database.psql
use auth0 app URI format to get the JWT example
https://{{YOUR_DOMAIN}}/authorize?audience={{API_IDENTIFIER}}&response_type=token&client_id={{YOUR_CLIENT_ID}}&redirect_uri={{YOUR_CALLBACK_URI}}
-
Initialize and activate a virtual environment using python virtualenv:
python3 -m venv venv source venv/bin/activate
-
Install dependencies:
pip install -r requirements.txt
-
Run the server locally:
export FLASK_APP=flaskr export FLASK_DEBUG=True export FLASK_ENVIRONMENT=debug flask run --reload
There are two database models to this app:
-
Invitation: Represents an Event invitation.
- id (primary key): Unique identifier for the invitation.
- name: Name of the host.
- email: Email address of the host.
- description: has the invitation text.
-
RSVP: Represents an RSVP response to an invitation.
- id (primary key): Unique identifier for the RSVP.
- invitation_id: Foreign key referencing the Invitation model.
- response: String representing the guest's response to the invitation (e.g. "Attending", "Not Attending", "Undecided").
- guest_name: Name of the guest who is responding to the invitation.
- guest_email: Email address of the guest who is responding to the invitation.
- plus_one: Boolean indicating whether the guest is bringing a plus one.
The following permissions are created under API settings.
post:invitation
patch:invitation
delete:invitation
get:invitation-rsvps
get:invitation-rsvp-details
post:invitation-rsvp
patch:invitation-rsvp
delete:invitation-rsvp
Two roles are created for users under Users & Roles
section in Auth0
- Admin:
- represents a person that manages the invitations in the database
- Admin have the following permissions:
post:invitation
patch:invitation
delete:invitation
get:invitation-rsvps
get:invitation-rsvp-details
- Guest:
- represents a person that can respond to an invitation
- Guest have the following permissions:
get:invitation-rsvp-details
post:invitation-rsvp
patch:invitation-rsvp
delete:invitation-rsvp
GET /invitations
- Retrieves a list of all invitations.
GET /invitations/{id}
- Retrieves a single invitation by ID.
POST /invitations
- Creates a new invitation.
PATCH /invitations/{id}
- Updates an existing invitation by ID.
DELETE /invitations/{id}
- Deletes an existing invitation by ID.
GET /invitations/{invitation_id}/rsvps
- Retrieves a list of all RSVPs for a specific invitation.
GET /invitations/{invitation_id}/rsvps/{id}
- Retrieves a single RSVP by ID.
POST /invitations/{invitation_id}/rsvps
- Creates a new RSVP.
PATCH /invitations/{invitation_id}/rsvps/{id}
- Updates an existing RSVP by ID.
DELETE /invitations/{invitation_id}/rsvps/{id}
- Deletes an existing RSVP by ID.
http://localhost:5000
The application will return the following error types when requests fail:
- 400: Bad Request
- 401: Unauthorized
- 404: Resource Not Found
- 422: Not Processable
Errors are returned as JSON objects in the following format:
{
"success": false,
"error": 400,
"message": "bad request"
}
GET /invitations
- Returns a list of all invitations.
- Sample Request:
curl -X GET \
http://localhost:5000/invitations \
-H 'Content-Type: application/json'
- Sample response
{
"success": true,
"invitations": [
{
"id": 1,
"name": "John Smith",
"email": "[email protected]",
"description": "Please join us to celebrate our wedding."
},
{
"id": 2,
"name": "Jane Doe",
"email": "[email protected]",
"description": "Please join us to celebrate our baby shower."
}
]
}
GET /invitations/int:id
- Returns an invitation by id.
- Sample Request:
curl -X GET \
http://localhost:5000/invitations/1 \
-H 'Content-Type: application/json'
- Sample response
{
"success": true,
"invitations": {
"id": 1,
"name": "John Smith",
"email": "[email protected]",
"description": "Please join us to celebrate our wedding."
}
}
POST /invitations
- Create a new invitation.
- Sample Request:
curl -X POST\
http://localhost:5000/invitations \
-H 'Authorization: Bearer {$TOKEN}' \
-H 'Content-Type: application/json' \
-d '{"name":"John Smith",
"email":"[email protected]",
"description":"Please join us to celebrate our wedding."}'
- Sample response
{
"success": true,
"invitations": {
"id": 3,
"name": "John Smith",
"email": "[email protected]",
"description": "Please join us to celebrate our wedding."
}
}
PATCH /invitations/int:id
- Update an invitation by id.
- Sample Request:
curl -X PATCH \
http://localhost:5000/invitations/1 \
-H 'Authorization: Bearer {$TOKEN}' \
-H 'Content-Type: application/json' \
-d '{"name":"John Doe"}'
- Sample response
{
"success": true,
"invitations": {
"id": 1,
"name": "John Doe",
"email": "[email protected]",
"description": "Please join us to celebrate our wedding."
}
}
DELETE /invitations/int:id
- Delete an invitation by id.
- Sample Request:
curl -X DELETE \
http://localhost:5000/invitations/1 \
-H 'Authorization: Bearer {$TOKEN}' \
-H 'Content-Type: application/json'
- Sample response
{
"success": true,
"invitation_id": 1
}
GET /invitations/int:invitation_id/rsvps
- Get a list of RSVPs for an invitation by id.
- Sample Request:
curl -X GET \
http://localhost:5000/invitations/1/rsvps \
-H "Authorization: Bearer {$TOKEN}" \
-H 'Content-Type: application/json'
- Sample response
{
"success": true,
"rsvps": [
{
"id": 1,
"guest_name": "Mary Smith",
"guest_email": "[email protected]",
"response": "Attending",
"plus_one": true,
"invitation_id": 1
},
{
"id": 2,
"guest_name": "Tom Jones",
"guest_email": "[email protected]",
"response": "Not Attending",
"plus_one": false,
"invitation_id": 2
}
]
}
GET /invitations/int:invitation_id/rsvps/int:rsvp_id
- Returns an rsvp by id.
- Sample Request:
curl -X GET \
http://localhost:5000/invitations/1/rsvps/1 \
-H 'Authorization: Bearer {$TOKEN}' \
-H 'Content-Type: application/json'
- Sample Response:
{
"success": true,
"rsvps": {
"guest_name": "John Doe",
"guest_email": "[email protected]",
"response": "Attending",
"plus_one": "True"
}
}
POST /invitations/int:invitation_id/rsvps
- Creates a new RSVP for the given invitation ID.
- Sample Request:
curl -X POST \
http://localhost:5000/invitations/1/rsvps \
-H 'Authorization: Bearer {$TOKEN}' \
-H 'Content-Type: application/json' \
-d '{
"guest_name": "Jane Smith",
"guest_email": "[email protected]",
"response": "Not Attending",
"plus_one": false
}'
- Sample Response:
{
"success": true,
"rsvps": {
"id": 2,
"guest_name": "Jane Smith",
"guest_email": "[email protected]",
"response": "Not Attending",
"plus_one": false,
"invitation_id": 1
}
}
PATCH /invitations/int:invitation_id/rsvps/int:rsvp_id
- Updates an existing RSVP for the given invitation ID and RSVP ID.
- Sample Request:
curl -X PATCH \
http://localhost:5000/invitations/1/rsvps/1 \
-H 'Authorization: Bearer {$TOKEN}' \
-H 'Content-Type: application/json' \
-d '{
"guest_name": "John Smith",
"guest_email": "[email protected]",
"response": "Not Attending",
"plus_one": false
}'
- Sample Response:
{
"success": true,
"rsvps": {
"id": 1,
"guest_name": "John Smith",
"guest_email": "[email protected]",
"response": "Not Attending",
"plus_one": false,
"invitation_id": 1
}
}
DELETE /invitations/int:invitation_id/rsvps/int:rsvp_id
- Deletes an existing RSVP for the given invitation ID and RSVP ID.
- Sample Request:
curl -X DELETE \
http://localhost:5000/invitations/1/rsvps/1 \
-H 'Authorization: Bearer {$TOKEN}' \
-H 'Content-Type: application/json'
- Sample Response:
{
"success": true,
"rsvp_id": 1
}