The way to write Swift scripts utilizing the brand new Command API in Vapor 4?

[ad_1]

Shell scripts are necessities on the server facet. Learn to construct Swift scripts on your backend apps utilizing property wrappers.

Vapor

Swift Argument Parser vs Vapor Instructions

Apple open-sourced a brand new library that may assist you a large number if you wish to construct scripts that written in Swift. The Swift Argument Parser was beforehand a part of the Swift Package deal Supervisor instruments, however now it’s even highly effective & has it is personal life (I imply repository). 😉

However Vapor already had a considerably comparable method to construct scripts, however in Vapor 4 the Command API is best than ever. Property Wrappers (obtainable from Swift 5.1) are utilized in each instances to deal with arguments, flags & choices. Personally I like this method lots.

Let me present you a easy whats up command:


import ArgumentParser

struct HelloCommand: ParsableCommand {
    @Argument(assist: "The identify to say whats up")
    var identify: String

    func run() throws {
        print("Hey (self.identify)!")
    }
}
HelloCommand.fundamental()

Now I will present you the best way to implement the same command utilizing Vapor:


import Vapor

remaining class HelloCommand: Command {
    
    let assist = "This command will say whats up to a given identify."

    struct Signature: CommandSignature {
        @Argument(identify: "identify", assist: "The identify to say whats up")
        var identify: String
    }

    func run(utilizing context: CommandContext, signature: Signature) throws {
        print("Hey (signature.identify)!")
    }
}

public func configure(_ app: Software) throws {
    app.instructions.use(HelloCommand(), as: "whats up")
}

As you’ll be able to see they virtually seem like the identical.


Should you love scripting, you need to undoubtedly verify swift-sh and Brisk


The Swift Argument Parser library is a light-weight answer if you’re solely in search of a easy Swift script. An excellent instance is a device that manipulates recordsdata on the system or one thing comparable. It is only one little dependency, but it surely removes a lot boilerplate out of your scripts. It lets you give attention to the script itself, as an alternative of parsing the command line inputs. Yow will discover extra detailed examples and an in depth documentation contained in the GitHub repository. 🙏


Vapor’s Command API is beneficial if you wish to carry out extra sophisticated duties together with your scripts. Something that is a part of your Vapor utility might be triggered from a command, so you’ll be able to simply create a backend device that reads (or writes) data from the database utilizing Fluent 4. That is the principle benefit of utilizing a Vapor command, as an alternative a stanadlone Swift script.




Arguments, choices, flags

Let’s prolong the whats up command with a brand new choice and a flag. The principle distinction between an choice and a flag is that an choice has an related worth, however a flag is simply one thing that you simply give to the command or not. Each choices and flags begin with a single - or a double sprint --, normally the only dashed model makes use of a brief identify for a similar factor. 🤓

Arguments are person supplied values learn so as (eg.: ./whats up joe bob john).

Now that you realize the essential definitions, right here is the instance:

remaining class HelloCommand: Command {
        
    struct Signature: CommandSignature {

        @Argument(identify: "identify", assist: "The identify to say whats up")
        var identify: String

        @Choice(identify: "greeting", quick: "g", assist: "Greeting used")
        var greeting: String?

        @Flag(identify: "capitalize", quick: "c", assist: "Capitalizes the identify")
        var capitalize: Bool
    }

    let assist = "This command will say whats up to a given identify."

    func run(utilizing context: CommandContext, signature: Signature) throws {
        let greeting = signature.greeting ?? "Hey"
        var identify = signature.identify
        if signature.capitalize {
            identify = identify.capitalized
        }
        print("(greeting) (identify)!")
    }
}

Arguments are required by default, choices and flags are optionals. You possibly can have a customized identify (quick and lengthy) for all the pieces, plus you’ll be able to customise the assistance message for each part.

swift run Run whats up john


swift run Run whats up john --greeting Hello


swift run Run whats up john --greeting Hello --capitalized


swift run Run whats up john -g Szia -c

You possibly can name the command utilizing a number of kinds. Be at liberty to select a most popular model. ⭐️



Subcommands

When command-line packages develop bigger, it may be helpful to divide them into a bunch of smaller packages, offering an interface by subcommands. Utilities corresponding to git and the Swift bundle supervisor are in a position to present diverse interfaces for every of their sub-functions by implementing subcommands corresponding to git department or swift bundle init.

Vapor can deal with command teams in a extremely cool means. I will add an additional static property to call our instructions, since I do not wish to repeat myself or bloat the code with pointless strings:

remaining class HelloCommand: Command {
    
    static var identify = "whats up"
        
    
}

struct WelcomeCommandGroup: CommandGroup {
    
    static var identify = "welcome"

    let assist: String
    let instructions: [String: AnyCommand]
    
    var defaultCommand: AnyCommand? {
        self.instructions[HelloCommand.name]
    }

    init() {
        self.assist = "search engine optimisation command group assist"

        self.instructions = [
            HelloCommand.name: HelloCommand(),
        ]
    }
}

public func configure(_ app: Software) throws {

    app.instructions.use(WelcomeCommandGroup(), as: WelcomeCommandGroup.identify)
}


That is it, we simply moved our whats up command beneath the welcome namespace.

swift run Run welcome whats up john --greeting "Hello" --capitalize

Should you learn the Swift Argument Parser docs, you’ll be able to obtain the very same conduct by a customized CommandConfiguration. Personally, I desire Vapor’s method right here… 🤷‍♂️



Ready for async duties

Vapor builds on high of SwiftNIO together with EventLoops, Futures & Guarantees. A lot of the API is asynchronous, however within the CLI world you must watch for the async operations to complete.

remaining class TodoCommand: Command {
    
    static let identify = "todo"

    struct Signature: CommandSignature { }
        
    let assist = "This command will create a dummy Todo merchandise"

    func run(utilizing context: CommandContext, signature: Signature) throws {
        let app = context.utility
        app.logger.discover("Creating todos...")
        
        let todo = Todo(title: "Look ahead to async duties...")
        attempt todo.create(on: app.db).wait()
        
        app.logger.discover("Todo is prepared.")
    }
}

There’s a throwing wait() methodology you can make the most of to “keep within the loop” till all the pieces is finished. You may also get a pointer for the appliance object by utilizing the present context. The app has the database connection, so you’ll be able to inform Fluent to create a brand new mannequin. Additionally you need to use the built-in logger to print data to the console whereas the person waits. ⏳




Utilizing ConsoleKit with out Vapor

Let’s discuss overheads. Vapor comes with this neat instructions API, but additionally bundles a number of different core issues. What if I simply need the goodies for my Swift scripts? No drawback. You should utilize the underlying ConsoleKit by including it as a dependency.


import PackageDescription

let bundle = Package deal(
    identify: "myProject",
    platforms: [
       .macOS(.v10_15)
    ],
    dependencies: [
        .package(url: "https://github.com/vapor/console-kit", from: "4.1.0"),
    ],
    targets: [
        .target(name: "myProject", dependencies: [
            .product(name: "ConsoleKit", package: "console-kit"),
        ])
    ]
)

You continue to need to do some further work in your fundamental.swift file, however nothing severe:

import ConsoleKit
import Basis

let console: Console = Terminal()
var enter = CommandInput(arguments: CommandLine.arguments)
var context = CommandContext(console: console, enter: enter)

var instructions = Instructions(enableAutocomplete: true)
instructions.use(HelloCommand(), as: HelloCommand.identify, isDefault: false)

do {
    let group = instructions.group(assist: "Utilizing ConsoleKit with out Vapor.")
    attempt console.run(group, enter: enter)
}
catch {
    console.error("(error)")
    exit(1)
}

This manner you’ll be able to do away with many of the community associated core packages (which might be included by default in the event you use Vapor). This method solely fetches swift-log as a 3rd social gathering dependency. 😍




Abstract

ConsoleKit in Vapor is a good way to jot down CLI instruments and small scripts. The brand new Swift Argument Parser is a extra light-weight answer for a similar drawback. In case your plan is to take care of databases by scripts otherwise you carry out a number of networking or asynchronous operations it could be higher to go together with Vapor, since you’ll be able to at all times develop by importing a brand new part from the ecosystem.


[ad_2]

Leave a Reply