Tutorial: Wie schreibe ich eine CRUD API mit Vapor 2?

Am Ende dieses Tutorials haben Sie eine API mit CRUD (Create, Read, Update and Delete) für einen Benutzer, der mit Ihnen über JSON spricht!

Das Ergebnis dieses Tutorials finden Sie auf github: hier.

1. Ein neues Vapour-Projekt erstellen

Hinweis: Um dieses Tutorial zu machen, müssen Sie swift 3, vapor-toolbox und postgresql installiert haben.

Wir werden das API-Template klonen, das Vapour bereitstellt:

dampf neues testbeispiel

Gehen Sie in Ihr Verzeichnis, generieren Sie ein neues Xcode-Projekt und öffnen Sie es:

CD Test-Beispiel /
dampf xcode -y

Sie sollten eine Projektstruktur wie diese haben:

Testbeispiel /
├── Package.swift
├── Quellen /
│ ├── App /
│ │ ├── Config + Setup.swift
│ │ │ Droplet + Setup.swift
│ │ ├── Routes.swift
│ │ ├── Steuerungen /
│ │ │ │ PostController.swift
│ │ └── Modelle /
│ │ └── Post.swift
│ └── Run /
├── Tests /
├── Konfig /
├── Öffentlich /
├── Abhängigkeiten /
└── Produkte /

2. Dateien und Code löschen (in den Papierkorb verschieben)

Ich fange gerne bei Null an, damit wir genau wissen, welche Dateien und Implementierungen für was benötigt werden

Testbeispiel /
├── Package.swift
├── Quellen /
│ ├── App /
│ │ ├── Config + Setup.swift
│ │ │ Droplet + Setup.swift
│ │ ├── Routes.swift
│ │ ├── Controller / <- LÖSCHEN
│ │ │ │ PostController.swift <- LÖSCHEN
│ │ └── Modelle /
│ │ └── Post.swift <- LÖSCHEN
│ └── Run /
├── Tests /
├── Konfig /
├── Öffentlich /
├── Abhängigkeiten /
└── Produkte /

Löschen Sie in Sources / App / Config + Setup.swift die folgende Zeile:

FluentProvider importieren
Erweiterung Config {
  public func setup () wirft {
    // Fuzzy-Konvertierungen für diese Typen zulassen
    // (fügen Sie hier Ihre eigenen Typen hinzu)
    Node.fuzzy = [Row.self, JSON.self, Node.self]
    versuche setupProviders ()
    versuche setupPreparations ()
  }
  /// Provider konfigurieren
  private func setupProviders () wirft {
    Versuchen Sie addProvider (FluentProvider.Provider.self)
  }
  /// Füge alle Modelle hinzu, die ihre haben sollen
  /// vorbereitete Schemata, bevor die App startet
  private func setupPreparations () wirft {
    prepare.append (Post.self) <- LÖSCHEN
  }
}

Löschen Sie in Sources / App / Routes.swift alles so, dass es so aussieht:

Vapor importieren
Erweiterung Droplet {
  func setupRoutes () wirft {
  }
}

3. Fügen Sie Abhängigkeiten hinzu

Fügen Sie in Package.swift die folgende Abhängigkeit hinzu (postgresql):

PackageDescription importieren
let package = Package (
  Name: "Test-Beispiel",
  Ziele: [
    Ziel (Name: "App"),
    Ziel (Name: "Ausführen", Abhängigkeiten: ["App"]),
  ],
  Abhängigkeiten:
    .Package (URL: "https://github.com/vapor/vapor.git", majorVersion: 2),
    .Package (URL: "https://github.com/vapor/fluent-provider.git", majorVersion: 1), <- VERGESSEN SIE DIESES KOMMA NICHT;)
    .Paket (URL: "https://github.com/vapor/postgresql-provider.git", majorVersion: 2)
  ],
  ausschließen: [
    "Config",
    "Datenbank",
    "Lokalisierung",
    "Öffentlichkeit",
    "Ressourcen",
  ]
)

Holen Sie sich jetzt die neue Abhängigkeit in Ihrem Terminal, die sich in Ihrem Testbeispiel / -verzeichnis befindet, erstellen Sie Ihr Xcode-Projekt neu und öffnen Sie es erneut:

Dampf holen
dampf xcode -y

Fügen Sie in Sources / App / Config + Setup.swift den PostgreSQLProvider hinzu:

FluentProvider importieren
PostgreSQLProvider importieren <- HINZUFÜGEN
Erweiterung Config {
  public func setup () wirft {
    // Fuzzy-Konvertierungen für diese Typen zulassen
    // (fügen Sie hier Ihre eigenen Typen hinzu)
    Node.fuzzy = [Row.self, JSON.self, Node.self]
    versuche setupProviders ()
    versuche setupPreparations ()
  }
  /// Provider konfigurieren
  private func setupProviders () wirft {
    Versuchen Sie addProvider (FluentProvider.Provider.self)
    Versuchen Sie addProvider (PostgreSQLProvider.Provider.self) <- ADD
  }
  /// Füge alle Modelle hinzu, die ihre haben sollen
  /// vorbereitete Schemata, bevor die App startet
  private func setupPreparations () wirft {
  }
}
Überprüfen wir, ob bis jetzt alles in Ordnung war, stellen Sie sicher, dass Sie "Mein Mac" ausgewählt und auf "Ausführen" ► geklickt haben, und prüfen Sie, ob 127.0.0.1:8080 in Ihrem Browser eine leere Seite zurückgibt

4. Konfigurieren und erstellen Sie die Datenbank

Erstellen Sie in Config einen neuen Ordner mit dem Namen "Secrets" und erstellen Sie im Verzeichnis "Secrets" eine Datei mit dem Namen "postgresql.json":

Testbeispiel /
├── Package.swift
├── Quellen /
├── Tests /
├── Konfig /
│ ├── app.json
│ │ crypto.json
│ │ droplet.json
│ ├── fließend.json
│ ├── Geheimnisse / <- ERSTELLEN
│ │ └── postgresql.json <- ERSTELLEN
│ └── server.json
├── Öffentlich /
├── Abhängigkeiten /
└── Produkte /

Inside postgresql.json schreibt:

{
  "Hostname": "127.0.0.1",
  "port": 5432,
  "user": "martinlasek",
  "Passwort": "",
  "database": "testexample"
}
Hinweis: Sie müssen den Benutzer martinlasek durch Ihren Benutzernamen ersetzen

In Config / fluent.json legen Sie postgresql als Ihren Treiber fest

{
  "//": "Die zugrunde liegende zu verwendende Datenbanktechnologie.",
  "//": "Speicher: SQLite-In-Memory-DB.",
  "//": "sqlite: Persisted SQLite DB (mit sqlite.json konfigurieren)",
  "//": "Andere Treiber sind über Vapor-Anbieter erhältlich",
  "//": "https://github.com/search?q=topic:vapor-provider+topic:database",
  "driver": "postgresql", <- wechselt vom Speicher zum Postgresql
  ...
}

Erstellen Sie das Datenbanktestbeispiel, indem Sie Folgendes in Ihr Terminal eingeben:

createdb testexample;

5. Erstellen Sie ein Benutzermodell

Erstellen Sie in Sources / App / Models / eine Datei mit dem Namen User.swift, generieren Sie Ihr Xcode-Projekt und öffnen Sie es:

Berühren Sie Sources / App / Models / User.swift
dampf xcode -y
Da sich in Ihrem Models / -Verzeichnis keine .swift-Datei befindet, wird dieses Verzeichnis von Xcode nicht angezeigt. Daher können Sie in Models / über Xcode keine Datei erstellen

Fügen Sie in Sources / App / Models / User.swift den folgenden Code ein:

Vapor importieren
FluentProvider importieren
HTTP importieren
Abschlussklasse Benutzer: Model {
  let storage = Storage ()
  var Benutzername: String
  Var Alter: Int
  init (Benutzername: String, Alter: Int) {
    self.username = Benutzername
    self.age = alter
  }
  // Benutzer mit Datenbankdaten initiieren
  init (row: Row) wirft {
    username = try row.get ("Benutzername")
    age = try row.get ("age")
  }
  func makeRow () wirft -> Row {
    var row = Row ()
    Versuchen Sie row.set ("Benutzername", Benutzername)
    versuche row.set ("age", age)
    Zeile zurück
  }
}
/// MARK: Fließende Vorbereitung
Erweiterung Benutzer: Vorbereitung {
  // bereitet eine Tabelle in der Datenbank vor
  static func prepare (_ database: Database) wirft {
    versuchen Sie database.create (self) {builder in
      builder.id ()
      builder.string ("Benutzername")
      builder.int ("alter")
    }
  }
  // löscht die Tabelle aus der Datenbank
  static func revert (_ database: Database) wirft {
    versuche database.delete (self)
  }
}
/// MARK: JSON
Erweiterung Benutzer: JSONConvertible {
  // Sie können Benutzer mit json initiieren
  Convenience Init (JSON: JSON) wirft {
    self.init (
      Benutzername: versuchen Sie es mit json.get ("Benutzername"),
      age: probiere json.get ("age")
    )
  }
  // JSON aus Benutzerinstanz erstellen
  func makeJSON () wirft -> JSON {
    var json = JSON ()
    versuchen Sie es mit json.set (User.idKey, id)
    versuche json.set ("Benutzername", Benutzername)
    versuche json.set ("age", age)
    Json zurück
  }
}

Informieren Sie Ihre Anwendung über Ihr Modell, indem Sie es in Sources / App / Config + Setup.swift hinzufügen

FluentProvider importieren
PostgreSQLProvider importieren
Erweiterung Config {
  public func setup () wirft {
    // Fuzzy-Konvertierungen für diese Typen zulassen
    // (fügen Sie hier Ihre eigenen Typen hinzu)
    Node.fuzzy = [Row.self, JSON.self, Node.self]
    versuche setupProviders ()
    versuche setupPreparations ()
  }
  /// Provider konfigurieren
  private func setupProviders () wirft {
    Versuchen Sie addProvider (FluentProvider.Provider.self)
    versuche addProvider (PostgreSQLProvider.Provider.self)
  }
  /// Füge alle Modelle hinzu, die ihre haben sollen
  /// vorbereitete Schemata, bevor die App startet
  private func setupPreparations () wirft {
    prepare.append (User.self) <- HINZUFÜGEN
  }
}

Lassen Sie uns nun das ► Projekt erneut ausführen. Es bereitet Ihre Datenbank vor und erstellt eine Benutzertabelle. Ihre Xcode-Konsole zeigt Folgendes an:

Der aktuelle Hash-Schlüssel „0000000000000000“ ist nicht sicher.
Aktualisieren Sie die Datei hash.key in Config / crypto.json, bevor Sie sie in der Produktion verwenden.
Verwenden Sie "openssl rand -base64 ", um eine zufällige Zeichenfolge zu generieren.
Der aktuelle Chiffrierschlüssel „AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA =“ ist nicht sicher.
Aktualisieren Sie die Datei cipher.key in Config / crypto.json, bevor Sie sie in der Produktion verwenden.
Verwenden Sie `openssl rand -base64 32`, um eine zufällige Zeichenfolge zu generieren.
Datenbank vorbereitet <- das ist es, wonach wir suchen
Kein Befehl angegeben, standardmäßig zu dienen ...
Server wird auf 0.0.0.0:8080 gestartet
Wenn Sie mit Xcode Ihr Projekt nicht ausführen können, führen Sie einfach vapor xcode -y in Ihrem Terminal aus und versuchen Sie es erneut

6. Implementieren: Erstellen

Implementieren Sie in Sources / App / Routes.swift eine neue Route, die eine JSON-Anfrage erwartet, initiieren Sie einen Benutzer daraus und speichern Sie ihn in der Datenbank:

Vapor importieren
Erweiterung Droplet {
  func setupRoutes () wirft {
    /// CREATE user
    /// http method: post
    post ("user") {req in
      // check request constains json
      Wache lass json = req.json else {
        Abort werfen (.badRequest, Grund: "no json provided")
      }
      let user: Benutzer
      // versuche den Benutzer mit json zu initialisieren
      tun {
        user = try User (json: json)
      }
      Fang {
        Abort werfen (.badRequest, Grund: "wrong json")
      }
      // Benutzer speichern
      versuche user.save ()
      // Benutzer zurückgeben
      zurück try user.makeJSON ()
    }
  }
}

Wenn Sie jetzt ► Ihre App und den POST auf 127.0.0.1:8080/user mit einem gültigen JSON ausführen:

{
  "Benutzername": "Tom Cruise",
  "Alter": 23
}

Es erstellt einen Benutzer, speichert ihn in der Datenbank und gibt den erstellten Benutzer im JSON-Format an Sie zurück. Du kannst Postman benutzen oder wenn du nerdy sprichst, benutze einfach deine Terminal-Eingabe:

curl -H "Inhaltstyp: application / json" -X POST -d '{"Benutzername": "Tom Cruise", "Alter": 23}' http://127.0.0.1:8080/user

In beiden Fällen erhalten Sie eine Antwort, die wie folgt aussieht:

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

7. Implementieren: Lesen

Implementieren Sie in Sources / App / Routes.swift eine neue Route, die eine ID erwartet und Ihnen den Benutzer mit dieser ID im JSON-Format zurückgibt:

Vapor importieren
Erweiterung Droplet {
  func setupRoutes () wirft {
    /// CREATE user
    /// http method: post
    post ("user") {req in
      ...
    }
    /// READ user mit angegebener id
    /// http Methode: get
    get ("user", Int.parameter) {req in
      // ID von URL erhalten
      let userId = try req.parameters.next (Int.self)
      // Benutzer mit angegebener ID finden
      guard let user = versuche User.find (userId) else {
        Abbruch auslösen (.badRequest, Grund: "Benutzer mit der ID \ (userId) existiert nicht")
      }
      // Benutzer als json zurückgeben
      zurück try user.makeJSON ()
    }
  }
}

Wenn Sie jetzt ► Ihre App ausführen, da es sich um eine GET-Route handelt, können Sie 127.0.0.1:8080/user/1 entweder in Ihrem Browser starten oder wenn Sie nerdy sprechen.

curl http://127.0.0.1:8080/user/1

Es sollte eine JSON des Benutzers mit der in der URL verwendeten ID zurückgeben, die wie folgt aussieht:

{
  "id": 1,
  "Alter": 23,
  "Benutzername": "Tom Cruise"
}

8. Implementieren: Aktualisieren

Implementieren Sie in Sources / App / Routes.swift eine neue Route, die eine JSON-Anfrage mit einer ID erwartet, mit der der Benutzer den aktualisierten Benutzer im JSON-Format aktualisieren und zurückgeben kann:

Vapor importieren
Erweiterung Droplet {
  func setupRoutes () wirft {
    /// CREATE user
    /// http method: post
    post ("user") {req in
      ...
    }
    /// READ user mit angegebener id
    /// http Methode: get
    get ("user", Int.parameter) {req in
      ...
    }
    
    /// UPDATE User voll
    /// http Methode: put
    put ("user", Int.parameter) {req in
      // Benutzer-ID von URL abrufen
      let userId = try req.parameters.next (Int.self)
      // Benutzer anhand der angegebenen ID finden
      guard let user = versuche User.find (userId) else {
        throw Abort (.badRequest, Grund: "Benutzer mit angegebener ID: \ (userId) konnte nicht gefunden werden")
      }
      // Benutzername prüfen wird von json bereitgestellt
      Wache let username = req.data ["Benutzername"] ?. string else {
        Abbruch werfen (.badRequest, Grund: "kein Benutzername angegeben")
      }
      // Alter prüfen wird von json bereitgestellt
      Wache let age = req.data ["age"] ?. int else {
        Abbruch werfen (.badRequest, Grund: "kein Alter angegeben")
      }
      // Neue Werte setzen, um Benutzer zu finden
      user.username = Benutzername
      user.age = alter
      // Benutzer mit neuen Werten speichern
      versuche user.save ()
      // Benutzer als json zurückgeben
      zurück try user.makeJSON ()
    }
  }
}

Wenn Sie jetzt ► Ihre App ausführen und PUT auf 127.0.0.1:8080/user/1 mit einem gültigen JSON ausführen:

{
  "Benutzername": "Link",
  "Alter": 41
}

Es sucht nach dem Benutzer mit der angegebenen ID in der URL, aktualisiert seine Eigenschaften, speichert ihn zurück in die Datenbank und sendet ihn im JSON-Format an Sie zurück. Du kannst Postman benutzen oder wenn du nerdy sprichst, benutze einfach deine Terminal-Eingabe:

curl -H "Inhaltstyp: application / json" -X PUT -d '{"Benutzername": "Yamato", "Alter": 41}' http://127.0.0.1:8080/user/1

Es sollte eine JSON des aktualisierten Benutzers zurückgeben, die wie folgt aussieht:

{
  "id": 1,
  "Benutzername": "Yamato"
  "Alter": 41,
}

9. Implementieren: Löschen

Implementieren Sie in Sources / App / Routes.swift eine neue Route, die eine ID erwartet und Ihnen eine JSON-Nachricht mit Erfolg zurückgibt

Vapor importieren
Erweiterung Droplet {
  func setupRoutes () wirft {
    /// CREATE user
    /// http method: post
    post ("user") {req in
      ...
    }
    /// READ user mit angegebener id
    /// http Methode: get
    get ("user", Int.parameter) {req in
      ...
    }
    
    /// UPDATE User voll
    /// http Methode: put
    put ("user", Int.parameter) {req in
      ...
    }
    /// DELETE user by id
    /// http Methode: löschen
    delete ("user", Int.parameter) {req in
      // Benutzer-ID von URL abrufen
      let userId = try req.parameters.next (Int.self)
      // Benutzer mit angegebener ID finden
      guard let user = versuche User.find (userId) else {
        Abbruch auslösen (.badRequest, Grund: "Benutzer mit der ID \ (userId) existiert nicht")
      }
      // Benutzer löschen
      versuche user.delete ()
      Rückgabeversuch JSON (Knoten: ["Typ": "Erfolg", "Nachricht": "Benutzer mit der ID \ (Benutzer-ID) wurde erfolgreich gelöscht"])
    }
  }
}

Wenn Sie jetzt ► Ihre App ausführen und auf 127.0.0.1:8080/user/1 LÖSCHEN, wird nach dem Benutzer mit der angegebenen ID in der URL gesucht, dieser gelöscht und eine JSON mit einer Erfolgsmeldung einschließlich der Benutzer-ID zurückgegeben. Du kannst Postman benutzen oder wenn du nerdy sprichst, benutze einfach deine Terminal-Eingabe:

curl -X DELETE http://127.0.0.1:8080/user/1

Es sollte einen JSON zurückgeben, der so aussieht:

{
  "Typ": "Erfolg",
  "message": "Benutzer mit ID 1 wurde erfolgreich gelöscht"
}

Glückwunsch! Sie haben erfolgreich eine API mit CRUD auf einem Benutzer implementiert !!

Wohin soll es von hier aus gehen? Erfahren Sie hier, wie Sie Ihre Routen testen können!

Vielen Dank fürs Lesen! Wenn Sie Vorschläge oder Verbesserungen haben, lassen Sie es mich wissen! I würde es lieben von dir zu hören!

Twitter / Github / Instagram