@re-shell/cli
Version:
Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja
1,428 lines (1,194 loc) • 45.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.kituraTemplate = void 0;
exports.kituraTemplate = {
id: 'kitura',
name: 'kitura',
displayName: 'Kitura Framework',
description: 'Enterprise-grade Swift web framework with IBM Cloud integration, middleware, and OpenAPI support',
language: 'swift',
framework: 'kitura',
version: '2.9.0',
tags: ['swift', 'kitura', 'api', 'rest', 'ibm', 'cloud', 'openapi'],
port: 8080,
dependencies: {},
features: ['authentication', 'openapi', 'health', 'metrics', 'logging', 'cors', 'cloud'],
files: {
// Swift Package Manager configuration
'Package.swift': `// swift-tools-version:5.9
import PackageDescription
let package = Package(
name: "{{projectName}}",
platforms: [
.macOS(.v10_15)
],
dependencies: [
// 💙 Kitura web framework
.package(url: "https://github.com/Kitura/Kitura.git", from: "2.9.200"),
.package(url: "https://github.com/Kitura/Kitura-OpenAPI.git", from: "1.4.0"),
.package(url: "https://github.com/Kitura/Swift-Kuery-ORM.git", from: "0.6.1"),
.package(url: "https://github.com/Kitura/Swift-Kuery-PostgreSQL.git", from: "2.1.1"),
.package(url: "https://github.com/Kitura/SwiftKueryMySQL.git", from: "2.0.2"),
.package(url: "https://github.com/Kitura/Swift-Kuery-SQLite.git", from: "2.0.2"),
// Authentication & Security
.package(url: "https://github.com/Kitura/Kitura-Credentials.git", from: "2.5.0"),
.package(url: "https://github.com/Kitura/Kitura-CredentialsJWT.git", from: "1.0.0"),
.package(url: "https://github.com/Kitura/Kitura-Session.git", from: "3.3.4"),
// Cloud & Monitoring
.package(url: "https://github.com/Kitura/Health.git", from: "1.0.5"),
.package(url: "https://github.com/RuntimeTools/SwiftMetrics.git", from: "2.6.5"),
.package(url: "https://github.com/Kitura/HeliumLogger.git", from: "2.0.0"),
// Utilities
.package(url: "https://github.com/Kitura/Kitura-CORS.git", from: "2.1.1"),
.package(url: "https://github.com/Kitura/Kitura-Compression.git", from: "2.2.2"),
.package(url: "https://github.com/Kitura/CloudEnvironment.git", from: "9.1.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.5.3"),
],
targets: [
.executableTarget(
name: "{{projectName}}",
dependencies: [
.product(name: "Kitura", package: "Kitura"),
.product(name: "KituraOpenAPI", package: "Kitura-OpenAPI"),
.product(name: "SwiftKueryORM", package: "Swift-Kuery-ORM"),
.product(name: "SwiftKueryPostgreSQL", package: "Swift-Kuery-PostgreSQL"),
.product(name: "SwiftKueryMySQL", package: "SwiftKueryMySQL"),
.product(name: "SwiftKuerySQLite", package: "Swift-Kuery-SQLite"),
.product(name: "Credentials", package: "Kitura-Credentials"),
.product(name: "CredentialsJWT", package: "Kitura-CredentialsJWT"),
.product(name: "KituraSession", package: "Kitura-Session"),
.product(name: "Health", package: "Health"),
.product(name: "SwiftMetrics", package: "SwiftMetrics"),
.product(name: "HeliumLogger", package: "HeliumLogger"),
.product(name: "KituraCORS", package: "Kitura-CORS"),
.product(name: "KituraCompression", package: "Kitura-Compression"),
.product(name: "CloudEnvironment", package: "CloudEnvironment"),
.product(name: "Logging", package: "swift-log"),
],
path: "Sources/{{projectName}}"
),
.testTarget(
name: "{{projectName}}Tests",
dependencies: ["{{projectName}}"],
path: "Tests/{{projectName}}Tests"
)
]
)`,
// Main application
'Sources/{{projectName}}/main.swift': `import Kitura
import HeliumLogger
import LoggerAPI
import CloudEnvironment
import Health
// Initialize Helium Logger
HeliumLogger.use()
let cloudEnv = CloudEnvironment()
let app = App(cloudEnv: cloudEnv)
do {
try app.run()
} catch let error {
Log.error("Failed to start application: \\(error.localizedDescription)")
}`,
// Application class
'Sources/{{projectName}}/Application/App.swift': `import Foundation
import Kitura
import KituraSession
import KituraOpenAPI
import KituraCORS
import KituraCompression
import SwiftKueryORM
import SwiftKueryPostgreSQL
import SwiftKueryMySQL
import SwiftKuerySQLite
import Credentials
import CredentialsJWT
import CloudEnvironment
import Health
import SwiftMetrics
import SwiftMetricsKitura
import LoggerAPI
import Logging
public class App {
let router = Router()
let cloudEnv: CloudEnvironment
let health = Health()
let metrics = Metrics()
let logger = Logger(label: "{{projectName}}")
public init(cloudEnv: CloudEnvironment) {
self.cloudEnv = cloudEnv
}
public func run() throws {
// Configure middleware
configureMiddleware()
// Configure database
try configureDatabase()
// Configure authentication
configureAuthentication()
// Configure routes
configureRoutes()
// Configure health checks
configureHealthChecks()
// Configure metrics
configureMetrics()
// Configure OpenAPI
KituraOpenAPI.addEndpoints(to: router)
// Start server
let port = cloudEnv.port ?? 8080
logger.info("Starting {{projectName}} on port \\(port)")
Kitura.addHTTPServer(onPort: port, with: router)
Kitura.run()
}
private func configureMiddleware() {
// CORS
let cors = CORS(
allowedOrigin: .all,
allowedHeaders: ["Content-Type", "Authorization"],
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
credentials: true,
maxAge: 3600
)
router.all("/*", middleware: cors)
// Body Parser
router.all("/*", middleware: BodyParser())
// Compression
router.all("/*", middleware: Compression())
// Session
router.all("/*", middleware: Session(secret: cloudEnv.getCredentials(for: "session_secret")?.username ?? "default-secret"))
// Static file serving
router.all("/", middleware: StaticFileServer(path: "./public"))
// Request logging
router.all("/*", middleware: RequestLogger())
}
private func configureDatabase() throws {
let dbType = ProcessInfo.processInfo.environment["DB_TYPE"] ?? "postgresql"
switch dbType {
case "postgresql":
let connectionString = cloudEnv.getDatabaseConfiguration(for: "{{projectName}}-db")?.url ??
ProcessInfo.processInfo.environment["DATABASE_URL"] ??
"postgresql://localhost:5432/{{projectName}}"
let pool = PostgreSQLConnection.createPool(
url: URL(string: connectionString)!,
poolOptions: ConnectionPoolOptions(initialCapacity: 10, maxCapacity: 50)
)
Database.default = Database(pool)
case "mysql":
let connectionString = ProcessInfo.processInfo.environment["DATABASE_URL"] ??
"mysql://root@localhost:3306/{{projectName}}"
let pool = MySQLConnection.createPool(
url: URL(string: connectionString)!,
poolOptions: ConnectionPoolOptions(initialCapacity: 10, maxCapacity: 50)
)
Database.default = Database(pool)
default:
let pool = SQLiteConnection.createPool(
filename: ProcessInfo.processInfo.environment["DATABASE_PATH"] ?? "./{{projectName}}.db",
poolOptions: ConnectionPoolOptions(initialCapacity: 1, maxCapacity: 5)
)
Database.default = Database(pool)
}
// Run migrations
try runMigrations()
}
private func configureAuthentication() {
let credentials = Credentials()
// JWT authentication
let jwtSecret = cloudEnv.getCredentials(for: "jwt_secret")?.password ??
ProcessInfo.processInfo.environment["JWT_SECRET"] ??
"default-jwt-secret"
credentials.register(CredentialsJWT(
verifier: .hs256(key: jwtSecret.data(using: .utf8)!)
))
router.all("/api/v1/protected/*", middleware: credentials)
}
private func configureRoutes() {
// API Info
router.get("/") { request, response, next in
response.send(json: [
"name": "{{projectName}} API",
"version": "1.0.0",
"status": "running"
])
next()
}
// Health check
router.get("/health") { request, response, next in
let health = self.health.status.toSimpleDictionary()
response.send(json: health)
next()
}
// API Routes
let api = router.route("/api/v1")
// Authentication routes
api.post("/auth/register", handler: AuthController.register)
api.post("/auth/login", handler: AuthController.login)
api.post("/auth/refresh", handler: AuthController.refresh)
// Protected routes
let protected = api.route("/protected")
// User routes
protected.get("/users", handler: UserController.list)
protected.get("/users/:id", handler: UserController.get)
protected.put("/users/:id", handler: UserController.update)
protected.delete("/users/:id", handler: UserController.delete)
// Todo routes
protected.get("/todos", handler: TodoController.list)
protected.post("/todos", handler: TodoController.create)
protected.get("/todos/:id", handler: TodoController.get)
protected.put("/todos/:id", handler: TodoController.update)
protected.delete("/todos/:id", handler: TodoController.delete)
}
private func configureHealthChecks() {
// Add liveness check
health.addLivenessCheck { callback in
callback(true, nil)
}
// Add readiness check - verify database connection
health.addReadinessCheck { callback in
Database.default?.tableExists(User.tableName) { exists, error in
callback(exists && error == nil, nil)
}
}
}
private func configureMetrics() {
metrics.initialize(router: router)
}
private func runMigrations() throws {
// Create tables
do {
try User.createTableSync()
try Todo.createTableSync()
try RefreshToken.createTableSync()
logger.info("Database migrations completed successfully")
} catch {
logger.error("Failed to run migrations: \\(error)")
throw error
}
}
}`,
// Models
'Sources/{{projectName}}/Models/User.swift': `import Foundation
import SwiftKueryORM
import Credentials
struct User: Model {
static var tableName = "users"
var id: UUID?
var email: String
var passwordHash: String
var name: String
var createdAt: Date?
var updatedAt: Date?
init(email: String, passwordHash: String, name: String) {
self.id = UUID()
self.email = email
self.passwordHash = passwordHash
self.name = name
self.createdAt = Date()
self.updatedAt = Date()
}
}
extension User {
struct CreateRequest: Codable {
let email: String
let password: String
let name: String
}
struct LoginRequest: Codable {
let email: String
let password: String
}
struct UpdateRequest: Codable {
let name: String?
let email: String?
}
struct PublicResponse: Codable {
let id: UUID
let email: String
let name: String
let createdAt: Date?
}
func toPublic() -> PublicResponse {
return PublicResponse(
id: id!,
email: email,
name: name,
createdAt: createdAt
)
}
}
// JWT Claims
struct UserClaims: Claims {
let sub: String // user id
let exp: Date
let iat: Date
let email: String
let name: String
}`,
'Sources/{{projectName}}/Models/Todo.swift': `import Foundation
import SwiftKueryORM
struct Todo: Model {
static var tableName = "todos"
var id: UUID?
var userId: UUID
var title: String
var description: String?
var completed: Bool
var createdAt: Date?
var updatedAt: Date?
init(userId: UUID, title: String, description: String? = nil) {
self.id = UUID()
self.userId = userId
self.title = title
self.description = description
self.completed = false
self.createdAt = Date()
self.updatedAt = Date()
}
}
extension Todo {
struct CreateRequest: Codable {
let title: String
let description: String?
}
struct UpdateRequest: Codable {
let title: String?
let description: String?
let completed: Bool?
}
}`,
'Sources/{{projectName}}/Models/RefreshToken.swift': `import Foundation
import SwiftKueryORM
struct RefreshToken: Model {
static var tableName = "refresh_tokens"
var id: UUID?
var userId: UUID
var token: String
var expiresAt: Date
var createdAt: Date?
init(userId: UUID) {
self.id = UUID()
self.userId = userId
self.token = UUID().uuidString
self.expiresAt = Date().addingTimeInterval(60 * 60 * 24 * 30) // 30 days
self.createdAt = Date()
}
var isValid: Bool {
return expiresAt > Date()
}
}`,
// Controllers
'Sources/{{projectName}}/Controllers/AuthController.swift': `import Foundation
import Kitura
import SwiftKueryORM
import Credentials
import CredentialsJWT
import CryptorECC
import LoggerAPI
struct AuthController {
static func register(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
let createRequest = try request.read(as: User.CreateRequest.self)
// Check if user exists
User.find(where: {$0.email == createRequest.email}) { users, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
if let users = users, !users.isEmpty {
response.status(.conflict).send(json: ["error": "User already exists"])
return next()
}
// Hash password
let passwordHash = PasswordHasher.hash(createRequest.password)
// Create user
var user = User(
email: createRequest.email,
passwordHash: passwordHash,
name: createRequest.name
)
user.save { savedUser, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
guard let savedUser = savedUser else {
response.status(.internalServerError).send(json: ["error": "Failed to create user"])
return next()
}
// Generate tokens
do {
let tokens = try generateTokens(for: savedUser)
response.send(json: [
"user": savedUser.toPublic(),
"accessToken": tokens.accessToken,
"refreshToken": tokens.refreshToken
])
} catch {
response.status(.internalServerError).send(json: ["error": "Failed to generate tokens"])
}
next()
}
}
}
static func login(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
let loginRequest = try request.read(as: User.LoginRequest.self)
User.find(where: {$0.email == loginRequest.email}) { users, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
guard let users = users,
let user = users.first,
PasswordHasher.verify(loginRequest.password, against: user.passwordHash) else {
response.status(.unauthorized).send(json: ["error": "Invalid credentials"])
return next()
}
// Generate tokens
do {
let tokens = try generateTokens(for: user)
response.send(json: [
"user": user.toPublic(),
"accessToken": tokens.accessToken,
"refreshToken": tokens.refreshToken
])
} catch {
response.status(.internalServerError).send(json: ["error": "Failed to generate tokens"])
}
next()
}
}
static func refresh(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
struct RefreshRequest: Codable {
let refreshToken: String
}
let refreshRequest = try request.read(as: RefreshRequest.self)
RefreshToken.find(where: {$0.token == refreshRequest.refreshToken}) { tokens, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
guard let tokens = tokens,
let token = tokens.first,
token.isValid else {
response.status(.unauthorized).send(json: ["error": "Invalid refresh token"])
return next()
}
// Find user
User.find(id: token.userId) { user, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
guard let user = user else {
response.status(.notFound).send(json: ["error": "User not found"])
return next()
}
// Delete old refresh token
token.delete { error in
if let error = error {
Log.error("Failed to delete old refresh token: \\(error)")
}
}
// Generate new tokens
do {
let tokens = try generateTokens(for: user)
response.send(json: [
"accessToken": tokens.accessToken,
"refreshToken": tokens.refreshToken
])
} catch {
response.status(.internalServerError).send(json: ["error": "Failed to generate tokens"])
}
next()
}
}
}
private static func generateTokens(for user: User) throws -> (accessToken: String, refreshToken: String) {
// Generate access token
let claims = UserClaims(
sub: user.id!.uuidString,
exp: Date().addingTimeInterval(60 * 15), // 15 minutes
iat: Date(),
email: user.email,
name: user.name
)
let jwtSecret = ProcessInfo.processInfo.environment["JWT_SECRET"] ?? "default-jwt-secret"
let jwt = JWT(claims: claims)
let accessToken = try jwt.sign(using: .hs256(key: jwtSecret.data(using: .utf8)!))
// Generate refresh token
var refreshToken = RefreshToken(userId: user.id!)
try refreshToken.save()
return (accessToken: accessToken, refreshToken: refreshToken.token)
}
}`,
'Sources/{{projectName}}/Controllers/UserController.swift': `import Foundation
import Kitura
import SwiftKueryORM
import Credentials
struct UserController {
static func list(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
User.findAll { users, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
let publicUsers = users?.map { $0.toPublic() } ?? []
response.send(json: publicUsers)
next()
}
}
static func get(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
guard let id = request.parameters["id"],
let userId = UUID(uuidString: id) else {
response.status(.badRequest).send(json: ["error": "Invalid user ID"])
return next()
}
User.find(id: userId) { user, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
guard let user = user else {
response.status(.notFound).send(json: ["error": "User not found"])
return next()
}
response.send(json: user.toPublic())
next()
}
}
static func update(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
guard let userProfile = request.userProfile,
let currentUserId = UUID(uuidString: userProfile.id) else {
response.status(.unauthorized).send(json: ["error": "Unauthorized"])
return next()
}
guard let id = request.parameters["id"],
let userId = UUID(uuidString: id) else {
response.status(.badRequest).send(json: ["error": "Invalid user ID"])
return next()
}
// Users can only update their own profile
guard currentUserId == userId else {
response.status(.forbidden).send(json: ["error": "Forbidden"])
return next()
}
let updateRequest = try request.read(as: User.UpdateRequest.self)
User.find(id: userId) { user, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
guard var user = user else {
response.status(.notFound).send(json: ["error": "User not found"])
return next()
}
// Update fields
if let name = updateRequest.name {
user.name = name
}
if let email = updateRequest.email {
// Check if email is already taken
User.find(where: {$0.email == email}) { existingUsers, error in
if let existingUsers = existingUsers,
!existingUsers.isEmpty,
existingUsers[0].id != userId {
response.status(.conflict).send(json: ["error": "Email already taken"])
return next()
}
user.email = email
user.updatedAt = Date()
user.update(id: userId) { updatedUser, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
response.send(json: updatedUser?.toPublic() ?? user.toPublic())
next()
}
}
} else {
user.updatedAt = Date()
user.update(id: userId) { updatedUser, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
response.send(json: updatedUser?.toPublic() ?? user.toPublic())
next()
}
}
}
}
static func delete(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
guard let userProfile = request.userProfile,
let currentUserId = UUID(uuidString: userProfile.id) else {
response.status(.unauthorized).send(json: ["error": "Unauthorized"])
return next()
}
guard let id = request.parameters["id"],
let userId = UUID(uuidString: id) else {
response.status(.badRequest).send(json: ["error": "Invalid user ID"])
return next()
}
// Users can only delete their own profile
guard currentUserId == userId else {
response.status(.forbidden).send(json: ["error": "Forbidden"])
return next()
}
User.delete(id: userId) { error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
response.status(.noContent)
next()
}
}
}`,
'Sources/{{projectName}}/Controllers/TodoController.swift': `import Foundation
import Kitura
import SwiftKueryORM
import Credentials
struct TodoController {
static func list(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
guard let userProfile = request.userProfile,
let userId = UUID(uuidString: userProfile.id) else {
response.status(.unauthorized).send(json: ["error": "Unauthorized"])
return next()
}
Todo.find(where: {$0.userId == userId}) { todos, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
response.send(json: todos ?? [])
next()
}
}
static func create(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
guard let userProfile = request.userProfile,
let userId = UUID(uuidString: userProfile.id) else {
response.status(.unauthorized).send(json: ["error": "Unauthorized"])
return next()
}
let createRequest = try request.read(as: Todo.CreateRequest.self)
var todo = Todo(
userId: userId,
title: createRequest.title,
description: createRequest.description
)
todo.save { savedTodo, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
response.status(.created).send(json: savedTodo ?? todo)
next()
}
}
static func get(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
guard let userProfile = request.userProfile,
let userId = UUID(uuidString: userProfile.id) else {
response.status(.unauthorized).send(json: ["error": "Unauthorized"])
return next()
}
guard let id = request.parameters["id"],
let todoId = UUID(uuidString: id) else {
response.status(.badRequest).send(json: ["error": "Invalid todo ID"])
return next()
}
Todo.find(id: todoId) { todo, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
guard let todo = todo else {
response.status(.notFound).send(json: ["error": "Todo not found"])
return next()
}
// Check ownership
guard todo.userId == userId else {
response.status(.forbidden).send(json: ["error": "Forbidden"])
return next()
}
response.send(json: todo)
next()
}
}
static func update(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
guard let userProfile = request.userProfile,
let userId = UUID(uuidString: userProfile.id) else {
response.status(.unauthorized).send(json: ["error": "Unauthorized"])
return next()
}
guard let id = request.parameters["id"],
let todoId = UUID(uuidString: id) else {
response.status(.badRequest).send(json: ["error": "Invalid todo ID"])
return next()
}
let updateRequest = try request.read(as: Todo.UpdateRequest.self)
Todo.find(id: todoId) { todo, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
guard var todo = todo else {
response.status(.notFound).send(json: ["error": "Todo not found"])
return next()
}
// Check ownership
guard todo.userId == userId else {
response.status(.forbidden).send(json: ["error": "Forbidden"])
return next()
}
// Update fields
if let title = updateRequest.title {
todo.title = title
}
if let description = updateRequest.description {
todo.description = description
}
if let completed = updateRequest.completed {
todo.completed = completed
}
todo.updatedAt = Date()
todo.update(id: todoId) { updatedTodo, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
response.send(json: updatedTodo ?? todo)
next()
}
}
}
static func delete(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
guard let userProfile = request.userProfile,
let userId = UUID(uuidString: userProfile.id) else {
response.status(.unauthorized).send(json: ["error": "Unauthorized"])
return next()
}
guard let id = request.parameters["id"],
let todoId = UUID(uuidString: id) else {
response.status(.badRequest).send(json: ["error": "Invalid todo ID"])
return next()
}
// Verify ownership before deletion
Todo.find(id: todoId) { todo, error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
guard let todo = todo else {
response.status(.notFound).send(json: ["error": "Todo not found"])
return next()
}
// Check ownership
guard todo.userId == userId else {
response.status(.forbidden).send(json: ["error": "Forbidden"])
return next()
}
Todo.delete(id: todoId) { error in
if let error = error {
response.status(.internalServerError).send(json: ["error": error.localizedDescription])
return next()
}
response.status(.noContent)
next()
}
}
}
}`,
// Middleware
'Sources/{{projectName}}/Middleware/RequestLogger.swift': `import Kitura
import LoggerAPI
class RequestLogger: RouterMiddleware {
func handle(request: RouterRequest, response: RouterResponse, next: @escaping () -> Void) throws {
let startTime = Date()
response.setOnEndInvoked {
let duration = Date().timeIntervalSince(startTime)
let durationMs = Int(duration * 1000)
Log.info("""
\\(request.method.rawValue) \\(request.originalURL) \\
\\(response.statusCode?.rawValue ?? 0) \\(durationMs)ms
""")
}
next()
}
}`,
// Utilities
'Sources/{{projectName}}/Utils/PasswordHasher.swift': `import Foundation
import Crypto
struct PasswordHasher {
static func hash(_ password: String) -> String {
// In production, use bcrypt or argon2
// This is a simple example using SHA256
let salt = UUID().uuidString
let salted = password + salt
let hashed = salted.digest(using: .sha256)?.base64EncodedString() ?? ""
return "\\(salt)$\\(hashed)"
}
static func verify(_ password: String, against hash: String) -> Bool {
let parts = hash.split(separator: "$")
guard parts.count == 2 else { return false }
let salt = String(parts[0])
let expectedHash = String(parts[1])
let salted = password + salt
let computedHash = salted.digest(using: .sha256)?.base64EncodedString() ?? ""
return computedHash == expectedHash
}
}`,
// Tests
'Tests/{{projectName}}Tests/AuthTests.swift': `import XCTest
import Foundation
import Kitura
import KituraNet
@testable import {{projectName}}
final class AuthTests: XCTestCase {
static var app: App?
static var port: Int = 8090
override class func setUp() {
super.setUp()
let cloudEnv = CloudEnvironment()
app = App(cloudEnv: cloudEnv)
Kitura.addHTTPServer(onPort: port, with: app!.router)
Kitura.start()
}
override class func tearDown() {
Kitura.stop()
super.tearDown()
}
func testRegister() {
let expectation = self.expectation(description: "Register user")
let user = [
"email": "test@example.com",
"password": "password123",
"name": "Test User"
]
performRequest(
method: "POST",
path: "/api/v1/auth/register",
body: user
) { data in
if let response = try? JSONDecoder().decode(AuthResponse.self, from: data) {
XCTAssertEqual(response.user.email, "test@example.com")
XCTAssertFalse(response.accessToken.isEmpty)
XCTAssertFalse(response.refreshToken.isEmpty)
} else {
XCTFail("Failed to decode response")
}
expectation.fulfill()
}
wait(for: [expectation], timeout: 5)
}
func testLogin() {
let expectation = self.expectation(description: "Login user")
// First register
let user = [
"email": "login@example.com",
"password": "password123",
"name": "Login User"
]
performRequest(
method: "POST",
path: "/api/v1/auth/register",
body: user
) { _ in
// Then login
let credentials = [
"email": "login@example.com",
"password": "password123"
]
self.performRequest(
method: "POST",
path: "/api/v1/auth/login",
body: credentials
) { data in
if let response = try? JSONDecoder().decode(AuthResponse.self, from: data) {
XCTAssertEqual(response.user.email, "login@example.com")
XCTAssertFalse(response.accessToken.isEmpty)
} else {
XCTFail("Failed to decode response")
}
expectation.fulfill()
}
}
wait(for: [expectation], timeout: 10)
}
private func performRequest(method: String, path: String, body: [String: Any]? = nil, callback: @escaping (Data) -> Void) {
var request = URLRequest(url: URL(string: "http://localhost:\\(AuthTests.port)\\(path)")!)
request.httpMethod = method
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
if let body = body {
request.httpBody = try? JSONSerialization.data(withJSONObject: body)
}
URLSession.shared.dataTask(with: request) { data, response, error in
XCTAssertNil(error)
XCTAssertNotNil(data)
if let data = data {
callback(data)
}
}.resume()
}
}
struct AuthResponse: Codable {
let user: UserResponse
let accessToken: String
let refreshToken: String
}
struct UserResponse: Codable {
let id: String
let email: String
let name: String
}`,
// Configuration files
'.env.example': `# Server Configuration
PORT=8080
# Database Configuration
DB_TYPE=postgresql
DATABASE_URL=postgresql://localhost:5432/{{projectName}}
# Security
JWT_SECRET=your-jwt-secret-key-here
SESSION_SECRET=your-session-secret-here
# IBM Cloud Services (optional)
VCAP_SERVICES={}
# Environment
NODE_ENV=development`,
'manifest.yml': `---
applications:
- name: {{projectName}}
memory: 256M
instances: 1
buildpack: swift_buildpack
env:
SWIFT_BUILD_DIR_CACHE: false
services:
- {{projectName}}-db
- {{projectName}}-monitoring`,
'cloud-config.json': `{
"name": "{{projectName}}",
"region": "us-south",
"services": {
"cloudant": {
"name": "{{projectName}}-cloudant",
"plan": "lite"
},
"appid": {
"name": "{{projectName}}-appid",
"plan": "lite"
},
"monitoring": {
"name": "{{projectName}}-monitoring",
"plan": "lite"
}
}
}`,
// Docker configuration
'Dockerfile': `# ================================
# Build image
# ================================
FROM swift:5.9-jammy as build
# Install system dependencies
RUN apt-get update && apt-get install -y \\
libssl-dev \\
libcurl4-openssl-dev \\
libpq-dev \\
libmysqlclient-dev \\
libsqlite3-dev \\
uuid-dev \\
&& rm -rf /var/lib/apt/lists/*
WORKDIR /build
# Copy package files
COPY Package.* ./
# Resolve dependencies
RUN swift package resolve
# Copy source
COPY Sources ./Sources
COPY Tests ./Tests
# Build for release
RUN swift build -c release
# Run tests
RUN swift test
# ================================
# Runtime image
# ================================
FROM ubuntu:22.04
# Install runtime dependencies
RUN apt-get update && apt-get install -y \\
libssl3 \\
libcurl4 \\
libpq5 \\
libmysqlclient21 \\
libsqlite3-0 \\
ca-certificates \\
tzdata \\
&& rm -rf /var/lib/apt/lists/*
# Create app user
RUN useradd -m -d /app -s /bin/bash app
WORKDIR /app
# Copy build artifacts
COPY --from=build /build/.build/release/{{projectName}} .
COPY --from=build /build/Package.resolved .
# Copy static files
COPY public ./public
# Create necessary directories
RUN mkdir -p logs && chown -R app:app /app
USER app
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \\
CMD curl -f http://localhost:8080/health || exit 1
EXPOSE 8080
CMD ["./{{projectName}}"]`,
'docker-compose.yml': `version: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- PORT=8080
- DB_TYPE=postgresql
- DATABASE_URL=postgresql://kitura:kitura@db:5432/{{projectName}}
- JWT_SECRET=development-jwt-secret
- SESSION_SECRET=development-session-secret
depends_on:
db:
condition: service_healthy
volumes:
- ./public:/app/public
db:
image: postgres:15-alpine
environment:
- POSTGRES_USER=kitura
- POSTGRES_PASSWORD=kitura
- POSTGRES_DB={{projectName}}
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U kitura"]
interval: 5s
timeout: 5s
retries: 5
metrics:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
volumes:
postgres_data:
prometheus_data:`,
'prometheus.yml': `global:
scrape_interval: 15s
scrape_configs:
- job_name: '{{projectName}}'
static_configs:
- targets: ['app:8080']
metrics_path: '/metrics'`,
// README
'README.md': `# {{projectName}}
Enterprise-grade Swift web application built with Kitura and IBM Cloud integration.
## Features
- ✅ RESTful API with Kitura framework
- ✅ OpenAPI/Swagger documentation
- ✅ JWT authentication with refresh tokens
- ✅ SwiftKuery ORM with PostgreSQL, MySQL, and SQLite
- ✅ Health checks and metrics monitoring
- ✅ IBM Cloud ready with manifest.yml
- ✅ Docker and Kubernetes support
- ✅ Request logging and compression
- ✅ CORS and session management
- ✅ Comprehensive test suite
## Requirements
- Swift 5.9 or later
- macOS 10.15+ or Ubuntu 22.04+
- PostgreSQL 12+ (optional)
## Getting Started
1. Clone the repository
2. Install dependencies:
\`\`\`bash
swift package resolve
\`\`\`
3. Copy \`.env.example\` to \`.env\` and configure
4. Run the application:
\`\`\`bash
swift run
\`\`\`
The server will start on port 8080.
## API Documentation
Once running, visit \`http://localhost:8080/openapi\` for interactive API documentation.
## Endpoints
### Public Endpoints
- \`GET /\` - API information
- \`GET /health\` - Health status
- \`GET /metrics\` - Prometheus metrics
- \`POST /api/v1/auth/register\` - Register new user
- \`POST /api/v1/auth/login\` - Login
- \`POST /api/v1/auth/refresh\` - Refresh token
### Protected Endpoints
All protected endpoints require Bearer token authentication.
- \`GET /api/v1/protected/users\` - List users
- \`GET /api/v1/protected/users/:id\` - Get user
- \`PUT /api/v1/protected/users/:id\` - Update user
- \`DELETE /api/v1/protected/users/:id\` - Delete user
- \`GET /api/v1/protected/todos\` - List todos
- \`POST /api/v1/protected/todos\` - Create todo
- \`GET /api/v1/protected/todos/:id\` - Get todo
- \`PUT /api/v1/protected/todos/:id\` - Update todo
- \`DELETE /api/v1/protected/todos/:id\` - Delete todo
## Running with Docker
\`\`\`bash
docker-compose up
\`\`\`
## Deploying to IBM Cloud
1. Install IBM Cloud CLI
2. Login: \`ibmcloud login\`
3. Push the app: \`ibmcloud cf push\`
## Testing
Run the test suite:
\`\`\`bash
swift test
\`\`\`
## Configuration
Environment variables:
- \`PORT\` - Server port (default: 8080)
- \`DB_TYPE\` - Database type: postgresql, mysql, sqlite (default: postgresql)
- \`DATABASE_URL\` - Database connection string
- \`JWT_SECRET\` - Secret key for JWT signing
- \`SESSION_SECRET\` - Secret key for sessions
## License
MIT`,
'.gitignore': `# Swift
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
DerivedData/
.swiftpm/config/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
# Environment
.env
.env.local
# Database
*.sqlite
*.db
# Logs
logs/
*.log
# Dependencies
node_modules/
# IDE
.vscode/
.idea/`,
'.cfignore': `.git/
.build/
.env
*.xcodeproj
Tests/
README.md
docker-compose.yml
Dockerfile`,
},
};