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

0/5 No votes

Report this app



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


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)!")

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. ⭐️


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? {

    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: [
    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 {

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. 😍


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.


Leave a Reply

Your email address will not be published.

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