Каков правильный путь в API отдыха для проверки ответов?

Я создаю веб-сайт в стеке MERN для образовательных целей. В нем есть анкета с 40 вопросами типа «да или нет» (утверждения, которые могут быть правдивыми или ложными) по одному конкретному предмету. Предметов может быть много, но утверждения всегда одинаковы для всех предметов.

После того, как пользователь завершит ответ, ответы должны быть отправлены (или ПОЛУЧИТЬ из?) API отдыха.

Серверная часть просто получает правильные ответы из БД, а затем проверяет ответы пользователей на них и отвечает с результатом.

Модель в бэкэнде - это просто документы, каждый из которых состоит из subject id и 40 логических as1 к as40.

(Новичок в nosql, так что я, возможно, полностью убил свою модель, в этом случае я бы с радостью исправился!)

Как правильно называть эту службу отдыха?

Думаю, я использую тело POST, например:

      {
    "answers": {
        "uas1": true,
        "uas2": false,
        ...
        "uas39": true,
        "uas40": false
    }
}

... но как должен выглядеть путь?

/statements/:id/answer?

2 ответа

Решение

Как правильно называть эту службу отдыха?

Основной вопрос, который вам нужно решить, - это понять, извлекает ли клиент ресурс (фактически операция только для чтения) или изменяет ресурс. Получение ресурса может означать извлечение ресурса из кеша , вместо того, чтобы позволить запросу пройти весь путь до вашего сервера.

Серверная часть просто получает правильные ответы из БД, а затем проверяет ответы пользователей на них и отвечает с результатом.

Для меня это звучит очень похоже на случай, когда используется только чтение: учитывая список ответов, найдите соответствующий документ с ответами. Поэтому обычным ответом для такой модели ресурсов было бы использование GET.

В Интернете это может выглядеть как большая форма с элементами управления вводом для 40 различных вопросов. Пользователь делал свой выбор, а затем нажимал кнопку отправки. Браузер будет использовать входные данные для вычисления строки запроса и выполнения HTTP-запроса GET, при этом все входные данные пользователя будут закодированы в части запроса (в соответствии с метаданными самой формы.

      ?a1=Y&a2=N&a3=T...&a40=Y

Используя HTML-формы, мы можем использовать любое написание для нужного пути, а также любое написание, которое мы хотим для ключей в части запроса, потому что эта информация становится частью метаданных формы: браузер может просто посмотреть на определение формы , и это описывает, как создать эффективный URI запроса (это часть стандарта для обработки HTML-форм).

Для чего-то вроде идентификатора субъекта у вас есть выбор между кодированием этой информации в путь (сделав эту информацию частью действия формы) или в части запроса (как ввод формы - возможно, «скрытый»).

как должен выглядеть путь?

Все, что угодно - REST не заботится о том, какие правила написания вы используете для идентификаторов ресурсов.

      GET /83eeecdd-a680-475f-913b-07aa0239cec0?a1=Y&a2=N&a3=T...&a40=Y

... в порядке . Вы, вероятно, хотите что-то более приятное для людей - операторы, читающие журнал, пользователь, просматривающий историю своего браузера, авторы, пытающиеся задокументировать модель ресурсов для других разработчиков и т. Д.

      GET /subject/:subject_id/answers?a1=Y&a2=N&a3=T...&a40=Y

Тоже все в порядке.


Думаю, я использую тело POST, например:

Судя по вашему описанию, это не мой первый выбор.

Запрос вроде

      POST /statements/:id/answer
Content-Type: application/json

{...}

имеет, с точки зрения компонента общего назначения, очень мало ограничений; компонент общего назначения не может предполагать, что POST фактически доступен только для чтения. Это означает, что мы не можем извлечь ответ из кеша. На самом деле, верно и обратное: успешный запрос POST приведет к тому, что кеши общего назначения аннулируют ранее сохраненные ответы с использованием того же эффективного uri.

Компонент общего назначения не может даже предполагать, что запросы POST имеют идемпотентную семантику, поэтому приложение HTTP не может автоматически помочь нам, повторно отправив запрос, если ответ потерян.


В случае, когда эффективная семантика только для чтения вам не подходит, можно использовать POST . С HTML-формами это был бы наш единственный реальный вариант.

Но было бы лучше, если бы вы могли разработать свою модель ресурсов так, чтобы каждый набор представленных ответов был отдельным ресурсом. Вы можете представить это так: пользователь ПОЛУЧАЕТ уникальную анкету, в которой все ответы пусты. Они заполняют свои собственные ответы и возвращают новое представление этой уникальной анкеты.

Реализация вашего API как редактирования документов позволяет вам использовать PUT; PUT имеет идемпотентную семантику, что означает, что компоненты общего назначения могут автоматически помогать, когда ответы теряются в ненадежной сети.

      PUT /statements/123/answers/Bob
Content-Type: application/json

{
    "answers": {
        "uas1": true,
        "uas2": false,
        ...
        "uas39": true,
        "uas40": false
    }
}

Здесь у нас есть ресурс, относящийся к ответам Боба, и запрос описывает изменение этого ресурса.

Технически вы можете попросить всех редактировать один и тот же ресурс.

      PUT /statements/123/answers
...

Это не очень хорошо, но вы получаете много преимуществ. Каждый успешно отправленный запрос делает целевой ресурс недействительным, но вас это может не волновать.

Я бы не назвал этот подход REST-совместимым, но он, вероятно, считается REST-достаточно близким, чтобы вам все сойдет с рук.

Вы должны разработать свои конечные точки API (или «пути») таким образом, чтобы они были действительно описательными и специфичными для каждого сценария. поэтому с учетом этого одна из конечных точек может выглядеть примерно так:

/subject/:subject_id/answers

затем на вашем интерфейсе вы должны отправить запрос POST, например,

http://127.0.0.1/3000/subject/23/answers

с телом запроса, которое будет выглядеть так:

      {
    "answers": {
        "uas1": true,
        "uas2": false,
        ...
        "uas39": true,
        "uas40": false
    }
}

По сути, эта конечная точка будет отправлять все 40 логических ответов для субъекта с идентификатором 23 на ваш сервер Express.js.

Затем ваш сервер проанализирует запрос и получит ответы от вашего req.body, а затем сверит их с вашей базой данных MongoDB. Результат этой проверки может быть отправлен обратно в таком ответе:

      res.status(200).send(`For subject ${subject_name}, you scored ${correct_answers}/40`) 
Другие вопросы по тегам