CSC/ECE 517 Spring 2024 - E2445. Implement BackEnd for participants.rb
Expertiza
Expertiza stands out as an open-source initiative rooted in the Ruby on Rails framework, brought to life through the collective efforts of NC State's faculty and students. This web application supports instructors in creating tailored assignments that can either be new or build upon existing ones. Moreover, it allows for the organization of topics into a roster for student selection. Expertiza offers students the chance to team up for joint projects and assignments, promoting collaborative learning. A key feature of this platform is enabling students to peer-review their colleagues' work.
With its capability to handle a wide variety of document types, Expertiza accepts submissions in formats ranging from URLs to wiki pages. As an open-source learning management system crafted with Ruby on Rails, it boasts a broad range of features that facilitate the submission and peer review of diverse learning materials, including articles, code, and websites. Instructors and teaching assistants can easily monitor and evaluate these submissions, making Expertiza a valuable tool for managing course assignments.
Introduction
To develop the backend functionality for the participants controller of Expertiza, ensuring seamless integration with the enhanced user interface for participants. This involves setting up API endpoints for CRUD (Create, Read, Update, Delete) operations, integrating with the database, and ensuring data integrity and security. Our focus includes thorough rswag testing of the participants_controller method and demonstrating Swagger UI integration.
Problem Statement
The reimplementation project entails:
- CRUD Operations: Setting up CRUD (Create, Read, Update, Delete) functionalities in the controller to streamline data handling.
- Routes: Establishing pathways for accessing actions within the participants controller.
- Database: Maintaining a database for participant information, including their connections to "Assignment".
- Adherence to DRY Principle: Adhering to the Don't Repeat Yourself (DRY) principle to minimize redundancy and enhance coding efficiency.
- Testing with RSwag: Developing detailed tests using RSwag for every controller action, ensuring their performance and compatibility with Swagger UI. This includes a video tutorial to illustrate the integration with Swagger UI and the operational efficiency of the revamped controller.
Design
Implementation of Participants Controller
The Participants Controller is designed to handle various interactions with participant data within an application, providing a range of RESTful actions. This controller facilitates operations such as listing all participants, retrieving specific participant details, and creating, updating, or deleting participant records, all through JSON responses suitable for API usage. It includes actions that are traditionally used in view-based controllers (such as new and edit) to instantiate and prepare participants for creation or editing. Additionally, the controller offers a specialized action to fetch and render a participant's assignment, enhancing its functionality by addressing specific data retrieval needs. It also implements global error handling for missing records, ensuring that all actions gracefully handle cases where participants are not found. This comprehensive approach makes the controller a central part of the participant management system in the application, equipped to handle both standard CRUD operations and specific relational data accesses in a structured and efficient manner.
Implemented methods
"Create Method" Commit
def create @participant = Participant.new(participant_params) if @participant.save render json: @participant, status: :created else render json: @participant.errors, status: :unprocessable_entity end end
create
action will handle the addition of new participants. It will take participant information, conducts security validations, ensures data integrity, and inserts the new record into the database, responding with the participant's details in JSON format or an error message if the process fails.
"Read Method" Commit
def index @participants = Participant.all render json: { participants: @participants }, status: :ok end
index
action will accept a participant ID, retrieves the corresponding data from the database, and returns it as a JSON object. If the participant does not exist, it will send an error message.
"Update Method" Commit
def update @participant = Participant.find(params[:id]) if @participant.update(participant_params) render json: { participant: @participant }, status: :ok else render json: @participant.errors, status: :unprocessable_entity end end
update
action will require a participant ID and the new data to be provided. The method will update the relevant record after security and data validation checks and returns the updated information in JSON format.
"Delete Method" Commit
def destroy @participant = Participant.find(params[:id]) @participant.destroy render json: { message: "Participant was successfully destroyed." }, status: :ok end
delete
action will remove a participant's record using their ID, ensuring that the request is authenticated and the user is authorized to perform the deletion. Upon successful deletion, it will confirm the action with a success response; otherwise, it returns an error.
"Participants of a particular assignment Method" Commit
def fetch_participants_for_assignment participants = Participant.where(assignment_id: params[:assignment_id]) render json: participants, status: :ok end
The fetch_participants_for_assignment
method will receive an assignment ID, this method will join the pertinent records from the participants and assignments tables, retrieving a comprehensive dataset that is then converted into a JSON array. This method will be instrumental for scenarios where a holistic view of assignment participation is required.
"Assignment of a particular Participant Method" Commit
def fetch_assignment_for_participant participant = Participant.find(params[:participant_id]) assignment = participant.assignment render json: assignment, status: :ok rescue ActiveRecord::RecordNotFound render json: { error: "Participant not found" }, status: :not_found end
The fetch_assignment_for_participant
method is designed to retrieve the assignment associated with a specific participant. It takes a participant ID from the request parameters, finds the corresponding participant record, and accesses its associated assignment. The assignment data is then rendered as a JSON object.
Design Principles
Single Responsibility Principle (SRP):
- Every function within the ParticipantsController will handle a distinct aspect of participant management.
- The functions will undergo restructuring to delineate responsibilities like fetching data, performing calculations, and presenting views.
- As an illustration, the view function will be dedicated to acquiring participant information.
Don't Repeat Yourself (DRY) Principle:
- Redundant code within the ParticipantsController will be reduced by moving shared functionalities into auxiliary methods or modules.
Encapsulation:
- The ParticipantsController will organize data and functionality into suitable methods and classes to reduce dependencies.
- The scope of access to instance variables and controller actions will be restricted to foster encapsulation and ensure a clear division of responsibilities.
Testing Plan
We employ a combination of manual testing with tools like Postman, automated testing through RSpec, and API documentation and testing using Swagger. This comprehensive approach allows us to validate our API's functionality, security, and usability across various scenarios.
Manual testing with Postman
We are using Postman to test our APIs during the development process. Below are few examples:
- GET /api/v1/participants: Endpoint to test the fetching of all Participants.
Fig 5.1.1 Postman UI displaying API testing to fetch all Participant.
- POST /api/v1/participants: Endpoint to test the creation of a Participant.
Fig 5.1.2 Postman UI displaying API testing to create a Partcipant.
- PATCH api/v1/participants/4: Endpoint to test the functionality of updating Participant using its ID.
Fig 5.1.3 Postman UI displaying API testing to update a Participant using its ID.
- DELETE api/v1/participants/4: Endpoint to test the functionality of deleting a Participant with participant id.
Fig 5.1.4 Postman UI displaying API testing to delete a Participant using its ID.
- GET api/v1/assignments/1/participants: Endpoint to test the functionality of fetching a participant using assignment Id.
Fig 5.1.5 Postman UI displaying API testing to fetch a participant using assignment Id.
- GET api/v1/participants/1/assignment: Endpoint to test the functionality of fetching an assignment using participant Id.
Fig 5.1.5 Postman UI displaying API testing to fetch an assignment using participant Id.
Automated Testing with Rspec
Scenario 1: Creating a New Participant
Validates the creation of a new Participant with appropriate parameters.
Expectation: Expects a 201 Created status and a JSON response with the created participant details.
describe "POST #create" do context "with valid parameters" do it "creates a new participant" do expect { post :create, params: { participant: attributes_for(:participant) } }.to change(Participant, :count).by(1) expect(response).to have_http_status(:created) end end end
Scenario 2: Handling Invalid Participant Creation
Tests the creation process with invalid parameters to ensure robust error handling.
Expectation: Expects a 400 Bad Request status and an error message detailing the invalid parameters.
context "with invalid parameters" do it "does not create a new participant" do expect { post :create, params: { participant: { user_id: nil } } }.to change(Participant, :count).by(0) expect(response).to have_http_status(:unprocessable_entity) end end
Scenario 3: Fetch a Participant who is not in the database
Checks the behaviour when attempting to fetch a Participant not present in the database.
Expectation: Expects a not found status
context "when the participant does not exist" do it "returns a not found status" do get :show, params: { id: -1 } expect(response).to have_http_status(:not_found) end end
Scenario 4: Fetching an Assignment of a particular Participant
Validates the functionality for fetching an Assignment of a particular Participant Id Expectation: Expects a 200 Ok status with the assignment of the participant.
describe "#participant_assignment" do context "when participant exists" do it "returns the assignment of the participant" do get :participant_assignment, params: { participant_id: participant.id } expect(response).to have_http_status(:ok) end end end
Scenario 5: Fetching an Assignment of an invalid Participant
Validates the functionality for fetching an Assignment of an Invalid Participant Id
Expectation: Expects a not found status status.
context "when participant does not exist" do it "returns not found status" do get :participant_assignment, params: { participant_id: -1 } expect(response).to have_http_status(:not_found) end end
Scenario 6: Updating a Participant
Ensures that an existing participant can be updated with valid parameters.
Expectation: Expects a 200 OK status and the updated participant details in the response.
describe "PATCH/PUT #update" do context "with valid parameters" do it "updates the participant" do patch :update, params: { id: participant.id, participant: { type: "NewType" } } expect(response).to have_http_status(:ok) end end end
Scenario 7: Updating a Participant
Checks the behavior when attempting to update a participant with invalid parameters.
Expectation: Expects a 422 Unprocessable Entity status and an error message detailing the issue.
context "with invalid parameters" do it "does not update the participant" do patch :update, params: { id: participant.id, participant: { user_id: nil } } expect(response).to have_http_status(:unprocessable_entity) end end
API Documentation and Testing with Swagger
To provide clear, interactive API documentation, facilitating easy understanding and testing of API endpoints.
Setup: Integrate Swagger with Rails application using gems like rswag.
Documentation: Annotate the API code to generate Swagger documentation automatically. Ensure that each endpoint is clearly described, with information on parameters, request bodies, and response schemas. Interactive Testing: Use the Swagger UI to interactively test API endpoints directly from the browser, providing an easy way for non-developers to understand and verify API functionality.
Fig 5.3 Swagger UI displaying API documentation and interactive testing interface for Participants endpoints.
Relevant Links
- Github Repository: https://github.com/achitti2812/expertiza_project4
- Pull Request: https://github.com/expertiza/reimplementation-back-end/pull/105
- Test Video Link: https://youtu.be/hwGuzbqcyjQ
Team
Mentor
- Chunduru Chetana
Members
- Akhilsai Chittipolu
- Koushik Gudipelly
- Sri Vaishnavi Mylavarapu