Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configure PostgreSQL DB with Vapor 3 on Heroku

I've built a simple Vapor 3 API that I'd like to deploy on Heroku. I'd like it to be backed by a PostgreSQL database which is also attached to another Heroku app (I have successfully attached the DB in the Heroku dashboard – and the DB works correctly in the other application). However, my Vapor app never completes starting up, crashing with the following error:

Fatal error: Error raised at top level: ⚠️ PostgreSQL Error: no pg_hba.conf entry for host "[the IP addr]", user "[heroku postgres username here]", database "[heroku psql db here]", SSL off
- id: PostgreSQLError.server.fatal.ClientAuthentication

I used vapor heroku init to set up the Heroku app. I've Googled around, and tried adding a Procfile and messing with configure.swift, but so far no luck. Here are all the relevant files I can think of:

Procfile:

web: Run serve --env production --hostname 0.0.0.0 --port $PORT --config:postgresql.url $DATABASE_URL

configure.swift:

import FluentPostgreSQL
import Vapor

/// Called before your application initializes.
public func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws {
    /// Register providers first
    try services.register(FluentPostgreSQLProvider())

    var contentConfig = ContentConfig.default()

    /// Create custom JSON encoder
    let jsonEncoder = JSONEncoder()
    if #available(OSX 10.12, *) {
        jsonEncoder.dateEncodingStrategy = .iso8601
    } else {
        jsonEncoder.dateEncodingStrategy = .millisecondsSince1970
    }
//    jsonEncoder.keyEncodingStrategy = .convertToSnakeCase

    /// Register JSON encoder and content config
    contentConfig.use(encoder: jsonEncoder, for: .json)
    services.register(contentConfig)

    /// Register routes to the router
    let router = EngineRouter.default()
    try routes(router)
    services.register(router, as: Router.self)

    /// Register middleware
    var middlewares = MiddlewareConfig() // Create _empty_ middleware config
    /// middlewares.use(FileMiddleware.self) // Serves files from `Public/` directory
    middlewares.use(ErrorMiddleware.self) // Catches errors and converts to HTTP response
    services.register(middlewares)

    // Configure a database
    let dbConfig: PostgreSQLDatabaseConfig
    if let url = Environment.get("DATABASE_URL"), let psqlConfig = PostgreSQLDatabaseConfig(url: url) {
        dbConfig = psqlConfig
    } else {
        dbConfig = PostgreSQLDatabaseConfig(hostname: "localhost", port: 5432, username: "admin", database: "development", password: nil)
    }
    let postgresql = try PostgreSQLDatabase(config: dbConfig)

    /// Register the configured SQLite database to the database config.
    var databases = DatabasesConfig()
    databases.add(database: postgresql, as: .psql)
    services.register(databases)

    /// Configure migrations
    var migrations = MigrationConfig()
    migrations.add(model: Visit.self, database: .psql)
    services.register(migrations)
}

Package.swift:

// swift-tools-version:4.0
import PackageDescription

let package = Package(
    name: "SubwayNyc",
    dependencies: [
        // 💧 A server-side Swift web framework.
        .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),

        // 🔵 Swift ORM (queries, models, relations, etc) built on PostgreSQL.
        .package(url: "https://github.com/vapor/fluent-postgresql.git", from: "1.0.0"),

        .package(url: "https://github.com/vapor/sql.git", from: "2.1.0")
    ],
    targets: [
        .target(name: "App", dependencies: ["FluentPostgreSQL", "Vapor"]),
        .target(name: "Run", dependencies: ["App"]),
        .testTarget(name: "AppTests", dependencies: ["App"])
    ]
)

How can I get PostgreSQL hooked up to my Vapor 3 app on Heroku?

like image 410
Elliot Schrock Avatar asked Oct 21 '18 03:10

Elliot Schrock


2 Answers

For Heroku we need unverifiedTLS transport.

https://api.vapor.codes/postgresql/latest/PostgreSQL/Classes/PostgreSQLConnection/TransportConfig.html

let pgURL = Environment.get("DATABASE_URL") ?? "postgres://user:password@host:port/database"

let pgConfig = PostgreSQLDatabaseConfig(url: pgURL, transport: PostgreSQLConnection.TransportConfig.unverifiedTLS)!

:D

like image 90
Rigel David Avatar answered Oct 13 '22 16:10

Rigel David


The original error is the key here, in particular: SSL off.

This error is thrown by Heroku Postgres when the client is attempting to connect without SSL. Not familiar with Vapor myself, but a quick look around suggests that configure.swift is where you can make configuration changes. Once you enable SSL from the client, you should be able to connect to this database instance without issue.

like image 29
RangerRanger Avatar answered Oct 13 '22 18:10

RangerRanger