magula
magula

Reputation: 151

Using FluentPostgreSQL in Swift 5.2, POST and GET are working but I have no idea where the data is being stored

1) I have the following in Package.swift:

    .package(url: 

"https://github.com/vapor/postgresql.git", from: "1.0.0")
 targets: [
        .target(name: "App", dependencies: ["FluentSQLite", "Vapor", "PostgreSQL"]),
... etc.

2) And I have PostgreSQL configured in configure.swift:

let postgreSQLConfig = PostgreSQLDatabaseConfig(
  hostname: "localhost",
  port: 5432,
  username: "postgres",
  database: "mydb2",
  password: "bigsecret"
)
let psql = PostgreSQLDatabase(config: postgreSQLConfig)
var databases = DatabasesConfig()
databases.add(database: psql, as: .psql)
services.register(databases)

3) And I have a table called article in PostgreSQL 11.3. 4) And I have the following in Article.swift:

    import Foundation
    import FluentPostgreSQL  
    import Vapor

    struct Article: PostgreSQLModel {
        var id: Int?

        var title: String
        var content: String
        init(id: Int? = nil, title: String, content: String) {
          self.title = title
          self.content = content
        }

    }

extension Article: Content {}
extension Article: Migration {}

5) routes.swift looks like:

let articleController = ArticleController()
router.get("articles", use: articleController.index)
router.post("articles", use: articleController.create)

6) Both the POST and GET are working (i.e. the GET returns everything I've POSTed) ,but I don't see the table in PostgreSQL, so I have no idea where the data is being stored:

import Vapor
import Foundation
    final class ArticleController {
        func index(_ req: Request) throws -> Future<[Article]> {
            return Article.query(on: req).all()
        }

        func create(_ req: Request) throws -> Future<Article> {
            return try req.content.decode(Article.self).flatMap { article in
                    print("10j")
                    return article.save(on: req)
            }
        }


    }

The request has Content-Type set to application/json and the request body looks like:

{"id":1,"title":"GGG","content":"HHH"}

Upvotes: 0

Views: 219

Answers (5)

magula
magula

Reputation: 151

Mystery solved. You need to quote the table name because of the capital A: mydb4=# select * from "Article";

Upvotes: 1

magula
magula

Reputation: 151

Also the POST request body (I'm using Rested on the macbook) should not have a PK (PostgreSQL supplies the PK). So:

{"title":"GGG","content":"HHH"}

not

{"id":1,"title":"GGG","content":"HHH"}

Upvotes: 1

magula
magula

Reputation: 151

I forgot to mention back in 2) - configure.swift at the end should have the migration code to create the table when you run the Xcode (or migrate any columns you added or changed in Article.swift):

var migrations = MigrationConfig()
migrations.add(model: Article.self, database: .psql)
services.register(migrations)

Upvotes: 1

0xTim
0xTim

Reputation: 5620

You can't just throw away the future like that. This causes a number of problems:

  1. In Vapor 3, that's going to cause a memory leak.
  2. You are ignoring the result of the save, so it's failing but you don't know that.
  3. You're returning the string before the future - the save in the database - has returned.

Since everything is asynchronous, you need to change the way you write your code. Instead you should do something like:

router.post(Article.self, at: "article") { req, article -> String in
    return article.save(on: req).map { savedArticle in
        return("what happened?")
    }
}

As for why the save has failed, you should see that printed out in the console.

Upvotes: 1

imike
imike

Reputation: 5656

You need to decode a payload, then save it into database and then transform to desired result

router.post(at: "article") { req -> EventLoopFuture<String> in
    let article = try req.content.decode(Article.self)
    return article.create(on: req).transform(to: "what happened?")
}

If you haven't created a model yet you can do it via migrations in configure.swift (example for Vapor3)

var migrations = MigrationConfig()
migrations.add(model: Article.self, database: .psql)
services.register(migrations)

Artice model file should look like (example for Vapor3)

final class Article {
    var id: Int?
    var title: String
    var content: String

    init(id: Int? = nil, title: String, content: String) {
      self.title = title
      self.content = content
    }
}
extension Article: Content {}
extension Article: Migration {}
extension Article: Model {
    typealias Database = PostgreSQLDatabase
    typealias ID = Int
    static var idKey: IDKey { \.id }
}

Upvotes: 2

Related Questions