Обработка запросов GET, POST, PUT и DELETE

ОБНОВЛЕНИЕ: К сожалению, мне пришлось сократить эту серию, потому что разработка Aqueduct была прекращена. Я рекомендую вам не использовать Акведук. Я верю, что появятся и другие серверные фреймворки Dart, но на данный момент явного победителя нет. А пока ознакомьтесь с моей серией статей о создании сервера Dart с нуля.

Это вторая часть из семи частей.

  1. "Начиная"
  2. HTTP-запросы (вы здесь)
  3. База данных
  4. Тестирование
  5. Аутентификация
  6. Производственный сервер
  7. Клиентское приложение Flutter

Вступление

На последнем уроке вы уже настроили Dart, Aqueduct и вашу IDE. Вы также сделали простой запрос GET от вашего браузера к работающему серверу Aqueduct, который вернул ответ браузеру.

В этом уроке вы узнаете еще несколько способов выполнения HTTP-запросов. В дополнение к запросам GET вы также будете выполнять запросы POST, PUT и DELETE. На стороне сервера вы напишете код для Aqueduct, который будет обрабатывать эти запросы.

Способы выполнения HTTP-запросов

Если вы предпочитаете смотреть видео, а не читать текст, то вот следующее видео:

Есть много разных способов сделать HTTP-запросы. Помимо браузера, вы можете использовать программу под названием Postman, утилиту командной строки curl, инструмент браузера под названием Swagger , среду тестирования Aqueduct или даже приложение Flutter.

Мы кратко рассмотрим каждый из них, но сначала откройте проект Aqueduct, который вы создали на последнем уроке. В файле lib / channel.dart замените метод entryPoint() следующим кодом:

@override
Controller get entryPoint {
  final router = Router();

  router.route("/example").linkFunction(
    (request) async {
      return Response.ok('Hello world')
        ..contentType = ContentType.text;
    },
  );

  return router;
}

Примечания:

  • Я изменил ответ, чтобы он возвращал Hello world в виде обычного текста, а не в формате JSON.
  • Путь для маршрута по-прежнему /example.

Теперь запустите сервер, выполнив следующую команду в терминале, когда вы находитесь в корне своего проекта Dart.

aqueduct serve

Браузер

Откройте любой браузер и перейдите по следующему адресу:

http://localhost:8888/

Aqueduct должен вернуть ответ 404 Not Found, потому что вы не обработали / корневой маршрут. Теперь перейдите по маршруту, который вы определили:

http://localhost:8888/example

Вы должны получить Hello world ответ.

Успех в браузере.

Почтальон

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

Скачайте Почтальон здесь. Если вы продолжаете нажимать на ссылку, вам не нужно ни для чего регистрироваться. После того, как вы его загрузили, установите его.

Введите следующее в адресной строке Postman и нажмите Отправить.

localhost:8888/example

Вы должны получить ответ от Aqueduct, показывающий Hello world в теле.

Обратите внимание, что статус - 200 OK. Все хорошо с сервера.

Успех с почтальоном.

завиток

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

Откройте терминал и выполните следующую команду, чтобы узнать, установлен ли у вас curl:

curl --version

Если он у вас не установлен, пропустите этот раздел. Мы не собираемся его так часто использовать. Но если вы хотите его установить, официальный сайт находится здесь.

Чтобы сделать запрос GET, выполните следующую команду:

curl -X GET "http://localhost:8888/example"

Вы должны получить Hello world ответ.

Успех на локон.

Чванство

Swagger, который теперь называется OpenAPI, позволяет вам протестировать серверное приложение, создав клиентское приложение в браузере. На самом деле я пока не нашел его настолько полезным, поэтому я не буду вдаваться в подробности о том, как его использовать сейчас.

Если вам интересно, то здесь - это официальная страница, а здесь - это документация по Акведуку.

Фреймворк для тестирования акведуков

Среда тестирования Aqueduct - хороший способ делать HTTP-запросы. В Части 4, посвященной тестированию, вы сделаете гораздо больше, но давайте сделаем небольшой предварительный просмотр прямо сейчас.

В своем проекте откройте файл test / example.dart.

Щелкните код правой кнопкой мыши, чтобы открыть контекстное меню. Выберите Выполнить или нажмите Control Shift R.

Тест не пройден, поскольку ожидается, что тело будет {“key”: “value”}. Но мы уже поменяли тело на Hello world. Тест необходимо обновить.

Замените весь файл следующим кодом:

import 'harness/app.dart';

Future main() async {
  final harness = Harness()..install();

  test("GET /example returns 200 {'key': 'value'}", () async {
    expectResponse(
      await harness.agent.get("/example"),
      200,
      body: "Hello world",
    );
  });
}

Запустите тест еще раз, и он должен пройти.

Выполнение запроса с помощью тестовой среды Aqueduct выполнено успешно.

Приложение Flutter

Я говорю «приложение Flutter», но это может быть приложение для Android или iOS. Вы можете использовать любой из этих вариантов для выполнения HTTP-запросов.

В части 7 мы будем создавать приложение Flutter, но если вы хотите сначала протестировать сервер, вы можете это сделать.

Вы делаете HTTP-запросы во Flutter, используя пакет http. Подробнее об этом вы можете прочитать в следующей статье:



Обработка запросов GET

Сервер уже обрабатывает GET-запросы к маршруту /example, но сейчас мы собираемся его расширить.

В этой серии статей вы собираетесь создать приложение-словарь, поэтому вместо /example вы собираетесь определять маршрут с путем /words.

В lib / channel.dart замените метод entryPoint() следующим:

@override
Controller get entryPoint {
  final router = Router();

  router.route("/words").link(() => WordsController());

  return router;
}

Обратите внимание на следующее:

  • Маршрут /words.
  • Вместо linkFunction мы используем link. Это перенаправляет все запросы, поступающие к /words, классу контроллера. Это сохраняет код нашего маршрутизатора чистым.
  • Вы еще не прошли WordsController() курс. Вы сделаете это дальше.

Создать контроллер

В папке lib создайте подпапку с названием controller.

Затем в lib / controller создайте файл с именем words_controller.dart. Вставьте следующий код:

import 'package:dart_server/dart_server.dart';

class WordsController extends ResourceController {

  final _words = [
    {'word': 'horse'},
    {'word': 'cow'},
    {'word': 'camel'},
    {'word': 'sheep'},
    {'word': 'goat'},
  ];

  @Operation.get()
  Future<Response> getAllWords() async {
    return Response.ok(_words);
  }
}

Примечания:

  • Этот класс расширяет ResourceController, который является классом Aqueduct, который заботится о многих деталях обработки запросов.
  • У нас еще не настроена база данных, поэтому для данных мы пока будем использовать массив объектов карты.
  • @Operation.get() - это аннотация, которая сообщает Aqueduct, что этот метод будет обрабатывать запросы GET. Он возвращает Response.ok(), который является ответом 200 OK, и мы передаем в него список данных. Aqueduct автоматически преобразует его в строку JSON и поместит в тело ответа.

В lib / channel.dart импортируйте только что созданный класс.

Протестируйте свой новый контроллер

Остановите сервер, нажав Control + C. Затем перезапустите сервер:

aqueduct serve

Откройте Postman и сделайте запрос, как мы делали раньше, но на этот раз измените адрес на следующий:

localhost:8888/words

Когда вы нажмете «Отправить», вы должны увидеть список JSON в теле ответа:

Получение одного предмета

В настоящее время сервер возвращает весь список данных. Что, если вы хотите получить только один элемент данных? Обычный способ сделать это - добавить идентификатор к пути следующим образом:

localhost:8888/words/1

Это запрос слова с id=1 от сервера, но мы еще не обрабатываем его.

Откройте lib / channel.dart. Замените метод entryPoint() следующим:

@override
Controller get entryPoint {
  final router = Router();

  router.route("/words/[:id]").link(() => WordsController());

  return router;
}

Примечания

  • Теперь к /words пути добавлен /[:id].
  • Двоеточие : означает, что id - это переменная. Вы можете называть переменную как хотите.
  • Квадратные скобки [ ] означают, что переменная не является обязательной.

Вернитесь в lib / controller / words_controller.dart. Вы собираетесь создать новый метод для обработки запросов на отдельные элементы. Вставьте следующий метод под методом getAllWords().

@Operation.get('id')
Future<Response> getWordByID(@Bind.path('id') int id) async {
  return Response.ok(_words[id]);
}

Примечания

  • Знак 'id' в аннотации служит для того, чтобы отличать этот метод от метода plain@Operation.get(), который мы создали ранее. Здесь 'id' - это то же имя, которое мы использовали для нашей переменной в channel.dart.
  • Часть @Bind означает, что Aqueduct возьмет переменную пути 'id' и попытается преобразовать ее как int. Если приведение не увенчалось успехом, Aqueduct вернет 404 Not Found. Но в случае успеха вы можете использовать целое число в качестве индекса для возврата элемента из списка данных.

Перезагрузите сервер:

aqueduct serve

В Postman отправьте запрос GET со следующим адресом:

localhost:8888/words/1

Вы должны получить ответ с одним элементом в теле:

Был возвращен элемент с индексом 1. Успех! Вы можете поиграть с запросом GET, отправив разные значения индекса. Если вы выберете большое значение, это вызовет ошибку сервера, и Aqueduct выдаст ответ 500.

Обработка запросов POST, PUT и DELETE

В этом разделе мы просто собираемся создать методы для обработки запросов POST, PUT и DELETE. Поскольку эти запросы предназначены для изменения данных на сервере, мы не закончим их до третьей части, когда добавим базу данных.

В lib / controller / words_controller.dart добавьте следующие методы к классу WordsController.

@Operation.post()
Future<Response> addWord() async {
  return Response.ok(null);
}

@Operation.put('id')
Future<Response> updateWord(@Bind.path('id') int id) async {
  return Response.ok(null);
}

@Operation.delete('id')
Future<Response> deleteWord(@Bind.path('id') int id) async {
  return Response.ok(null);
}

Примечания

  • Аннотация Operation определяет тип запроса, который обрабатывает метод. Запросы POST предназначены для создания ресурса сервера. Запросы PUT предназначены для обновления существующего ресурса. DELETE был назван правильно, поэтому требует пояснений.
  • Поскольку PUT и DELETE работают с существующими данными, мы привязываем идентификатор к целому числу, чтобы определить, какой элемент данных следует обновить или удалить.
  • На данный момент все возвращает ответ по умолчанию 200 OK. Мы изменим это позже.

Перезагрузите сервер с aqueduct serve.

Проверьте это в Postman

Откройте Почтальон. Вместо GET выберите POST в раскрывающемся меню.

В качестве URL-адреса запроса напишите следующее, а затем нажмите Отправить.

localhost:8888/words

Вы должны получить 200 OK ответ.

Повторите этот процесс для PUT и DELETE, используя URL-адрес с идентификатором:

localhost:8888/words/1

Результат все равно должен быть 200 OK.

Полный код

Если вы заблудились, вот полный код того, что мы сделали сегодня.

lib / channel.dart

библиотека / контроллер / words_controller.dart

Заключение

Теперь вы знаете основы обработки любого типа запроса. Конечно, позже будет еще что заполнить, но, как видите, это не так уж и сложно. В этом уроке путь маршрута был /words. Вы можете легко обрабатывать другие маршруты, просто определив какой-либо другой путь и назначив новый контроллер, который позаботится о нем.

В части 3 вы узнаете, как подключить базу данных PostgreSQL к серверу Aqueduct.

После того, как я закончу часть 3, я добавлю сюда ссылку. А пока не стесняйтесь продолжать смотреть видеоряд или следовать документации по акведуку.