SDK for creating Telegram Bots in Swift.

Overview

Swift Chat Platform License Build Status

ChatChangelogPrerequisitesGetting startedCreating a new botGenerating Xcode projectAPI overviewDebugging notesExamplesDocumentationSupportLicense

SDK for creating Telegram Bots in Swift.

Sample projects:

Shopping list bot.

Word reverse bot.

Trivial bot:

import TelegramBotSDK

let bot = TelegramBot(token: "my token")
let router = Router(bot: bot)

router["greet"] = { context in
    guard let from = context.message?.from else { return false }
    context.respondAsync("Hello, \(from.firstName)!")
    return true
}

router[.newChatMembers] = { context in
    guard let users = context.message?.newChatMembers else { return false }
    for user in users {
        guard user.id != bot.user.id else { continue }
        context.respondAsync("Welcome, \(user.firstName)!")
    }
    return true
}

while let update = bot.nextUpdateSync() {
	try router.process(update: update)
}

fatalError("Server stopped due to error: \(bot.lastError)")

Telegram chat

Join our chat in Telegram: swiftsdkchat.

What's new

Release notes contain the significant changes in each release with migration notes.

Prerequisites

On OS X, use the latest Xcode 9 release.

On Linux, install Swift 4.2 or newer and libcurl4-openssl-dev package. Note that shopster-bot example won't build on Linux because GRDB doesn't support Linux yet, but otherwise the library should be functional.

Getting started

Please get familiar with the documentation on Telegram website:

Creating a new bot

In Telegram, add BotFather. Send him these commands:

/newbot
BotName
username_of_my_bot

BotFather will return a token.

Create a project for your bot:

mkdir hello-bot
cd hello-bot
swift package init --type executable

Create Package.swift:

// swift-tools-version:5.1
import PackageDescription

let package = Package(
    name: "hello-bot",
    products: [
        // Products define the executables and libraries produced by a package, and make them visible to other packages.
        .executable(
            name: "hello-bot",
            targets: ["hello-bot"]
        ),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
        .package(name: "TelegramBotSDK", url: "https://github.com/zmeyc/telegram-bot-swift.git", from: "2.0.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages which this package depends on.
        .target(
            name: "hello-bot",
            dependencies: ["TelegramBotSDK"]),
    ]
)

Create Sources/main.swift:

import Foundation
import TelegramBotSDK

let token = readToken(from: "HELLO_BOT_TOKEN")
let bot = TelegramBot(token: token)

while let update = bot.nextUpdateSync() {
    if let message = update.message, let from = message.from, let text = message.text {
        bot.sendMessageAsync(chatId: .chat(from.id),
                             text: "Hi \(from.firstName)! You said: \(text).\n")
    }
}

fatalError("Server stopped due to error: \(String(describing: bot.lastError))")

Do not commit your token to git!

readToken reads token from environment variable or from a file. So, either create an environment variable:

export HELLO_BOT_TOKEN='token'

Or save the token to a file and add the file to .gitignore:

echo token > HELLO_BOT_TOKEN

Build your bot:

swift build

And run it:

./.build/x86_64-apple-macosx10.10/debug/hello-bot

More details are available on Wiki: New Bot.

Generating Xcode project

It's easy:

swift package generate-xcodeproj

Open generated hello-bot.xcodeproj and switch the active scheme to the bottom one:

Don't forget to add your token to environment variables in Xcode (Scheme settings -> Run).

Press CMD-R to start the bot.

API overview

Type and request names

SDK type and request names closely mirror original Telegram ones.

Swift types and enums were added where appropriate:

if entity.type == .botCommand { ... }

In most cases raw methods accepting strings are also available. They can be used as fallbacks if required enum case is not added yet:

if entity.typeString == "bot_command" { ... }

To allow accessing fields which are still missing in SDK, every data type has json member with original json structure:

if entity.json["type"].stringValue == "bot_command" { ... }

All types conform to JsonConvertible protocol and can be created from json or serialized back to json. Use debugDescription method for human-readable json or description for json which can be sent to server.

Requests

Sync and Async

Request names closely mirror Telegram ones, but have two versions: synchronous and asynchronous with method suffixes Sync and Async correspondingly.

  • Synchronous methods block until the operation is completed.
let fromId: ChatId = .chat(12345678) // your user id
bot.sendMessageSync(fromId, "Hello!") // blocks until the message is sent
bot.sendMessageSync(fromId, "Bye.")

These methods return a server response or nil in case of error. If nil is returned, details can be obtained by querying bot.lastError.

guard let sentMessage = bot.sendMessageSync(fromId, "Hello") else {
    fatalError("Unable to send message: \(bot.lastError.unwrapOptional)")
}

Do not use synchronous methods in real apps because they're slow. Use them when debugging or for experimenting in REPL. More details: Using Swift REPL for calling API methods

  • Asynchronous methods accept an optional completion handler which will be called when operation is completed.

Completion handler is called on main thread by default.

bot.sendMessageAsync(fromId, "Hello!") { result, error in
  // message sent!
  bot.sendMessageAsync(fromId, "Bye.")
}
// execution continues immediately

In completion handler result contains the server response or nil in case of error. Details can be obtained by querying error.

For simplicity, it's possible to synchronously process messages, but respond asynchronously to avoid blocking the processing of the next message. So, a typical bot's main loop can look like this:

while let update = bot.nextUpdateSync() {
  // process the message and call Async methods
}

Request parameters

Parameter names should be specified explicitly in most cases:

bot.sendLocationAsync(chat_id: chatId, latitude: 50.4501, longitude: 30.5234)

Exception to this are sendMessageSync/Async and respondSync/Async functions which are used very often. Parameter names can be omitted in them:

bot.sendMessageAsync(chatId: chatId, text: "Text")
bot.sendMessageAsync(chatId, "Text") // will also work

Optional parameters can also be passed:

let markup = ForceReply()
bot.sendMessageAsync(chatId: chatId, text: "Force reply",
    reply_markup: markup, disable_notification: true)

If you ever encounter a situation when parameter hasn't been added to method signature yet, you can pass a dictionary with any parameters at the end of parameter list:

let markup = ForceReply()
bot.sendMessageAsync(chatId: chatId, text: "Force reply",
    ["reply_markup": markup, "disable_notification": true])

It's also possible to set default parameter values for a request:

bot.defaultParameters["sendMessage"] = ["disable_notification": true]

In dictionaries nil values will be treated as no value and won't be sent to Telegram server.

Available requests

Check TelegramBot/Requests subdirectory for a list of available requests.

If you find a missing request, please create a ticket and it will be added. Until then, an arbitrary unsupported endpoint can be called like this:

let user: User? = requestSync("sendMessage", ["chat_id": chatId, "text": text])

Or async version:

() in ... } ">
requestAsync("sendMessage", ["chat_id": chatId, "text": text]) { (result: User?, error: DataTaskError?) -> () in
    ...
}

These methods automatically deserialize the json response.

Explicitly specifying result type is important. Result type should conform to JsonConvertible protocol. Bool and Int already conform to JsonConvertible.

JSON class itself also conforms to JsonConvertible, so you can request a raw json if needed:

let user: JSON? = requestSync("sendMessage", ["chat_id": chatId, "text": text])

Routing

Router maps text commands and other events to their handler functions and helps parsing command arguments.

let router = Router(bot)
router["command1"] = handler1
router["command2"] = handler2
router[.event] = handler3
...
router.process(update: update)

Multiple commands can be specified in a single rule:

router["Full Command Name", "command"] = handler

Multiword commands are also supported:

router["list add"] = onListAdd
router["list remove"] = onListRemove

Routers can be chained. This helps creating a context-sensitive routers with fallback to a global router.

router1.unmatched = router2.handler

Handlers

Handlers take Context argument and return Bool.

  • If handler returns true, command matching stops.
  • If handler returns false, other paths will be matched.

So, in handler check preconditions and return false if they aren't satisfied:

router["reboot"] = { context in
    guard let fromId = context.fromId where isAdmin(fromId) else { return false }

    context.respondAsync("I will now reboot the PC.") { _ in
        reboot()
    }

    return true
}

Handler functions can be marked as throws and throw exceptions. Router won't process them and will simply pass the exceptions to caller.

Context is a request context, it contains:

  • bot - a reference to the bot.
  • update - current Update structure.
  • message - convenience method for accessing update.message. If update.message is nil, fallbacks to update.edited_message, then to update.callback_query?.message.
  • command - command without slash.
  • slash - true, if command was prefixed with a slash. Useful if you want to skip commands not starting with slash in group chats.
  • args - command arguments scanner.
  • properties - context sensitive properties. Pass them to process method:
var properties = [String: AnyObject]()
properties["myField"] = myValue
try router.process(update: update, properties: properties)

And use them in handlers:

func myHandler(context: Context) -> Bool {
    let myValue = context.properties["myField"] as? MyValueType
    // ...
}

Or make a Context category for easier access to your properties, for example:

extension Context {
    var session: Session { return properties["session"] as! Session }
}

Context also contains a few helper methods and variables:

  • privateChat - true, if this is a private chat with bot, false for all group chat types.
  • chatId - shortcut for message?.chat.id. If message is nil, tries to retrieve chatId from other Update fields.
  • fromId - shortcut for message?.from?.id. If message is nil, tries to retrieve fromId from other Update fields.
  • respondAsync, respondSync - works as sendMessage(chatId, ...)
  • respondPrivatelyAsync/Sync("text", groupText: "text") - respond to user privately, sending a short message to the group if this was a group chat. For example:
context.respondPrivatelyAsync("Command list: ...",
    groupText: "Please find a list of commands in a private message.")
  • reportErrorAsync/Sync(text: "User text", errorDescription: "Detailed error description for administrator") - sends a short message to user and prints detailed error description to a console. text parameter can be omitted, in which case user will receive a generic error message.

Text commands

Router can match text commands:

router["start"] = onStart

Command name is processed differently in private and group chats:

  • In private chats slash is optional. start matches /start as well as start.
  • It group chats 'start' only matches /start.

This can be overridden. The following line will require slash even in private chats:

router["start", .slashRequired] = onStart

Router is case-insensitive by default. To make it case-sensitive, pass .caseSensitive option:

router["command", .caseSensitive] = handler

Multiple options can be passed:

router["command", [.slashRequired, .caseSensitive]] = handler

In Telegram group chats, user can append bot name to a command, for example: /greet@hello_bot. Router takes care of removing the @hello_bot part from command name automatically.

Text commands with arguments

Words can be captured and then processed by using scanWord method.

router["two_words"] = { context in
    let word1 = context.args.scanWord()
    let word2 = context.args.scanWord()
}

Array of words can be captured using scanWords:

router["words"] = { context in
    let words = context.args.scanWords() // returns [String] array
}

Numbers can be captured using scanInt, scanInt64 and scanDouble. restOfString captures the remainder as a single string.

router["command"] = { context in
    let value1 = context.args.scanInt()
    let value2 = context.args.scanDouble()
    let text = context.args.scanRestOfString()
}

It's also possible to directly access NSScanner used for scanning arguments: context.args.scanner.

Handler is expected to read all the arguments, otherwise user will see a warning: Part of your input was ignored: text

So, for example, if there's a command swap which expects two arguments but user types: /swap aaa bbb ccc, he will see:

bbb aaa
Part of your input was ignored: ccc

A possible way to avoid the warning is to skip unneeded arguments by calling context.args.skipRestOfString().

Also, the warning can be overridden:

router.partialMatch = { context in
    context.respondAsync("Part of your input was ignored: \(context.args.scanRestOfString())")
    return true
}

Other events

Router can handle other event types as well. For example, when new user joins the chat, .new_chat_member path will be triggered:

router[.new_chat_member] = { context in
    guard let users = context.message?.newChatMembers else { return false }
    for user in users {
        guard user.id != bot.user.id else { return false }
        context.respondAsync("Welcome, \(user.firstName)!")
    }
    return true
}

Check TelegramBot/Router/ContentType.swift file for a complete list of events supported by Router.

Handling unmatched paths

If no paths were matched, router will call it's unmatched handler, which will print "Command not found" by default. This can be overridden by setting an explicit handler:

router.unmatched = { context in
    // Do something else with context.args
    return true
}

Debugging notes

In debugger you may want to dump the contents of a json structure, but debugDescription loses it's formatting.

prettyPrint helper function allows printing any JsonConvertible with indentation:

let user: User
user.prettyPrint()

bot.sendMessageSync(fromId, "Hello!")?.prettyPrint()

Examples

There are 3 example projects available:

  • Examples/hello-bot - a trivial bot which responds to /greet command and greets users who join the chat.

  • Examples/word-reverse-bot - demonstrates how to handle start and stop requests, keep session state and parse command arguments. Behaves differently in private and group chats. Uses a router and a controller.

  • Examples/shopster-bot - maintains a shopping list using sqlite3 database. Allows creating shared shopping lists in group chats. GRDB library is used for working with database.

Details on compiling and running the bots are available on Wiki: Building and running the example projects.

Documentation

Additional documentation is available on Telegram Bot Swift SDK Wiki.

Check Examples/ for sample bot projects.

This SDK is a work in progress, expect the API to change very often.

Need help?

Please submit an issue on Github.

If you miss a specific feature, please create an issue and it will be prioritized. Pull Requests are also welcome.

Talk with other developers in our Telegram chat: swiftsdkchat.

Happy coding!

License

Apache License Version 2.0 with Runtime Library Exception. Please see LICENSE.txt for more information.

Comments
  • error: use of unresolved identifier 'CURLOPT_WRITEDATA'

    error: use of unresolved identifier 'CURLOPT_WRITEDATA'

    Hello, I try to run example on ubuntu 14.04 on IBM bluemix cloud foundry. Following error appears there and on my local ubuntu server 14.04. Maybe you can give some advice what it can be? On what environment do you test Linux build? maybe you have some ready docker container you use?

    saveliy@ubuntu:~/terst/telegram-bot-swift/Examples/hello-bot$ swift build
    warning: minimum recommended clang is version 3.6, otherwise you may encounter linker errors.
    Cloning /home/saveliy/terst/telegram-bot-swift
    HEAD is now at 5f2730a Update changelog
    Resolved version: 0.14.0
    Cloning https://github.com/zmeyc/CCurl.git
    HEAD is now at 7ef2701 Include stdint.h
    Resolved version: 0.0.2
    Cloning https://github.com/zmeyc/SwiftyJSON.git
    HEAD is now at 54c7a31 Fix warning on Linux
    Resolved version: 12.1.4
    Cloning https://github.com/smud/ScannerUtils.git
    HEAD is now at 26015cb Comment out failing "Hello World" test function
    Resolved version: 1.0.6
    Compile Swift Module 'ScannerUtils' (2 sources)
    Compile Swift Module 'SwiftyJSON' (2 sources)
    Compile Swift Module 'TelegramBot' (134 sources)
    /home/saveliy/terst/telegram-bot-swift/Examples/hello-bot/Packages/telegram-bot-swift-0.14.0/Sources/TelegramBot/TelegramBot.swift:228:40: error: use of unresolved identifier 'CURLOPT_WRITEDATA'
            curl_easy_setopt_pointer(curl, CURLOPT_WRITEDATA, &callbackData)
                                           ^~~~~~~~~~~~~~~~~
    CCurl.CURLOPT_IOCTLDATA:1:12: note: did you mean 'CURLOPT_IOCTLDATA'?
    public var CURLOPT_IOCTLDATA: CURLoption { get }
               ^
    CCurl.CURLOPT_WRITEINFO:1:12: note: did you mean 'CURLOPT_WRITEINFO'?
    public var CURLOPT_WRITEINFO: CURLoption { get }
               ^
    <unknown>:0: error: build had 1 command failures
    error: exit(1): /home/saveliy/swift/usr/bin/swift-build-tool -f /home/saveliy/terst/telegram-bot-swift/Examples/hello-bot/.build/debug.yaml
    
    opened by savelii 19
  • Error when building with swift package manager

    Error when building with swift package manager

    When building a new project using swift build with your SDK as a dependency, I get this error: https://pastebin.com/0rpzMgFi

    This is my Package.swift: https://pastebin.com/FDPg2tzE

    I was first using Swift 4.2.1 but also tried updating to Swift 5.0.1, which didn't help.

    My main.swift only contains these two lines:

    import TelegramBotSDK
    
    print("Hello, world!")
    
    opened by iComputerfreak 7
  • Swift build error

    Swift build error

    That's what I did:

    swift package init --type executable added a dependency in Package.swift swift build

    And it throws a hundreds of errors, like: /opt/local/include/curl/system.h:399:12: note: while building module 'Darwin' imported from /opt/local/include/curl/system.h:399: # include ^ :338:9: note: in file included from :338: #import "ncurses.h" ^ /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/ncurses.h:141:10: note: in file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/ncurses.h:141: #include ^ /opt/local/include/unctrl.h:60:63: error: unknown type name 'SCREEN' NCURSES_EXPORT(NCURSES_CONST char ) NCURSES_SP_NAME(unctrl) (SCREEN, chtype); ^ /opt/local/include/curl/system.h:399:12: note: while building module 'Darwin' imported from /opt/local/include/curl/system.h:399: '#' include ^ ...

    My Package.swift:

    import PackageDescription
    
    let package = Package(
        name: "todo-bot",
        dependencies: [
            // Dependencies declare other packages that this package depends on.
            // .package(url: /* package url */, from: "1.0.0"),
            .package(url: "https://github.com/zmeyc/telegram-bot-swift.git", from: "0.0.0")
        ],
        targets: [
            // Targets are the basic building blocks of a package. A target can define a module or a test suite.
            // Targets can depend on other targets in this package, and on products in packages which this package depends on.
            .target(
                named: "todo-bot",
                dependencies: ["telegram-bot-swift"]),
        ]
    )
    
    
    opened by EgorKolyshkin 7
  • BOT won't start.

    BOT won't start.

    program out:

    ndpoint: getMe, data: endpoint: getUpdates, data: limit=100&timeout=60 Fatal error: Server stopped due to error: Optional(Codable failed to decode result): zsh: illegal hardware instruction .build/debug/cityhelper

    I see an update.prettyPrint() in the sample code, but this option is not supported in version 2.0.0 of the library :(

    opened by hdcola 5
  • Keyboards not working

    Keyboards not working

    Hi! I'm trying to use reply markups with InlineKeyboardMarkup and ReplyKeyboardMarkup, but is not working for both types.

    In the first place it doesn't allow me to reach empty init, but still if I try to create buttons and markups with the initializers present (json and data), I can see that rawDictionary contains the values that I'm using, but the parameter reply_markup in the URL is sent empty and of course the buttons will not appear in the chat.

    Thank you

    opened by Alexsilvacodes 5
  • Fatal error: Server stopped due to error: Hü…

    Fatal error: Server stopped due to error: Hü…

    Sorry for the vague title of this issue.

    I test my bot with a fresh token (a new bot) and it works fine. But when I switched to my old one, it always throws an weird error:

    截屏2021-08-10 下午11.49.50.png

    Based on my digging, it was a decoding error:

    Error: keyNotFound(CodingKeys(stringValue: "location", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "result", intValue: nil), _JSONKey(stringValue: "Index 1", intValue: 1), CodingKeys(stringValue: "chosenInlineResult", intValue: nil)], debugDescription: "No value associated with key CodingKeys(stringValue: \"location\", intValue: nil) (\"location\").", underlyingError: nil))
    

    But how could it possibly run properly on one bot while generates error on another one?

    So I compared their settings via @botfather. The only difference is Inline feedback. The failed bot is set to 100% and the other one is 0.

    So maybe the parameter chosenInlineResult.location should be an Optional?

    opened by Butanediol 3
  • Bot not working on Ubuntu 16.04 with Swift 5.2.4

    Bot not working on Ubuntu 16.04 with Swift 5.2.4

    When running my bot (which uses your API v2.1.0) on Ubuntu 16.04, the API's getUpdates request does not work. When starting the bot I get the following output:

    user@hostname:~/NotifierBot$ ./Notifier
    Installation Directory: /home/user/NotifierBot
    endpoint: getMe, data: 
    endpoint: getUpdates, data: 
    endpoint: getUpdates, data: 
    endpoint: getUpdates, data: 
    endpoint: getUpdates, data: 
    endpoint: getUpdates, data: 
    endpoint: getUpdates, data: 
    

    When I run the same bot on macOS 10.15 (Catalina), it works like expected:

    Installation Directory: [...]
    endpoint: getMe, data: 
    endpoint: getUpdates, data: timeout=60&limit=100
    

    After every getUpdates request, the bot waits 60 seconds or until someone uses a command. On Ubuntu, the bot just spams the getUpdates requests (2 at a time, every two second).

    If I use a command, while the bot runs on Ubuntu, the bot tries to send the reply infinitely (but no message is received by me in Telegram).

    endpoint: sendMessage, data: disable_notification=true&text=THE_MESSAGE&disable_web_page_preview=true
    endpoint: getUpdates, data: 
    

    This happens more than once per second.

    Both machines use Swift 5.2.4 My Bot: https://github.com/iComputerfreak/NotifierBot

    opened by iComputerfreak 3
  • Handling live location updates

    Handling live location updates

    Hey there! I'm note really sure what is the best way to handle live location updates, can somebody help me here?

    So what I'm trying to achieve is following: when the user shares his live location I want my bot to do something every time when the location changes. When I just start sharing my live location, first event I can handle by doing

    router[.location] = { context in ... }
    

    But when the new location comes I get Unsupported content type. Is there is another way to catch this events except router.unsupportedContentType = { context in } handler?

    Thanks in advance.

    opened by iSapozhnik 3
  • How to recover from error on `nextUpdateSync`

    How to recover from error on `nextUpdateSync`

    In all the examples and documentation if method nextUpdateSync returns nil. Proposed way to behave is to log error and exit. But what to do if I want to recover from error by, for instance, restarting bot after 5 minutes. Can you give an example of how it can be done?

    It is important to me because sometimes telegram servers return 504, and I don't want to shut down bot because of that.

    opened by zapko 3
  • New package not showing up in Xcode dependencies

    New package not showing up in Xcode dependencies

    In package.swift I added .Package(url: "https://github.com/Alamofire/Alamofire.git", majorVersion: 3) I then ran swift build in terminal and the package showed up in the sources folder in finder However, in the dependencies tab of the Xcode project, Alamofire doesn't show up, and I can't import it into main.swift either. Is there a way to add it in build phases or something like that?

    opened by simonnarang 3
  • rangeOfString function not working

    rangeOfString function not working

    I am unable to call the rangeOfString function for the command string. The error I get is value of type 'String' has no member 'rangeOfString' I don't know why this is happening, I am using swift 2.2 snapshot 4-12 and it runs fine in playground

    opened by simonnarang 3
  • Fatal error: Server stopped due to error: nil: file Bot/main.swift

    Fatal error: Server stopped due to error: nil: file Bot/main.swift

    Hello, I just noticed that all of my projects which include this library started throwing this error for some unknown reason. Example code:

    import Foundation
    import TelegramBotSDK
    
    let bot = TelegramBot(token: "TOKEN")
    let router = Router(bot: bot)
    
    router["start"] = { context in
        guard let from = context.message?.from else { return false }
        context.respondAsync("Hello!")
        return true
    }
    
    fatalError("Server stopped due to error: \(bot.lastError)") // throws error at this line, bot.lastError is nil, I guess
    

    Is there a way to fix this?

    opened by ghost 2
  • Error response 400 in Raspberry Pi. Chat_id not included in request

    Error response 400 in Raspberry Pi. Chat_id not included in request

    when compiled and run in a Raspi 2, (armhf, Swift5.1). The requests are generated without the chat_id, for some reason.

    Could be rogue behaviour or HTTPUtils.formUrlencode, or curlPerformRequest.

    opened by gvJaime 4
  • Correct method documentations

    Correct method documentations

    I'm not sure how method documentations are written/generated, but the Swift parameters are camelCased while the documentation parameters are underline_separated, which makes the documentation not show up in xCode.

    Here's an example: image image

    opened by dancojocaru2000 3
  • Write proper documentation

    Write proper documentation

    This is a requirement for next major version (2.0). We must write proper examples on how to handle user sessions, integrations with Vapor/Kitura/Other web frameworks, integrations with databases and various.

    enhancement 
    opened by cipi1965 0
  • Allow commands to start with different symbol

    Allow commands to start with different symbol

    - router["command"] : allow both "/command" and "command": typical usage
    - router["command", .exactMatch]: allow only "command": rare case
    - router [".command"]:  allow only ".command": special command sets
    - router["/command"]: allow only "/command": rare case
    

    In other words, the logic is: if it starts with alphanumeric, then '/' is optional, otherwise requires exact match.

    opened by zmeyc 0
Releases(v2.1.2)
Swift Bot with Vapor for Telegram Bot Api

Telegram Vapor Bot Please support Swift Telegram Vapor Bot Lib development by giving a ⭐️ Telegram Bot based on Swift Vapor. Swift Server Side Communi

OleG. 104 Jan 6, 2023
A (really) native and powerful macOS Telegram client built using SwiftUI, optimized for moderating large communities and personal use.

Moc A (really) native and powerful macOS Telegram client, optimized for moderating large communities and personal use. This client is currently in dev

GGorAA 84 Jan 2, 2023
👤 Framework to Generate Random Users - An Unofficial Swift SDK for randomuser.me

RandomUserSwift is an easy to use Swift framework that provides the ability to generate random users and their accompanying data for your Swift applic

Wilson Ding 95 Sep 9, 2022
CovidCertificate SDK for iOS

This is the Swiss implementation of the Electronic Health Certificates (EHN) Specification [1] used to verify the validity of Digital Covid Certificates. It is partly based on the reference implementation of EHN's ValidationCore

Swiss Admin 19 Apr 5, 2022
Unofficial iOS/macOS SDK for the Notion API.

NotionClient: a Notion SDK for iOS & macOS Unofficial Notion API SDK for iOS & macOS. This is an alpha version and still work in progress. TODO Featur

David De Bels 15 Aug 4, 2022
Desk360 Mobile Chat SDK for iOS

Desk360 Chat iOS SDK Desk360 Chat SDK provides simplicity and usability in one place. With this feature, you can provide live support to your customer

null 5 Sep 21, 2022
WANNA SDK enhances your iOS app with virtual try-on capabilities for shoes and watches

WANNA SDK enhances your iOS app with virtual try-on capabilities for shoes and watches. With this feature, your users will be able to see in real time how the selected product looks on them, just by pointing their smartphone camera at their feet or wrist.

Wannaby Inc. 18 Dec 2, 2022
Swift implementation of Github REST API v3

GitHubAPI Swift implementation of GitHub REST api v3. Library support Swift 4.2. Work is in progress. Currently supported: Issues API. Activity API(Fe

Serhii Londar 77 Jan 7, 2023
Google Directions API helper for iOS, written in Swift

PXGoogleDirections Google Directions API SDK for iOS, entirely written in Swift. ?? Features Supports all features from the Google Directions API as o

Romain L 268 Aug 18, 2022
Swift Reddit API Wrapper

reddift reddift is Swift Reddit API Wrapper framework, and includes a browser is developed using the framework. Supports OAuth2(is not supported on tv

sonson 236 Dec 28, 2022
Swifter - A Twitter framework for iOS & OS X written in Swift

Getting Started Installation If you're using Xcode 6 and above, Swifter can be installed by simply dragging the Swifter Xcode project into your own pr

Matt Donnelly 2.4k Dec 26, 2022
Instagram API client written in Swift

SwiftInstagram is a wrapper for the Instagram API written in Swift. It allows you to authenticate users and request data from Instagram effortlessly.

Ander Goig 580 Nov 25, 2022
Swift client for Kubernetes

Table of contents Overview Compatibility Matrix Examples Usage Creating a client Configuring a client Client authentication Client DSL Advanced usage

Swiftkube 94 Dec 14, 2022
Instagram Private API Swift

SwiftyInsta Please notice SwiftyInsta may not be actively maintained at the moment of you reading this note. Refer to #244 for more info. Instagram of

Mahdi Makhdumi 218 Jan 5, 2023
A Swift client for the OpenAI API.

OpenAI A Swift client for the OpenAI API. Requirements Swift 5.3+ An OpenAI API Key Example Usage Completions import OpenAI

Mattt 161 Dec 26, 2022
Solana + RxSolana This is a open source library on pure swift for Solana protocol

The objective is to create a cross platform, fully functional, highly tested and less depencies as posible. The project is still at initial stage. Lots of changes chan happen to the exposed api.

Arturo Jamaica 138 Dec 15, 2022
Fetch Multiple Rest API using Swift 5.5 Async Await with Task, TaskGroup, Continuation API

Source code for Tutorial on experimenting with Swift Async Await to fetch multiple REST API endpoints and eliminate Pyramid of Doom callback hell to improve code readability and maintanability

Alfian Losari 14 Dec 7, 2022
QuoteKit is a Swift framework to use the free APIs provided by Quotable created by Luke Peavey.

QuoteKit The QuoteKit is a Swift framework to use the free APIs provided by Quotable created by Luke Peavey.

Rudrank Riyam 17 Jun 23, 2022
Swift library for the Twitter API v1 and v2

Swift library for the Twitter API v1 and v2

mironal 96 Dec 30, 2022