restful api implementation - lorenzo-medici/PWP_StudentManager GitHub Wiki

Important information for Deadline 3

‼️  This chapter should be completed by Deadline 3 (see course information at Lovelace)


📑  Chapter summary In this section you must implement a RESTful API. The minimum requirements are summarized in the Minimum Requirements section of the Project Work Assignment. If you do not meet the minimum requirements this section WILL NOT be evaluated.

CHAPTER GOALS

  • Implement a RESTful API
  • Write tests for the API

✔️     Chapter evaluation (max 20 points) You can get a maximum of 20 points after completing this section. More detailed evaluation is provided in the evaluation sheet in Lovelace.

RESTful API implementation

List of implemented resources

📑  Content that must be included in the section A list of all resourcess. Each resource should include its URL, a short description and supported methods. You should mark also which is the name of the class implementing the resource (if you have implemented such resource) Consider that you do not need to implement every resource you initially planned.   The minimum requirements are summarized in the Minimum requirements section from the Project work assignment.

✏️ List your resources here. You can use the table below for listing resources. You can also list unimplemented resources if you think they are worth mentioning

Resource name Resource url Resource description Supported Methods Implemented
StudentCollection /api/students/ All the students enrolled at the University GET, POST StudentCollection
StudentItem /api/students/<student:student> A single student, identified by the student_id attribute GET, PUT, DELETE StudentItem
CourseCollection /api/courses/ All the courses offered by the University GET, POST CourseCollection
CourseItem /api/courses/<course:course>/ A single course, identified by the course_id attribute GET, PUT, DELETE CourseItem
AssessmentCollection /api/assessments/ Saving a new assessment POST AssessmentCollection
StudentAssessmentCollection, CourseAssessmentCollection /api/students/<student:student>/assessments/
/api/courses/<course:course>/assessments/
All the assessments for a given student or course GET StudentAssessmentCollection, CourseAssessmentCollection
StudentAssessmentItem, CourseAssessmentItem /api/students/<student:student>/assessments/<course:course>/
/api/courses/<course:course>/assessments/<student:student>/
A single assessment of a given student or course GET, PUT, DELETE StudentAssessmentItem, CourseAssessmentItem
ProfilePictureItem /api/students/<student:student>/profilePicture/ A student's profile picture (prototype: same for all, read only) GET ProfilePictureItem

Basic implementation

💻     TODO: SOFTWARE TO DELIVER IN THIS SECTION The code repository must contain:
  1. The source code for the RESTful API 
  2. The external libraries that you have used
  3. We recommend to include a set of scripts to setup and run your server
  4. A database file or the necessary files and scripts to automatically populate your database.
  5. A README.md file containing:
    • Dependencies (external libraries)
    • How to setup the framework.
    • How to populate and setup the database.
    • How to setup (e.g. modifying any configuration files) and run your RESTful API.
    • The URL to access your API (usually nameofapplication/api/version/)=> the path to your application.
Do not forget to include in the README.md file which is the path to access to your application remotely. NOTE: Your code MUST be clearly documented. For each public method/function you must provide: a short description of the method, input parameters, output parameters, exceptions (when the application can fail and how to handle such fail).  In addition should be clear which is the code you have implemented yourself and which is the code that you have borrowed from other sources. Always provide a link to the original source. This includes links to the course material.

✏️ You do not need to write anything in this section, just complete the implementation.


RESTful API testing

💻     TODO: SOFTWARE TO DELIVER IN THIS SECTION The code repository must contain:
  1. The code to test your RESTful API (Functional test)
    • The code of the test MUST be commented indicating what you are going to test in each test case.
    • The test must include values that force error messages
  2. The external libraries that you have used
  3. We recommend to include a set of scripts to execute your tests.
  4. A database file or the necessary files and scripts to automatically populate your database.
  5. A README.md file containing:
    • Dependencies (external libraries)
    • Instructions on how to run the different tests for your application.
Do not forget to include in the README.md the instructions on how to run your tests. Discuss briefly which were the main errors that you detected thanks to the functional testing. Remember that you MUST implement a functional testing suite. A detailed description of the input / output in the a REST client plugin. In this section it is your responsibility that your API handles requests correctly. All of the supported methods for each resource should work. You also need to show that invalid requests are properly handled, and that the response codes are correct in each situation.

✏️ Most important part of this section is completing the implementation. Write down here a short reflection on which are the main errors you have solved thanks to the functional tests.


REST conformance

📑  Content that must be included in the section Explain briefly how your API meets REST principles. Focus specially in these three principles: Addressability, Uniform interface, Statelessness. Provide examples (e.g. how does each HTTP method work in your API). Note that Connectedness will be addressed in more depth in Deadline 4.

✏️ Our API meets the following REST principles:

  • Addressability: each resource can be reached through a URL that uniquely points to it. For example, when using the GET method /api/students/1 will yield the student with the corresponding student_id and no other; /api/course/1 will only yield the course with the given course_id. Both these example URLs will point to the corresponding resource as long as it exists, once it is deleted they will no longer point to any valid resource. Addressability is also guaranteed by the fact that we are using URL converters for Students and Courses, which will handle the conversion between URL and database object. Students will be identified by their student_id, Courses by their course_id and Assessments by the pair (student_id, course_id).
  • Uniform interface: all the resources we defined use the HTTP methods in the standard way, GET returns the resource (or list of resources when called on a collection), DELETE removes the resource, PUT replaces the existing resource (setting to null any unspecified optional fields; we don't have any optional fields so this doesn't have any effect on our API), and POST adds a new resource to the collection it is called on. This allows any new developer to interact with the API in a standard way, without having to get into new method semantics.
  • Statelessness: all operations performed by the server are based strictly on the incoming request and on the model data stored at the time, we never store or access information about the client in order to complete the request, so the response will be the same (barring side-effects for DELETE/POST/PUT requests) for a new client or for a client that has already sent many requests. Furthermore, we don't make use of the concept of session for any purpose. Finally, authentication is not login-based, but makes use of tokens embedded in the request's header, and doesn't take into consideration information such as the user's IP address or the number of past exchanges.

Extras

📑  Details on extra features This section lists the additional features that will be graded as part of the API but are not required. In addition to implementing the feature you are also asked to write a short description for each.

URL Converters

📑  Fill this section if you used URL converters Write a short rationale of how URL converters are used, including your thoughts on the possible trade-offs. Go through all URL parameters in your API and describe whether they use a converter, what property is used for converting, or why it's not using a converter.

✏️ URL Converters are used in our API for the Student and Course resources. Both students and courses are converted based on their respective id, used as primary key in the database. We chose to use converters because they simplify the application code of the Resource classes, and handle the boilerplate code that would be repeated for each request.

We couldn't use URL Converters for the Assessment resources, because they are uniquely identified by two different fields in the URL: student_id and course_id. Once the Student and Course are converted by their respective URLConverters, the desired Assessment can be retrieved. The URL for an Assessment is the URL for the CourseAssessmentItem resource /api/courses/<course_id>/assessments/<student_id>/


Schema Validation

📑  Fill this section if you used JSON schema validation Write a short description of your JSON schemas, including key decision making for choosing how to validate each field.

✏️ JSON schemas are used in our application for all database entities, in order to simplify and de-clutter the application code in POST and PUT methods. Since all fields are not nullable in our database, all fields of the schemas are mandatory, this will not be repeated for each entity.

Student schema:

  • first_name, "string"
  • last_name, "string"
  • date_of_birth, "string" with format "date-time", validated using Draft7Validator.FORMAT_CHECKER, checked if it is in the past done by database constraints
  • ssn, "string", validated through SQLAlchemy's @validates functions, uniqueness checked through database constraints, both when adding the student to the database

Course schema:

  • title, "string"
  • teacher, "string"
  • code, "string", uniqueness checked by database constraints
  • ects, "number", checked if it is an integer after unpacking request.json

Assessment schema:

  • student_id: "number", checked if it is an integer after unpacking request.json, checked for validity as foreign key by database constraints
  • course_id: "number", checked if it is an integer after unpacking request.json, checked for validity as foreign key by database constraints
  • grade: "number", checked if it is an integer after unpacking request.json, checked for correct range by database constraint
  • date: "string" with format "date-time", validated using Draft7Validator.FORMAT_CHECKER, checked if it is in the past done by database constraints

Caching

📑  Fill this section if you implemented server side caching

✏️ Our application relies on several resource classes, including CourseCollection, CourseItem, StudentCollection,StudentItem and AssessmentCollection. We have implemented a caching system to enhance their performance. To this end, we imported the cache module from the studentmanager package and applied the @cache.cached() decorator to the get() methods of the resource classes.

The current implementation of cache does not have an expiration time because we hardly anticipate that the resources will be modified frequently. However to ensure the integrity of values stored in cache, we update the cache on every post,put and delete of a resource. To maintain cache consistency, we use the _clear_cache() method in the collection classes. This method is triggered whenever a new course or student is added to the database or when changes are made to the existing data. Specifically, the method relies on the delete() or delete_many() function of the cache module to remove the cached results for the current resource. In case of the assessments collection,the caching is implemented using the cache.cached decorator with a custom make_cache_key function that generates a unique cache key based on the request's path.This function removes the cache entries for the following endpoints:

  • Assessment's view
  • Course's assessments view
  • Student's assessments view
  • Course's and student's view (since assessments are included in serialize()).

Authentication

📑  Fill this section if you implemented authentication Explain your authentication scheme here. Describe the authentication requirements for each resource in your API, and your reasoning for the decisions. In addition, provide a plan for how API keys will be distributed, even if the distribution is not currently implemented.

✏️ For our API we opted for two different "tiers" of authentication keys: admin and assessments. The role of the admin key is to have complete control over the whole database, while the assessments key would be limited to acting on the AssessmentCollection and AssessmentItem resources. This choice follows naturally from the different levels of importance and rigidity of the different resources. The existing instances of students and courses should be extremely stable over time, while it could be more common to change individual assessments; adding the latter would also happen very frequently. Furthermore, deleting an individual student or, worse, a course, would have big repercussions on the assessments stored in the database, and should be done only by qualified and responsible personnel, that has been granted an admin key.

In both cases, the restrictions only apply to POST, PUT and DELETE methods on the related resources, GET methods are always available without any key.

Distribution of assessment keys could be done through a simple web page, where professors could input their credentials and receive their own assessment key. Requirements for granting assessment keys could be defined by a third entity (e.g. security board of the University), who could handle the distribution completely if given access to the database (or if our API connected to their database). Since the admin keys would be more powerful and sensitive, such methods of distribution would be somewhat unsafe, ideally the admin key should be given to very few and trusted employees, so a direct exchange would be used instead.


Resources allocation

Task Student Estimated time
Meetings All 4h
Implementing Assessment Resource Daniel Szabo 6h
Fixing Project Structure Lorenzo Medici 1h
Wiki and README Lorenzo Medici 1h
Coverage, Pylint, code quality Lorenzo Medici 2h
Caching, Authentication Lorenzo Medici 2h
Course collection Implementation Pranav Bahulekar 5h
Student Collection Implementation Alessandro Nardi 5h
⚠️ **GitHub.com Fallback** ⚠️