This is an api for a casting-agency. It covers following technical topics in 1 app:-
- Database modeling with
postgres
&sqlalchemy
(seemodels.py
) - API to performance CRUD Operations on database with
Flask
(seeapp.py
) - Automated testing with
Unittest
(seetest_app
) - Authorization & Role based Authentification with
Auth0
(seeauth.py
) - Deployment on
Heroku
Make sure you cd
into the correct folder (with all app files) before following the setup steps.
Also, you need the latest version of Python 3
and postgres installed on your machine.
To start and run the local development server,
- Initialize and activate a virtualenv:
$ virtualenv --no-site-packages env_capstone
$ source env_capstone/scripts/activate
- Install the dependencies:
$ pip install -r requirements.txt
Running this project locally means that it can´t access Herokus
env variables.
To fix this, you need to edit a few informations in config.py
, so it can
correctly connect to a local database
- Change database config so it can connect to your local postgres database
- Open
config.py
with your editor of choice. - Here you can see this dict:
database_setup = {
"database_name_production" : "agency",
"user_name" : "postgres", # default postgres user name
"password" : "testpassword123", # if applicable. If no password, just type in None
"port" : "localhost:5432" # default postgres port
}
- Just change
user_name
,password
andport
to whatever you choose while installing postgres.
tip:
user_name
usually defaults topostgres
andport
always defaults tolocalhost:5432
while installing postgres, most of the time you just need to change thepassword
.
- Setup Auth0
If you only want to test the API (i.e. Project Reviewer), you can
simply take the existing bearer tokens in
config.py
.
If you already know your way around Auth0
, just insert your data
into config.py
=> auth0_config.
FYI: Here are the steps I followed to enable authentification.
- Run the development server:
$ python app.py
- (optional) To execute tests, run
$ python test_app.py
If you choose to run all tests, it should give this response if everything went fine:
$ python test_app.py
.........................
----------------------------------------------------------------------
Ran 25 tests in 18.132s
OK
Here you can find all existing endpoints, which methods can be used, how to work with them & example responses you´ll get.
Additionally, common pitfalls & error messages are explained, if applicable.
https://artist-capstone-fsnd-matthew.herokuapp.com
Please see API Authentification
Here is a short table about which ressources exist and which method you can use on them.
Allowed Methods
Endpoints | GET | POST | DELETE | PATCH |
|------|-------|---------|--------|
/actors | [x] | [x] | [x] | [x] |
/movies | [x] | [x] | [x] | [x] |
Click on a link to directly get to the ressource.
- Actors
- Movies
Each ressource documentation is clearly structured:
- Description in a few words
curl
example that can directly be used in terminal- More descriptive explanation of input & outputs.
- Required permission
- Example Response.
- Error Handling (
curl
command to trigger error + error response)
Query paginated actors.
$ curl -X GET localhost/actors?page1
- Fetches a list of dictionaries of examples in which the keys are the ids with all available fields
- Request Arguments:
- integer
page
(optional, 10 actors per page, defaults to1
if not given)
- integer
- Request Headers: None
- Requires permission:
read:actors
- Returns:
- List of dict of actors with following fields:
- integer
id
- string
name
- string
gender
- integer
age
- integer
- boolean
success
- List of dict of actors with following fields:
{
"actors": [
{
"age": 25,
"gender": "Male",
"id": 1,
"name": "Matthew"
}
],
"success": true
}
If you try fetch a page which does not have any actors, you will encounter an error which looks like this:
$ curl -X GET localhost/actors?page123124
will return
{
"error": 404,
"message": "no actors found in database.",
"success": false
}
Insert new actor into database.
$ curl -X POST localhost/actors
- Request Arguments: None
- Request Headers: (application/json)
1. string
name
(required) 2. integerage
(required) 3. stringgender
- Requires permission:
create:actors
- Returns:
- integer
id from newly created actor
- boolean
success
- integer
{
"created": 5,
"success": true
}
If you try to create a new actor without a requiered field like name
,
it will throw a 422
error:
$ curl -X GET localhost/actors?page123124
will return
{
"error": 422,
"message": "no name provided.",
"success": false
}
Edit an existing Actor
$ curl -X PATCH localhost/actors/1
- Request Arguments: integer
id from actor you want to update
- Request Headers: (application/json)
1. string
name
2. integerage
3. stringgender
- Requires permission:
edit:actors
- Returns:
- integer
id from updated actor
- boolean
success
- List of dict of actors with following fields:
- integer
id
- string
name
- string
gender
- integer
age
- integer
- integer
{
"actor": [
{
"age": 30,
"gender": "Other",
"id": 1,
"name": "Test Actor"
}
],
"success": true,
"updated": 1
}
If you try to update an actor with an invalid id it will throw an 404
error:
$ curl -X PATCH localhost/actors/125
will return
{
"error": 404,
"message": "Actor with id 125 not found in database.",
"success": false
}
Additionally, trying to update an Actor with already existing field values will result in an 422
error:
{
"error": 422,
"message": "provided field values are already set. No update needed.",
"success": false
}
Delete an existing Actor
$ curl -X DELETE localhost/actors/1
- Request Arguments: integer
id from actor you want to delete
- Request Headers:
None
- Requires permission:
delete:actors
- Returns:
- integer
id from deleted actor
- boolean
success
- integer
{
"deleted": 5,
"success": true
}
If you try to delete actor with an invalid id, it will throw an 404
error:
$ curl -X DELETE localhost/125
will return
{
"error": 404,
"message": "Actor with id 125 not found in database.",
"success": false
}
Query paginated movies.
$ curl -X GET https://localhost/movies?page1
- Fetches a list of dictionaries of examples in which the keys are the ids with all available fields
- Request Arguments:
- integer
page
(optional, 10 movies per page, defaults to1
if not given)
- integer
- Request Headers: None
- Requires permission:
read:movies
- Returns:
- List of dict of movies with following fields:
- integer
id
- string
name
- date
release_date
- integer
- boolean
success
- List of dict of movies with following fields:
{
"movies": [
{
"id": 1,
"release_date": "Sun, 16 Feb 2020 00:00:00 GMT",
"title": "Matthew first Movie"
}
],
"success": true
}
If you try fetch a page which does not have any movies, you will encounter an error which looks like this:
$ curl -X GET https://localhost/movies?page123124
will return
{
"error": 404,
"message": "no movies found in database.",
"success": false
}
Insert new Movie into database.
$ curl -X POST https://localhost/movies
- Request Arguments: None
- Request Headers: (application/json)
1. string
title
(required) 2. daterelease_date
(required) - Requires permission:
create:movies
- Returns:
- integer
id from newly created movie
- boolean
success
- integer
{
"created": 5,
"success": true
}
If you try to create a new movie without a requiered field like name
,
it will throw a 422
error:
$ curl -X GET https://localhost/movies?page123124
will return
{
"error": 422,
"message": "no name provided.",
"success": false
}
Edit an existing Movie
$ curl -X PATCH https://localhost/movies/1
- Request Arguments: integer
id from movie you want to update
- Request Headers: (application/json)
1. string
title
2. daterelease_date
- Requires permission:
edit:movies
- Returns:
- integer
id from updated movie
- boolean
success
- List of dict of movies with following fields:
- integer
id
- string
title
- date
release_date
- integer
- integer
{
"created": 1,
"movie": [
{
"id": 1,
"release_date": "Sun, 16 Feb 2020 00:00:00 GMT",
"title": "Test Movie 123"
}
],
"success": true
}
If you try to update an movie with an invalid id it will throw an 404
error:
$ curl -X PATCH https://localhost/movies/125
will return
{
"error": 404,
"message": "Movie with id 125 not found in database.",
"success": false
}
Additionally, trying to update an Movie with already existing field values will result in an 422
error:
{
"error": 422,
"message": "provided field values are already set. No update needed.",
"success": false
}
Delete an existing movie
$ curl -X DELETE https:/localhost/movies/1
- Request Arguments: integer
id from movie you want to delete
- Request Headers:
None
- Requires permission:
delete:movies
- Returns:
- integer
id from deleted movie
- boolean
success
- integer
{
"deleted": 5,
"success": true
}
If you try to delete movie with an invalid id, it will throw an 404
error:
$ curl -X DELETE https://localhost/movies/125
will return
{
"error": 404,
"message": "Movie with id 125 not found in database.",
"success": false
}
All API Endpoints are decorated with Auth0 permissions. To use the project locally, you need to config Auth0 accordingly
- Login to https://manage.auth0.com/
- Click on Applications Tab
- Create Application
- Give it a name like
Music
and select "Regular Web Application" - Go to Settings and find
domain
. Copy & paste it into config.py => auth0_config['AUTH0_DOMAIN'] (i.e. replace"example-matthew.eu.auth0.com"
) - Click on API Tab
- Create a new API:
- Name:
Music
- Identifier
Music
- Keep Algorithm as it is
- Name:
- Go to Settings and find
Identifier
. Copy & paste it into config.py => auth0_config['API_AUDIENCE'] (i.e. replace"Example"
)
- Before creating
Roles & Permissions
, you need toEnable RBAC
in your API (API => Click on your API Name => Settings = Enable RBAC => Save) - Also, check the button
Add Permissions in the Access Token
. - First, create a new Role under
Users and Roles
=>Roles
=>Create Roles
- Give it a descriptive name like
Casting Assistant
. - Go back to the API Tab and find your newly created API. Click on Permissions.
- Create & assign all needed permissions accordingly
- After you created all permissions this app needs, go back to
Users and Roles
=>Roles
and select the role you recently created. - Under
Permissions
, assign all permissions you want this role to have.
If you want to access the real, temporary API, bearer tokens for all 3 roles are included in the config.py
file.
They are 3 Roles with distinct permission sets:
- Casting Assistant:
- GET /actors (view:actors): Can see all actors
- GET /movies (view:movies): Can see all movies
- Casting Director (everything from Casting Assistant plus)
- POST /actors (create:actors): Can create new Actors
- PATCH /actors (edit:actors): Can edit existing Actors
- DELETE /actors (delete:actors): Can remove existing Actors from database
- PATCH /movies (edit:movies): Can edit existing Movies
- Exectutive Dircector (everything from Casting Director plus)
- POST /movies (create:movies): Can create new Movies
- DELETE /movies (delete:movies): Can remove existing Motives from database
In your API Calls, add them as Header, with Authorization
as key and the Bearer token
as value. Don´t forget to also
prepend Bearer
to the token (seperated by space).
For example: (Bearer token for Executive Director
)
{
"Authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik16azVRVUk0TXpSR04wSXhOVU13TkRrME16QXdNMFpHTmtFMU1VWXdPRUpCTmpnMFJrVTBSZyJ9.eyJpc3MiOiJodHRwczovL2ZzbmQtbWF0dGhldy5ldS5hdXRoMC5jb20vIiwic3ViIjoiYXV0aDB8NWU0N2VmYzc2N2YxYmEwZWJiNDIwMTYzIiwiYXVkIjoiTXVzaWMiLCJpYXQiOjE1ODE4NjI0NjksImV4cCI6MTU4MTg2OTY2OSwiYXpwIjoiVGh2aG9mdmtkRTQwYlEzTkMzSzdKdFdSSzdSMzFOZDciLCJzY29wZSI6IiIsInBlcm1pc3Npb25zIjpbImNyZWF0ZTphY3RvcnMiLCJjcmVhdGU6bW92aWVzIiwiZGVsZXRlOmFjdG9ycyIsImRlbGV0ZTptb3ZpZXMiLCJlZGl0OmFjdG9ycyIsImVkaXQ6bW92aWVzIiwicmVhZDphY3RvcnMiLCJyZWFkOm1vdmllcyJdfQ.iScamWOFNx9pjiVZhsvPzDoRi6EraZaxWg-WMj80HNW_-dchkOymnKA7OOhPQ8svLc9-wViLlCT-ySnupZ-209cIBVHSA_slncSP-lzEM6NKbBmDEETTQ1oxv2jTH-JL72eLhyAWUsmSIZDmEab1hln1yWEN7mUnn0nZJfxCRCs89h5EGJzXS2v8PbAjq9Mu7wFsrioEMx_PGWzSM0r5WIrKBvpXRy0Jm-vssZl4M1akDHIL5Shcfp_Bfnarc2OLOMvdQVHVDEWhrbFSnfCENLDxkcmB18VnOedJAuY_C88YRUfY2wQAOPux8RVuqIb5KxTg4YP7kiDcBU"
}