Skip to content

she-codes-crowdfunding-api-project-Hauteclere created by GitHub Classroom

Notifications You must be signed in to change notification settings

SheCodesAus/example_finished_drf_project

 
 

Repository files navigation

Crowdfunding Back End

Table of Contents

Context

This is an example completed back-end for the She Codes Plus course content. It is intended for use in project feedback, to allow mentors to demonstrate techniques and code patterns to students, without needing to write a new app every time.

It is NOT intended to be shared with students before their DRF projects are submitted, since it includes content they are expected to synthesise themselves.

The deployed back-end can be found here: https://example-finished-drf-project.fly.dev/

A "tour" of some of the key concepts and patterns used in this project can be found here

Note To Students

This is a relatively complex app.

The aim here is to provide an example for most/all of the patterns and use-cases that mentors might want to demonstrate to students of the DRF module, and that means we needed to pick a slightly ambitious design.

If I saw this kind of work from a student, I would surmise that one or more of the following was true:

  • They had previous programming experience
  • They had a LOT of spare time to throw into the project
  • They had busted an absolute gut and were rightly proud of their effort

That means that it's perfectly fine and normal if your app is simpler or less developed than this! Remember, these projects are learning activities, not assessment activities. You're not supposed to go IN knowing how to ace the project; you're supposed to come OUT with a better understanding and an artifact that illustrates your coding journey.

Feel free to use this code as an inspiration to expand on your project after you have submitted it. And if you see something here that you'd like help interpreting or applying, feel free to reach out on slack to set up a 1-1 with a mentor.

App Name: "Examplify"

Examplify is a crowdfunding app that allows educators to connect students in their classes with tutors who have succeeded in the class previously.

Educators advertise upcoming exams (i.e., projects) that they need tutors for. Ex-students can pledge their time to help current students study, as long as they achieved a high enough grade on that same exam in a previous class. Educators can specify the grade they require their tutors to have achieved on an exam in order to quality to tutor for it.

Entity Relationship Diagram

API Spec

Scroll sideways to see the whole table!

URL HTTP Method Purpose Request Body Success Response Code Authentication/Authorisation Complete
/ GET Returns hello world to prevent the root URI from returning a 404. This is just a cosmetic feature so that it's instantly clear that the demo is working when it's opened in front of students. N/A 200 None
/api-token-auth/ POST Obtain a JWT to use as authentication at other endpoints, as well as the details of the currently-logged-in user. {
"username": ...,
"password": ...
}
200 Supply the correct username/password combo.
/users/ GET Query the list of all users. N/A 200 None
/users/ POST Create a new user account. {
"username": ...,
"email": ...,
"password: ...
}
201 None
/users/<int: pk>/ GET Retrieve the details of a specific user. N/A 200 None
/users/<int: pk>/ POST Record a specific user's result on an exam. {
"exam_id": ...
"score": ...
}
201 Bearer token (prefix: "Token ")
Must be the creator of the exam.
/exams/ GET Get the list of all exams it is possible to sit or study for. N/A 200 N/A
/exams/ POST Create a new exam. {
"name": ...
}
201 Bearer token (prefix: "Token ")
Must select a unique name for the new exam.
/exams/<int: pk>/ POST Create a new project {
"name": ...,
"tutor_for": ...
"description": ...,
"image": ...,
"required_grade": ...,
"required_tutoring_hours": ...,
"is_open": ...
}
201 Bearer token (prefix: "Token ")
Must be the creator of the associated exam.
/tutor_projects/ GET Query the list of all projects N/A 200 None
/tutor_projects/<int: pk>/ GET Retrieve the details of a specific project N/A 200 None
/tutor_projects/<int: pk>/ PUT Update the details of a specific project Fields to be updated 201 Bearer token (prefix: "Token ". Must be the creator of the project.)
/tutor_projects/<int: pk>/ POST Create a new pledge to a specific project. {
"hours_pledged": ...,
"comment": ...,
}
201 Bearer token (prefix: "Token ")
Must have an ExamResult that matches the exam and required_grade for this TutorProject. Also, the tutor_project must be open.
/tutor_pledges/ GET Query the list of all pledges. N/A 200 None
/tutor_pledges/<int: pk>/ DELETE Delete a specific pledge. N/A 204 Bearer token (prefix: "Token ")
Must either be the creator of the pledge, or the creator of the TutorProject

Notice how not every model in the ERD has an endpoint? That's not because we're showcasing perfect design - it's because we're showcasing a ruthlessly sparse MVP!

Perhaps a later iteration of this app would have a full set of CRUD endpoints for every model, but the goal of this module was to move fast and break stuff :)

Testing

The following tests take each row in the API spec table, and apply one test to each requirement that is set out there. This is important to do! I found a few errors that I had made while performing these tests.

I used manual testing here. That means I just went through and created a test in Insomnia for to check that the app fulfilled each stipulation in the API spec. An alternative to this is automated testing - writing code that checks each test case for you, so you don't need to click around in Insomnia every time you make a change to the app. The Django/DRF docs have some information on how to perform automated testing, and that would be an impressive way to build on this project to further demonstrate your skills!

Scroll sideways to see the whole table!

Endpoint Action JSON Expected Result Expected Code Success
/users/ GET details of current users N/A A list of current users. 200
/users/ POST a new user with correct details {"username": "testuser", "email": "test@user.com", "password": <PASSWORD HERE>} A JSON user object. 201
/users/ POST a new user with INCORRECT details {} A JSON errors object 400
/api-token-auth/ POST login with a correct email/password combo {"username": "testuser","password": <PASSWORD HERE>} The user details including email and primary key 200
/api-token-auth/ POST login with a incorrect email/password combo { "username": "testuser", "password": "wrongpass"} Failure to log in message 400
/users/<int: pk>/ GET the details of a specific user N/A Details of the user inclduing all owned exams, exam results, owned projects, and pledges 200
/users/<int: pk>/ GET the details of a user that does not exist N/A Not Found 404
/exams/ POST a correct new exam with authentication token. {"name": "newexam"} Details of the newly created exam. 201
/exams/ POST a correct new exam while not authenticated {"name": "unauthenticated exam"} "Unauthorised" message 401
/exams/ POST an incorrect exam while authenticated {} Description of field errors. 400
/exams/ POST exam with duplicate name while authenticated {"name": "newexam"} Duplicate name message 400
/users/<int: pk>/ POST a correct new exam result while authenticated {"exam": 2, "score": 1} Details of new exam result 200
/users/<int: pk>/ POST correct new exam result for non-existent user {"exam": 2, "score": 1} Not found 404
/users/<int: pk>/ POST correct new exam result for non-existent exam {"exam": 99, "score": 1} Invalid pk 400
/users/<int: pk>/ POST correct new exam result while NOT authenticated {"exam": 2, "score": 1} Unauthorised 401
/users/<int: pk>/ POST correct new exam result for a different educator's exam {"exam": 1, "score": 1} Forbidden 403
/users/<int: pk>/ POST malformed exam result {} Field errors 400
/exams/<int: pk>/ POST new project {"name": "newproject", "description": "a new project", "image": "https://upload.wikimedia.org/wikipedia/commons/4/48/Silly_Dog_%282277051513%29.jpg", "required_grade": 90, "required_tutoring_hours": 10, "is_open": true} Details of new project 201
/exams/<int: pk>/ POST new project NOT authenticated {"name": "newproject", "description": "a new project", "image": "https://upload.wikimedia.org/wikipedia/commons/4/48/Silly_Dog_%282277051513%29.jpg", "required_grade": 90, "required_tutoring_hours": 10, "is_open": true} Unauthorised 401
/exams/<int: pk>/ POST new project to non-existent exam {"name": "newproject", "description": "a new project", "image": "https://upload.wikimedia.org/wikipedia/commons/4/48/Silly_Dog_%282277051513%29.jpg", "required_grade": 90, "required_tutoring_hours": 10, "is_open": true} Not found 404
/exams/<int: pk>/ POST new project to a different educator's exam {"name": "newproject", "description": "a new project", "image": "https://upload.wikimedia.org/wikipedia/commons/4/48/Silly_Dog_%282277051513%29.jpg", "required_grade": 90, "required_tutoring_hours": 10, "is_open": true} Forbidden 403
/exams/<int: pk>/ POST a malformed new project {} Field errors 400
/tutor_projects/ GET list of projects N/A List of projects 200
/tutor_projects/<int: pk>/ GET details of specific project N/A Project details 200
/tutor_projects/<int: pk>/ GET details of project that does not exist N/A Not Found 404
/tutor_projects/<int: pk>/ PUT updated details of a project {"name": "updated name"} Updated project details 201
/tutor_projects/<int: pk>/ PUT updated details of project while NOT authenticated {"name": "updated name"} Unauthorised 401
/tutor_projects/<int: pk>/ PUT updated details of another educator's project {"name": "updated name"} Forbidden 403
/tutor_projects/<int: pk>/ PUT updated details of project that does not exist {"name": "updated name"} Not found 404
/tutor_projects/<int: pk>/ PUT malformed project details {"required_grade": "not a number"} Field errors 400
/tutor_projects/<int: pk>/ POST a pledge to a specific project {"hours_pledged": 1, "comment": "a comment"} Details of new pledge 200
/tutor_projects/<int: pk>/ POST a pledge while not authenticated {"hours_pledged": 1, "comment": "a comment"} Unauthorised 401
/tutor_projects/<int: pk>/ POST a pledge to a project that does not exist {"hours_pledged": 1, "comment": "a comment"} Not found 404
/tutor_projects/<int: pk>/ POST a malformed pledge {} Field errors 400
/tutor_projects/<int: pk>/ POST a pledge to a project without a sufficiently high ExamResult {"hours_pledged": 1, "comment": "a comment"} Forbidden 403
/tutor_projects/<int: pk>/ POST a pledge to a closed project {"hours_pledged": 1, "comment": "a comment"} Forbidden 403
/tutor_pledges/ GET list of pledges N/A List of pledges 200
/tutor_pledges/<int: pk>/ DELETE a pledge as pledger N/A N/A 204
/tutor_pledges/<int: pk>/ DELETE a pledge as pledgee N/A N/A 204
/tutor_pledges/<int: pk>/ DELETE pledge, NOT as pledger OR pledgee N/A Forbidden 403
/tutor_pledges/<int: pk>/ DELETE non existent pledge N/A Not found 404

About

she-codes-crowdfunding-api-project-Hauteclere created by GitHub Classroom

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 98.0%
  • Dockerfile 1.5%
  • Shell 0.5%