Урок: как да напишете CRUD API с Vapor 2

В края на този урок ще имате API със Създаване, четене, актуализиране и изтриване (CRUD) на потребител, който говори JSON с вас!

Можете да намерите резултата от този урок на github: тук.

1. Създаване на нов проект за пари

Забележка: За да направите този урок, трябва да имате инсталиран бърз 3, набор от инструменти за пара и postgresql.

Ще клонираме api-шаблона, който осигурява пара:

пара нов тест-пример

Влезте вътре в своята директория, генерирайте нов Xcode проект и го отворете:

cd тест-пример /
пара xcode -y

Трябва да имате структура на проекта като тази:

тест-пример /
├── Package.swift
├── Източници /
│ ├── Приложение /
│ │ ├── Config + Setup.swift
│ │ ├── Droplet + Setup.swift
│ │ ├── Routes.swift
│ │ ├── Контролери /
│ │ │ └── PostController.swift
│ │ └── Модели /
│ │ └── Post.swift
│ └── Изпълнение /
├── Тестове /
├── Конфигуриране /
├── Обществен /
├── Зависимости /
└── Продукти /

2. Изтрийте (преместете в кошчето) файлове и код

Обичам да започвам от нулата, така че да знаем точно кои файлове и реализации са необходими за какво

тест-пример /
├── Package.swift
├── Източници /
│ ├── Приложение /
│ │ ├── Config + Setup.swift
│ │ ├── Droplet + Setup.swift
│ │ ├── Routes.swift
│ │ ├── Контролери / <- DELETE
│ │ │ └── PostController.swift <- DELETE
│ │ └── Модели /
│ │ └── Post.swift <- DELETE
│ └── Изпълнение /
├── Тестове /
├── Конфигуриране /
├── Обществен /
├── Зависимости /
└── Продукти /

Вътрешни източници / App / Config + Setup.swift изтрийте следния ред:

импортиране на FluentProvider
разширение Config {
  публични функции за настройка () хвърля {
    // позволяват размити преобразувания за тези типове
    // (добавете свои собствени типове тук)
    Node.fuzzy = [Row.self, JSON.self, Node.self]
    опитайте setupProviders ()
    опитайте setupPreparations ()
  }
  /// Конфигурирайте доставчиците
  private func setupProviders () хвърля {
    опитайте addProvider (FluentProvider.Provider.self)
  }
  /// Добавете всички модели, които трябва да имат своите
  /// схеми, подготвени преди стартирането на приложението
  private func setupPreparations () хвърля {
    препарати.прилагам (публикувам себе си) <- ДЕЛЕТЕ
  }
}

Вътрешни източници / App / Routes.swift изтрийте всичко, така че да изглежда така:

внос пари
разширение капчица {
  func setupRoutes () хвърля {
  }
}

3. Добавете зависимости

В Package.swift добавете следната зависимост (postgresql):

импортиране на PackageDescription
нека пакет = пакет (
  име: "тестов пример",
  цели: [
    Цел (име: „Приложение“),
    Цел (име: „Изпълнение“, зависимости: [„Приложение“]),
  ],
  зависимости: [
    .Package (url: „https://github.com/vapor/vapor.git“, majorVersion: 2),
    .Package (url: „https://github.com/vapor/fluent-provider.git“, majorVersion: 1), <- НЕ ЗАБРАВАЙТЕ ТОВА КОММА;)
    .Package (url: „https://github.com/vapor/postgresql-provider.git“, majorVersion: 2)
  ],
  изключете: [
    "Config",
    "База данни",
    "Локализация",
    "Обществено",
    "ресурси",
  ]
)

Сега донесете новата зависимост във вашия терминал, който е във вашия тестов пример / директория, пресъздайте вашия Xcode проект и го отворете отново:

извличане на пари
пара xcode -y

В Sources / App / Config + Setup.swift добавете PostgreSQLProvider:

импортиране на FluentProvider
импортиране на PostgreSQLProvider <- ADD
разширение Config {
  публични функции за настройка () хвърля {
    // позволяват размити преобразувания за тези типове
    // (добавете свои собствени типове тук)
    Node.fuzzy = [Row.self, JSON.self, Node.self]
    опитайте setupProviders ()
    опитайте setupPreparations ()
  }
  /// Конфигурирайте доставчиците
  private func setupProviders () хвърля {
    опитайте addProvider (FluentProvider.Provider.self)
    опитайте addProvider (PostgreSQLProvider.Provider.self) <- ADD
  }
  /// Добавете всички модели, които трябва да имат своите
  /// схеми, подготвени преди стартирането на приложението
  private func setupPreparations () хвърля {
  }
}
Нека проверим дали всичко е наред дотук, проверете дали сте избрали My Mac и натиснете стартиране ► и вижте дали 127.0.0.1:8080 в браузъра ви връща празна страница

4. Конфигурирайте и създайте база данни

Вътре конфигурирайте / създайте нова папка, наречена тайни, а в директорията тайни / създайте файл, наречен postgresql.json:

тест-пример /
├── Package.swift
├── Източници /
├── Тестове /
├── Конфигуриране /
│ ├── app.json
│ ├── crypto.json
│ ├── kapplet.json
│ ├── fluent.json
│ ├── тайни / <- СЪЗДАВАНЕ
│ │ └── postgresql.json <- СЪЗДАВАНЕ
│ └── server.json
├── Обществен /
├── Зависимости /
└── Продукти /

Вътре в postgresql.json пише:

{
  "име на хост": "127.0.0.1",
  "порт": 5432,
  "потребител": "martinlasek",
  "парола": "",
  "база данни": "testexample"
}
Забележка: ще трябва да замените потребителя martinlasek с вашето потребителско име

Вътре Config / fluent.json задайте postgresql като вашия драйвер

{
  "//": "Основната технология на базата данни, която да се използва.",
  "//": "памет: БД в паметта на SQLite.",
  "//": "sqlite: Персистирана SQLite DB (конфигуриране с sqlite.json)",
  "//": "Други драйвери са достъпни чрез доставчици на пари",
  "//": "https://github.com/search?q=topic:vapor-provider+topic:database",
  "driver": "postgresql", <- промяна от паметта на postgresql
  ...
}

Създайте testexample на базата данни, като въведете в терминала си следното:

създаден testexample;

5. Създайте потребителски модел

Вътрешни източници / Приложение / Модели / създайте файл, наречен User.swift, регенерирайте и отворете вашия Xcode проект:

докоснете Източници / Приложение / Модели / User.swift
пара xcode -y
Тъй като във вашия модел / директория няма .swift-файл, Xcode няма да покаже тази директория. За това не можете да създадете файл в Модели / чрез Xcode

Вътрешни източници / Приложение / Модели / User.swift поставете следния код:

внос пари
импортиране на FluentProvider
импортиране на HTTP
Последен клас Потребител: Модел {
  нека съхранение = съхранение ()
  var потребителско име: String
  var age: Int
  init (потребителско име: Низ, възраст: Int) {
    self.username = потребителско име
    self.age = възраст
  }
  // инициира потребителя с данни от база данни
  init (ред: Ред) хвърля {
    потребителско име = опитайте row.get ("потребителско име")
    age = опитайте row.get ("age")
  }
  func makeRow () хвърля -> Ред {
    var row = Ред ()
    опитайте row.set ("потребителско име", потребителско име)
    пробвайте row.set ("възраст", възраст)
    връщане ред
  }
}
/// МАРК: Течна подготовка
разширение Потребител: Подготовка {
  // подготвя таблица в базата данни
  static func pripra (_ база данни: база данни) хвърля {
    опитайте database.create (self) {builder in
      builder.id ()
      builder.string ( "име")
      builder.int ( "възраст")
    }
  }
  // изтрива таблицата от базата данни
  static func revert (_ база данни: база данни) хвърля {
    опитайте database.delete (самостоятелно)
  }
}
/// МАРКА: JSON
разширение Потребител: JSONConvertible {
  // да ви позволи да инициирате потребител с json
  удобство init (json: JSON) хвърля {
    self.init (
      потребителско име: опитайте json.get („потребителско име“),
      възраст: опитайте json.get ("age")
    )
  }
  // създаване на json от потребителска инстанция
  func makeJSON () хвърля -> JSON {
    var json = JSON ()
    опитайте json.set (User.idKey, id)
    опитайте json.set ("потребителско име", потребителско име)
    опитайте json.set ("възраст", възраст)
    върнете json
  }
}

Уведомете приложението си за вашия модел, като го добавите в Sources / App / Config + Setup.swift

импортиране на FluentProvider
импортиране на PostgreSQLProvider
разширение Config {
  публични функции за настройка () хвърля {
    // позволяват размити преобразувания за тези типове
    // (добавете свои собствени типове тук)
    Node.fuzzy = [Row.self, JSON.self, Node.self]
    опитайте setupProviders ()
    опитайте setupPreparations ()
  }
  /// Конфигурирайте доставчиците
  private func setupProviders () хвърля {
    опитайте addProvider (FluentProvider.Provider.self)
    опитайте addProvider (PostgreSQLProvider.Provider.self)
  }
  /// Добавете всички модели, които трябва да имат своите
  /// схеми, подготвени преди стартирането на приложението
  private func setupPreparations () хвърля {
    препарати.прилагам (самия потребител) <- ДОБАВИ
  }
}

Сега отново да стартираме ► проекта, той ще подготви вашата база данни и ще създаде потребителска таблица. Вашата конзола Xcode ще ви покаже нещо като:

Настоящият ключ за хеш „0000000000000000“ не е защитен.
Актуализирайте hash.key в Config / crypto.json, преди да използвате в производството.
Използвайте `openssl rand -base64 `, за да генерирате произволен низ.
Сегашната шифър ключ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA =" не е сигурно.
Актуализирайте cipher.key в Config / crypto.json, преди да използвате в производството.
Използвайте `openssl rand -base64 32`, за да генерирате произволен низ.
Подготвена база данни <- това търсим
Не е предоставена команда, по подразбиране за обслужване ...
Стартиращ сървър на 0.0.0.0:8080
Ако Xcode не ви позволява да стартирате проекта си, просто изпълнете vapor xcode -y във вашия терминал и опитайте да стартирате отново

6. Изпълнение: Създаване

Във вашия Sources / App / Routes.swift внедрете нов маршрут, който ще очаква JSON-заявка, инициира потребител от него и го запази в базата данни:

внос пари
разширение капчица {
  func setupRoutes () хвърля {
    /// СЪЗДАВАНЕ на потребител
    /// http метод: публикация
    post ("потребител") {req в
      // заявката за проверка съдържа json
      пази нека json = req.json else {
        хвърли Abort (.badRequest, причина: "не е предоставен json")
      }
      нека потребител: Потребител
      // опитайте да инициализирате потребителя с json
      направете {
        потребител = опитайте потребител (json: json)
      }
      улов {
        хвърлете Abort (.badRequest, причина: "неправилно json")
      }
      // запазване на потребителя
      опитайте user.save ()
      // върнете потребител
      върнете опитайте user.makeJSON ()
    }
  }
}

Ако сега стартирате ► вашето приложение и POST до 127.0.0.1:8080/user с валиден JSON:

{
  "потребителско име": "Том Круз",
  "възраст": 23
}

тя ще създаде потребител, ще го запише в базата данни и ще ви върне създадения потребител във формат JSON обратно. Можете да използвате Пощальон или ако говорите нелепо просто използвайте терминалното си писане:

curl -H "Content-Type: application / json" -X POST -d '{"username": "Tom Cruise", "age": 23}' http://127.0.0.1:8080/user

Така или иначе ще получите отговор изглеждащ така:

{"id": 1, "age": 23, "username": "Tom Cruise"}

7. Изпълнение: Прочетете

Във вашия Sources / App / Routes.swift внедрете нов маршрут, който ще очаква идентификатор и ще ви върне потребителя с този идентификатор във формат JSON:

внос пари
разширение капчица {
  func setupRoutes () хвърля {
    /// СЪЗДАВАНЕ на потребител
    /// http метод: публикация
    post ("потребител") {req в
      ...
    }
    /// ПРОЧЕТЕТЕ потребителя по зададен номер
    /// http метод: get
    get ("потребител", Int.parameter) {req в
      // Вземете идентификатор от URL адреса
      нека userId = опитайте req.parameters.next (Int.self)
      // намери потребител с даден идентификационен номер
      охрана нека потребител = опитайте User.find (userId) else {
        хвърли Abort (.badRequest, причина: "потребител с id \ (userId) не съществува")
      }
      // върнете потребителя като json
      върнете опитайте user.makeJSON ()
    }
  }
}

Ако сега стартирате ► приложението си, тъй като това е GET маршрут, можете да задействате 127.0.0.1:8080/user/1 или в браузъра си, или ако говорите нелепо - просто използвайте въвеждането на терминала:

къдря http://127.0.0.1:8080/user/1

трябва да ви върне JSON на потребителя, като идентификаторът, използван в URL адреса, изглежда като:

{
  "id": 1,
  "възраст": 23,
  "потребителско име": "Том Круз"
}

8. Изпълнение: Актуализация

Във вашия Sources / App / Routes.swift внедрете нов маршрут, който ще очаква JSON-Заявка с идентификатор за потребителя да актуализира и да ви върне актуализирания потребител във формат JSON:

внос пари
разширение капчица {
  func setupRoutes () хвърля {
    /// СЪЗДАВАНЕ на потребител
    /// http метод: публикация
    post ("потребител") {req в
      ...
    }
    /// ПРОЧЕТЕТЕ потребителя по зададен номер
    /// http метод: get
    get ("потребител", Int.parameter) {req в
      ...
    }
    
    /// Актуализиране на потребителя напълно
    /// http метод: пут
    put ("потребител", Int.parameter) {req в
      // Вземете userId от URL
      нека userId = опитайте req.parameters.next (Int.self)
      // намери потребител по зададен идентификатор
      охрана нека потребител = опитайте User.find (userId) else {
        хвърли Abort (.badRequest, причина: "потребител с зададен идентификатор: \ (userId) не може да бъде намерен")
      }
      // проверете потребителското име е предоставено от json
      пази нека потребителско име = req.data ["потребителско име"] ?. string else {
        хвърли Abort (.badRequest, причина: "не е въведено потребителско име")
      }
      // възрастта за проверка се предоставя от json
      пази оставете age = req.data ["age"] ?. int else {
        хвърлете Abort (.badRequest, причина: "не е въведена възраст")
      }
      // задайте нови стойности на намерения потребител
      user.username = потребителско име
      user.age = възраст
      // запишете потребителя с нови стойности
      опитайте user.save ()
      // върнете потребителя като json
      върнете опитайте user.makeJSON ()
    }
  }
}

Ако сега стартирате ► вашето приложение и PUT до 127.0.0.1:8080/user/1 с валиден JSON:

{
  "потребителско име": "Връзка",
  "възраст": 41
}

той ще търси потребителя с зададен идентификатор в URL адреса, ще актуализира неговите свойства, ще го запише обратно в базата данни и също ще го върне обратно в JSON формат. Можете да използвате Пощальон или ако говорите нелепо просто използвайте терминалното си писане:

curl -H "Content-Type: application / json" -X PUT -d '{"потребителско име": "Yamato", "age": 41}' http://127.0.0.1:8080/user/1

трябва да ви върне JSON на актуализирания потребител, изглеждащ като:

{
  "id": 1,
  "потребителско име": "Ямато"
  "възраст": 41,
}

9. Изпълнение: Изтриване

Във вашия Sources / App / Routes.swift внедрете нов маршрут, който ще очаква идентификатор и ще ви върне съобщението JSON с успех

внос пари
разширение капчица {
  func setupRoutes () хвърля {
    /// СЪЗДАВАНЕ на потребител
    /// http метод: публикация
    post ("потребител") {req в
      ...
    }
    /// ПРОЧЕТЕТЕ потребителя по зададен номер
    /// http метод: get
    get ("потребител", Int.parameter) {req в
      ...
    }
    
    /// Актуализиране на потребителя напълно
    /// http метод: пут
    put ("потребител", Int.parameter) {req в
      ...
    }
    /// ИЗТРИВАНЕ потребител от ид
    /// http метод: изтриване
    delete („потребител“, Int.parameter) {req in
      // извличане на потребителски идентификатор от URL
      нека userId = опитайте req.parameters.next (Int.self)
      // намери потребител с даден идентификационен номер
      охрана нека потребител = опитайте User.find (userId) else {
        хвърли Abort (.badRequest, причина: "потребител с id \ (userId) не съществува")
      }
      // изтриване на потребител
      опитайте user.delete ()
      върнете опита JSON (node: ["type": "success", "message": "user with id \ (userId) успешно бяха изтрити"])
    }
  }
}

Ако сега стартирате ► вашето приложение и DELETE до 127.0.0.1:8080/user/1, то ще потърси потребителя с зададен идентификатор в URL адреса, изтрийте го и върнете JSON със съобщение за успех, включително потребителския идентификатор. Можете да използвате Пощальон или ако говорите нелепо просто използвайте терминалното си писане:

къдря -X DELETE http://127.0.0.1:8080/user/1

Трябва да ви върне JSON, изглеждащ като:

{
  "type": "успех",
  "message": "потребителят с идентификатор 1 е изтрит успешно"
}

Поздравления! Успешно внедрихте API с CRUD на потребител !!

Къде да отида от тук? Научете как да тествате маршрутите си тук!

Благодаря ви много за четенето! Ако имате някакви предложения или подобрения, уведомете ме! Бих се радвал да чуя от вас!

Twitter / Github / Instagram