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

0/5 No votes

Report this app

Description

[ad_1]

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

Vapor

Swift Argument Parser vs Vapor Instructions

Apple open-sourced a brand new library that may assist you numerous 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). 😉

Then again Vapor already had a considerably comparable strategy to construct scripts, however in Vapor 4 the Command API is best than ever. Property Wrappers (accessible 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 whats up command:


import ArgumentParser

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

    func run() throws {
        print("Hey (self.title)!")
    }
}
HelloCommand.major()

Now I am going to present you how you can implement an identical command utilizing Vapor:


import Vapor

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

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

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

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

As you may see they virtually appear like the identical.


In the event you love scripting, you must positively test 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 superb instance is a instrument that manipulates information 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 means that you can 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 difficult duties together with your scripts. Something that is a part of your Vapor software might be triggered from a command, so you may simply create a backend instrument that reads (or writes) information from the database utilizing Fluent 4. That is the principle benefit of utilizing a Vapor command, as a substitute a stanadlone Swift script.




Arguments, choices, flags

Let’s prolong the whats up 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 simply give to the command or not. Each choices and flags begin with a single - or a double sprint --, often the only dashed model makes use of a brief title for a similar factor. 🤓

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

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

last class HelloCommand: Command {
        
    struct Signature: CommandSignature {

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

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

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

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

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

Arguments are required by default, choices and flags are optionals. You’ll be able to have a customized title (quick and lengthy) for every part, plus you may 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’ll be able to name the command utilizing a number of types. Be happy 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 means of subcommands. Utilities similar to git and the Swift package deal supervisor are in a position to present different interfaces for every of their sub-functions by implementing subcommands similar to git department or swift package deal init.

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

last class HelloCommand: Command {
    
    static var title = "whats up"
        
    
}

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

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

    init() {
        self.assist = "website positioning command group assist"

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

public func configure(_ app: Utility) throws {

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


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

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

In the event you learn the Swift Argument Parser docs, you may obtain the very same conduct by means of a customized CommandConfiguration. Personally, I want Vapor’s strategy right here… 🤷‍♂️



Ready for async duties

Vapor builds on high of SwiftNIO together with EventLoops, Futures & Guarantees. Many of the API is asynchronous, however within the CLI world it’s a must to watch for the async operations to complete.

last class TodoCommand: Command {
    
    static let title = "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: "Watch for async duties...")
        attempt todo.create(on: app.db).wait()
        
        app.logger.discover("Todo is prepared.")
    }
}

There’s a throwing wait() technique that you would be able to make the most of to “keep within the loop” till every part is finished. You too can get a pointer for the appliance object through the use of the present context. The app has the database connection, so you may inform Fluent to create a brand new mannequin. Additionally you should utilize 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 in addition bundles a number of different core issues. What if I simply need the goodies for my Swift scripts? No downside. You should utilize the underlying ConsoleKit by including it as a dependency.


import PackageDescription

let package deal = Package deal(
    title: "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 must 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.title, 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 fashion you may eliminate a lot of the community associated core packages (which can be included by default if you happen to use Vapor). This strategy solely fetches swift-log as a 3rd occasion dependency. 😍




Abstract

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


[ad_2]

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.