diff --git a/asystgrade/classes/api/client.php b/asystgrade/classes/api/client.php
index 61cdaa9cf4ab9e439ec170d1392fb465172fbe1f..6371f8c8e9e47fa6f590c2f076aca1ffa7cb6bda 100755
--- a/asystgrade/classes/api/client.php
+++ b/asystgrade/classes/api/client.php
@@ -3,20 +3,35 @@
 namespace local_asystgrade\api;
 
 use Exception;
+use \local_asystgrade\api\http_client_interface;
 
 defined('MOODLE_INTERNAL') || die();
 
 class client {
-    private $endpoint;
-    private $httpClient;
+    private string                $endpoint;
+    private http_client_interface $httpClient;
+    private static ?client        $instance = null;
 
     /**
      * @param string $endpoint
-     * @param http_client|null $httpClient
+     * @param http_client_interface $httpClient
      */
-    public function __construct(string $endpoint, http_client $httpClient = null) {
+    private function __construct(string $endpoint, http_client_interface $httpClient) {
         $this->endpoint = $endpoint;
-        $this->httpClient = $httpClient ?: new http_client();
+        $this->httpClient = $httpClient;
+    }
+
+    /**
+     * @param string $endpoint
+     * @param http_client_interface $httpClient
+     * @return client
+     */
+    public static function getInstance(string $endpoint, http_client_interface $httpClient): client
+    {
+        if (self::$instance === null) {
+            self::$instance = new client($endpoint, $httpClient);
+        }
+        return self::$instance;
     }
 
     /**
@@ -24,9 +39,12 @@ class client {
      * @return bool|string
      * @throws Exception
      */
-    public function send_data(array $data) {
-        $response = $this->httpClient->post($this->endpoint, $data);
-
-        return $response;
+    public function send_data(array $data): bool|string
+    {
+        try {
+            return $this->httpClient->post($this->endpoint, $data);
+        } catch (Exception $e) {
+            throw new Exception('HTTP request error: ' . $e->getMessage());
+        }
     }
 }
\ No newline at end of file
diff --git a/asystgrade/classes/db/QuizQuery.php b/asystgrade/classes/db/QuizQuery.php
new file mode 100755
index 0000000000000000000000000000000000000000..bb75f58e95e3a750293dbe801e1d4fa1c508082c
--- /dev/null
+++ b/asystgrade/classes/db/QuizQuery.php
@@ -0,0 +1,75 @@
+<?php
+namespace local_asystgrade\db;
+
+class QuizQuery implements QuizQueryInterface
+{
+    private $db;
+
+    public function __construct() {
+        global $DB;
+        $this->db = $DB;
+    }
+
+    /**
+     * @param $qid
+     * @param $slot
+     * @return mixed
+     */
+    public function get_question_attempts($qid, $slot) {
+        return $this->db->get_recordset(
+            'question_attempts',
+            [
+                'questionid' => $qid,
+                'slot' => $slot
+            ],
+            '',
+            '*'
+        );
+    }
+
+    /**
+     * @param $qid
+     * @return mixed
+     */
+    public function get_reference_answer($qid) {
+        return $this->db->get_record(
+            'qtype_essay_options',
+            [
+                'questionid' => $qid
+            ],
+            '*',
+            MUST_EXIST
+        )->graderinfo;
+    }
+
+    /**
+     * @param $question_attempt_id
+     * @return mixed
+     */
+    public function get_attempt_steps($question_attempt_id) {
+        return $this->db->get_recordset(
+            'question_attempt_steps',
+            [
+                'questionattemptid' => $question_attempt_id
+            ],
+            '',
+            '*'
+        );
+    }
+
+    /**
+     * @param $attemptstepid
+     * @return mixed
+     */
+    public function get_student_answer($attemptstepid) {
+        return $this->db->get_record(
+            'question_attempt_step_data',
+            [
+                'attemptstepid' => $attemptstepid,
+                'name' => 'answer'
+            ],
+            '*',
+            MUST_EXIST
+        )->value;
+    }
+}
diff --git a/asystgrade/classes/db/QuizQueryInterface.php b/asystgrade/classes/db/QuizQueryInterface.php
new file mode 100755
index 0000000000000000000000000000000000000000..4f1f0896cb32e64ce284cb8243bd162d780f8aac
--- /dev/null
+++ b/asystgrade/classes/db/QuizQueryInterface.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace local_asystgrade\db;
+
+interface QuizQueryInterface
+{
+    public function get_question_attempts($qid, $slot);
+
+    public function get_reference_answer($qid);
+
+    public function get_attempt_steps($question_attempt_id);
+
+    public function get_student_answer($attemptstepid);
+}
\ No newline at end of file
diff --git a/asystgrade/lib.php b/asystgrade/lib.php
index cc87de7a5b245519a71c68e514a84e16da058e07..11d96b6876c08defded5420d67bf1c0008e09208 100755
--- a/asystgrade/lib.php
+++ b/asystgrade/lib.php
@@ -21,6 +21,8 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 use local_asystgrade\api\client;
+use local_asystgrade\api\http_client;
+use local_asystgrade\db\QuizQuery;
 
 defined('MOODLE_INTERNAL') || die();
 
@@ -33,90 +35,24 @@ defined('MOODLE_INTERNAL') || die();
 
 function local_asystgrade_before_footer()
 {
-    global $PAGE, $DB;
+    global $PAGE;
 
     // Получение параметров из URL
     $qid = optional_param('qid', null, PARAM_INT);
     $slot = optional_param('slot', false, PARAM_INT);
 
     if ($PAGE->url->compare(new moodle_url('/mod/quiz/report.php'), URL_MATCH_BASE) && $slot) {
-        $question_attempts = $DB->get_recordset(
-            'question_attempts',
-            [
-                'questionid' => $qid,
-                'slot'       => $slot
-            ],
-            '',
-            '*'
-        );
-
-        // Obtaining exemplary answer
-        $referenceAnswer = $DB->get_record(
-            'qtype_essay_options',
-            [
-                'questionid' => $qid
-            ],
-            '*',
-            MUST_EXIST
-        )->graderinfo;
-
-        $studentAnswers = [];
-        $inputNames = [];
-        foreach ($question_attempts as $question_attempt) {
-
-            // Obtaining all steps for this questionusageid
-            $quizattempt_steps = $DB->get_recordset(
-                'question_attempt_steps',
-                [
-                    'questionattemptid' => $question_attempt->id
-                ],
-                '',
-                '*'
-            );
-
-            // Processing every quiz attempt step
-            foreach ($quizattempt_steps as $quizattempt_step) {
-                if ($quizattempt_step->state === 'complete') {
-                    $userid = $quizattempt_step->userid;
-                    $attemptstepid = $quizattempt_step->id;
-
-                    // Obtaining student's answer
-                    $studentAnswer = $DB->get_record(
-                        'question_attempt_step_data',
-                        [
-                            'attemptstepid' => $attemptstepid,
-                            'name'          => 'answer'
-                        ],
-                        '*',
-                        MUST_EXIST
-                    )->value;
-
-                    // Forming student's answers array
-                    $studentAnswers[] = $studentAnswer;
-
-                    // Forming correct mark text input field name: q + questionusageid : question's slot + _mark
-                    $inputNames[] = "q" . $question_attempt->questionusageid . ":" . $question_attempt->slot . "_-mark";
-
-                    error_log("User ID: $userid, Student Answer: $studentAnswer, Reference Answer: $referenceAnswer, Input Name: $inputNames[-1]");
-                }
-            }
+        $quizQuery = new QuizQuery();
 
-            // Closing of record's sets
-            $quizattempt_steps->close();
-        }
+        $question_attempts = $quizQuery->get_question_attempts($qid, $slot);
+        $referenceAnswer = $quizQuery->get_reference_answer($qid);
 
-        // Closing of record's sets
-        $question_attempts->close();
+        $data = prepare_api_data($quizQuery, $question_attempts, $referenceAnswer);
 
-        // API request preparation
-        $data = [
-            'referenceAnswer' => $referenceAnswer,
-            'studentAnswers'  => $studentAnswers
-        ];
+        $inputNames = $data['inputNames'];
 
         error_log('Data prepared: ' . print_r($data, true));
 
-        // Obtaining API settings
         $apiendpoint = get_config('local_asystgrade', 'apiendpoint');
         if (!$apiendpoint) {
             $apiendpoint = 'http://127.0.0.1:5000/api/autograde'; // Default setting
@@ -124,15 +60,14 @@ function local_asystgrade_before_footer()
 
         error_log('APIendpoint: ' . $apiendpoint);
 
-        // Initializing API client
         try {
-            $apiClient = new client($apiendpoint);
+            $httpClient = new http_client();
+            $apiClient = client::getInstance($apiendpoint, $httpClient);
             error_log('ApiClient initiated.');
 
-            // Sending data on API and obtaining auto grades
             error_log('Sending data to API and getting grade');
             $response = $apiClient->send_data($data);
-            $grades   = json_decode($response, true);
+            $grades = json_decode($response, true);
 
             error_log('Grade obtained: ' . print_r($grades, true));
         } catch (Exception $e) {
@@ -142,36 +77,96 @@ function local_asystgrade_before_footer()
 
         error_log('After API call');
 
-        // Check grades existence and pasting them at grade input fields through JavaScript DOM manipulations
-        $script = "
-            <script type='text/javascript'>
-                document.addEventListener('DOMContentLoaded', function() {";
-        foreach ($grades as $index => $grade) {
-            if (isset($grade['predicted_grade'])) {
-                $predicted_grade = $grade['predicted_grade'] == 'correct' ? 1 : 0;
-                // How forms param name="q2:1_-mark" see at https://github.com/moodle/moodle/blob/main/question/behaviour/rendererbase.php#L132
-                // and https://github.com/moodle/moodle/blob/main/question/engine/questionattempt.php#L381 , L407
-                $input_name = $inputNames[$index]; // Q is an question attempt -> ID of mdl_quiz_attempts, :1_ is question attempt -> step
-                $script     .= "
-                                console.log('Trying to update input: {$input_name} with grade: {$predicted_grade}');
-                                var gradeInput = document.querySelector('input[name=\"{$input_name}\"]');
-                                if (gradeInput) {
-                                    console.log('Found input: {$input_name}');
-                                    gradeInput.value = '{$predicted_grade}';
-                                } else {
-                                    console.log('Input not found: {$input_name}');
-                                }";
+        pasteGradedMarks($grades, $inputNames);
+
+        error_log('URL matches /mod/quiz/report.php in page_init');
+    }
+}
+
+/**
+ * Adds JavasScript scrypt to update marks
+ *
+ * @param mixed $grades
+ * @param mixed $inputNames
+ * @return void
+ */
+function pasteGradedMarks(mixed $grades, mixed $inputNames): void
+{
+    echo generate_script($grades, $inputNames);;
+}
+
+/**
+ * @param QuizQuery $database
+ * @param $question_attempts
+ * @param $referenceAnswer
+ * @return array
+ */
+function prepare_api_data(QuizQuery $database, $question_attempts, $referenceAnswer): array
+{
+    $studentAnswers = [];
+    $inputNames = [];
+
+    foreach ($question_attempts as $question_attempt) {
+        $quizattempt_steps = $database->get_attempt_steps($question_attempt->id);
+
+        foreach ($quizattempt_steps as $quizattempt_step) {
+            if ($quizattempt_step->state === 'complete') {
+                $studentAnswer = $database->get_student_answer($quizattempt_step->id);
+                $studentAnswers[] = $studentAnswer;
+                $inputNames[] = "q" . $question_attempt->questionusageid . ":" . $question_attempt->slot . "_-mark";
+
+                error_log("Student Answer: $studentAnswer, Input Name: " . end($inputNames));
             }
         }
-        $script .= "
-            });
-        </script>";
 
-        echo $script;
-        error_log('URL matches /mod/quiz/report.php in page_init');
+        $quizattempt_steps->close();
     }
+
+    $question_attempts->close();
+
+    return [
+        'referenceAnswer' => $referenceAnswer,
+        'studentAnswers' => $studentAnswers,
+        'inputNames' => $inputNames
+    ];
 }
 
+/**
+ * Builds JavasScript scrypt to update marks using DOM manipulations
+ *
+ * @param $grades
+ * @param $inputNames
+ * @return string
+ */
+function generate_script($grades, $inputNames) {
+    $script = "<script type='text/javascript'>
+        document.addEventListener('DOMContentLoaded', function() {";
+
+    foreach ($grades as $index => $grade) {
+        if (isset($grade['predicted_grade'])) {
+            $predicted_grade = $grade['predicted_grade'] == 'correct' ? 1 : 0;
+            $input_name = $inputNames[$index];
+            $script .= "
+                console.log('Trying to update input: {$input_name} with grade: {$predicted_grade}');
+                var gradeInput = document.querySelector('input[name=\"{$input_name}\"]');
+                if (gradeInput) {
+                    console.log('Found input: {$input_name}');
+                    gradeInput.value = '{$predicted_grade}';
+                } else {
+                    console.log('Input not found: {$input_name}');
+                }";
+        }
+    }
+
+    $script .= "});
+    </script>";
+
+    return $script;
+}
+
+/**
+ * Autoloader registration
+ */
 spl_autoload_register(function ($classname) {
     // Check if the class name starts with our plugin's namespace
     if (strpos($classname, 'local_asystgrade\\') === 0) {