Home IOS Development How one can write Swift scripts utilizing the brand new Command API in Vapor 4?

How one can write Swift scripts utilizing the brand new Command API in Vapor 4?

0
How one can write Swift scripts utilizing the brand new Command API in Vapor 4?

[ad_1]

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 Bundle Supervisor instruments, however now it’s even highly effective & has it is personal life (I imply repository). 😉

Alternatively Vapor already had a considerably related strategy 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 strategy rather a lot.

Let me present you a easy howdy command:


import ArgumentParser

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

    func run() throws {
        print("Hi there (self.identify)!")
    }
}
HelloCommand.major()

Now I will present you easy methods to implement an identical command utilizing Vapor:


import Vapor

ultimate class HelloCommand: Command {
    
    let assist = "This command will say howdy to a given identify."

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

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

public func configure(_ app: Utility) throws {
    app.instructions.use(HelloCommand(), as: "howdy")
}

As you’ll be able to see they nearly appear like the identical.

Should you love scripting, it is best to positively verify swift-sh and Brisk

The Swift Argument Parser library is a light-weight answer in case you are solely in search of a easy Swift script. A very good instance is a instrument that manipulates information on the system or one thing related. It is only one little dependency, nevertheless it removes a lot boilerplate out of your scripts. It permits you to give attention to the script itself, as a substitute of parsing the command line inputs. You’ll find extra detailed examples and an in depth documentation contained in the GitHub repository. 🙏

Vapor’s Command API is helpful if you wish to carry out extra sophisticated duties together with your scripts. Something that is a part of your Vapor software will be triggered from a command, so you’ll be able to simply create a backend instrument that reads (or writes) information from the database utilizing Fluent 4. That is the primary benefit of utilizing a Vapor command, as a substitute a standalone Swift script.

Arguments, choices, flags

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

Arguments are person supplied values learn so as (e.g. ./howdy joe bob john).

Now that the fundamental definitions, right here is the instance:

ultimate class HelloCommand: Command {
        
    struct Signature: CommandSignature {

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

        @Possibility(identify: "greeting", brief: "g", assist: "Greeting used")
        var greeting: String?

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

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

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

Arguments are required by default, choices and flags are optionals. You’ll be able to have a customized identify (brief and lengthy) for every thing, plus you’ll be able to customise the assistance message for each element.

swift run Run howdy john
# Hi there john!

swift run Run howdy john --greeting Hello
# Hello john!

swift run Run howdy john --greeting Hello --capitalized
# Hello John!

swift run Run howdy john -g Szia -c
# Szia John!

You’ll be able to name the command utilizing a number of kinds. Be at liberty to choose 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 means of subcommands. Utilities comparable to git and the Swift bundle supervisor are capable of present diverse interfaces for every of their sub-functions by implementing subcommands comparable to git department or swift bundle init.

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

ultimate class HelloCommand: Command {
    
    static var identify = "howdy"
        
    
}

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 optimization command group assist"

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

public func configure(_ app: Utility) throws {

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

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

swift run Run welcome howdy john --greeting "Hello" --capitalize

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

Ready for async duties

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

ultimate 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.software
        app.logger.discover("Creating todos...")
        
        let todo = Todo(title: "Look forward to async duties...")
        strive todo.create(on: app.db).wait()
        
        app.logger.discover("Todo is prepared.")
    }
}

There’s a throwing wait() methodology that you may make the most of to “keep within the loop” till every thing is completed. You can too get a pointer for the applying 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 speak about 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 use the underlying ConsoleKit by including it as a dependency.


import PackageDescription

let bundle = Bundle(
    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 major.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.")
    strive console.run(group, enter: enter)
}
catch {
    console.error("(error)")
    exit(1)
}

This fashion you’ll be able to eliminate a lot of the community associated core packages (which are included by default when you use Vapor). This strategy solely fetches swift-log as a 3rd celebration dependency. 😍

Abstract

ConsoleKit in Vapor is an effective way to write 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 keep up databases by means of scripts otherwise you carry out a number of networking or asynchronous operations it is perhaps higher to go along with Vapor, since you’ll be able to all the time develop by importing a brand new element from the ecosystem.

[ad_2]

LEAVE A REPLY

Please enter your comment!
Please enter your name here