🐦 An asynchronous Twitter library based on the Twitter v2 API

Overview

Twift

Twitter API v2 badge Documentation Coverage

Twift is an asynchronous Swift library for the Twitter v2 API.

  • No external dependencies
  • Only one callback-based method (requestUserCredentials)
  • Full Swift type definitions/wrappers around Twitter's API objects

Quick Start Guide

To be completed

Requirements

To be completed

Documentation

You can find the full documentation in this repo's Wiki (auto-generated by SwiftDoc).

Comments
  • Refresh token issues for oAuth2

    Refresh token issues for oAuth2

    I've been running into an issue with refresh tokens. I have no issues logging in for the user, but I'm finding if I come back several hours later I'm unauthorized and have to initiate the login process all over again.

    This is what I'm running at start of the update in my AppDelegate. Do I need to refreshOAuth2AccessToken at initiateLogin?

    func initiateLogin(forceReconnect: Bool = false, completion: @escaping (Bool)->Void) {
         Task {
             try await container.client?.refreshOAuth2AccessToken() // I don't know if this will do anything, but I'm trying.
             await loginUser(forceReconnect: forceReconnect, completion: { user in
    
                 if let encoded = try? self.encoder.encode(user) {
                     self.defaults.set(encoded, forKey: ConstantStrings.authKeyChainString)
                     self.initClient(withCredentials: user)
                     completion(true)
                 }
           })
         }
       }
    
    
         func loginUser(forceReconnect: Bool = false, completion: @escaping (OAuth2User)->Void) async {
         do {
           // flow with existing user
             if let savedUser = defaults.object(forKey: ConstantStrings.authKeyChainString) as? Data {
                 if let oauthUser = try? decoder.decode(OAuth2User.self, from: savedUser), !forceReconnect {
                     completion(oauthUser)
                 } else {
                     // flow with new user
                     let oauthUser = try await Twift.Authentication().authenticateUser(
                       clientId: TWITTER_clientId,
                       redirectUri: URL(string: TWITTER_CALL_BACKURL)!,
                       scope: Set(OAuth2Scope.allCases),
                       presentationContextProvider: nil)
                     completion(oauthUser)
                   }
             }
         } catch {
           print(error.localizedDescription)
         }
       }
    
    
       func initClient(withCredentials oauthUser: OAuth2User) {
           container.client = Twift(oauth2User: oauthUser, onTokenRefresh: { newUser in
               if let encoded = try? self.encoder.encode(newUser) {
                   self.defaults.set(encoded, forKey: ConstantStrings.authKeyChainString)
               }
           })
       }
    
    opened by arbyruns 18
  • Using Previews

    Using Previews

    Good morning,

    Am I missing something here? I am trying to feed a User array into my preview, but for the life of me I cannot get this thing to work. Below is a snippet, the error is "Type Twift has no member User", however this a nearly exact copy of the results received from the api call. Thoughts.

    struct FollowingView_Previews: PreviewProvider { static var previews: some View { let users: [User] = [Twift.User(id: "1445771133337235470", name: "Oppenheimer", username: "OppenheimerFilm", createdAt: Date(), protected: false, withheld: WithheldInformation, location: "nowhere", pinnedTweetId: "", url: "", description: "", verified: "", entities: "", profileImageUrl: "", publicMetrics: "")] FollowingView(users: users) } }

    opened by damartin1 15
  • Add

    Add "Create a List" method

    Create List method was lacking from the "Manage Lists" group. https://developer.twitter.com/en/docs/twitter-api/lists/manage-lists/introduction

    Not sure If this is the correct way to do it, but I tried to follow the same approach as for some other similar methods I saw inside Twift.

    @daneden Note 👇 The main concern on my end is: "How do I test this?" 😅 So far I've only worked on personal packages and changing branches was easy 👌 However, when contributing I do not know how to test it without having to do quite a bit of duplication 😅

    opened by roblack 15
  • Add contentMediaType for variants object

    Add contentMediaType for variants object

    Unfortunately I was not able to find proper spec in the Twitter API for this before, and only way to really test this is to have it in the package and use it.

    Or could we somehow test this in the demo app @daneden ?

    As for this PR, I presumed that mediaType and contentType are the same, however from a bit of testing it turns you types slightly differ in strings, so we needed a new enum to handle that.

    opened by roblack 7
  • Refresh token/access possible issue

    Refresh token/access possible issue

    I have an issue where I am not sure If I am doing anything wrong or if there is an issue with 2.0 token.

    When I initiate the app and login by authorizing the user like so:

    let oauthUser = try await Twift.Authentication().authenticateUser(
         clientId: Constants.clientID,
         redirectUri: URL(string: Constants.urlScheme)!,
         scope: Set(OAuth2Scope.allCases),
         presentationContextProvider: nil)
    client = Twift(.oauth2UserAuth(oauthUser))
    UserDefaults.encodeUser(user: oauthUser)
    self.oauthUser = oauthUser
    completion(true)
    

    Everything works fine (UserDefaults storing is temporary)

    But after launching the app for example...few hours later, same build in xcode, I use the path:

    if let oauthUser = UserDefaults.decodeUser() {
                    client = Twift(.oauth2UserAuth(oauthUser))
                    completion(true)
    

    However, the call I make after this, using the said client, fails to get a response other than Unauthorised

    When I follow the call, refresh is not used as authToken is valid, and by checking expiresIn myself, I saw that is true.

    So, seems that the client is not initiated/authorized then? The only difference in two flows is that first one uses authenticateUser and second one does not, but I am storing that user properly (I read it before and after storing and it seems 👌)

    Here is the call that gets invalid response" https://api.twitter.com/2/users/me?user.fields=description,profile_image_url with token: Bearer akNhMEZxTklrSU1ZV19TVS1qM2FSenRmdmdlWm9OZ0x6dTd6WktzUWlzZmE0OjE2NTQxMTE1MDg1NTE6MTowOmF0OjE

    Update: If I perform the force refresh, everything is fine 🤷‍♂️. client?.refreshOAuth2AccessToken() So maybe the Twift(.oauth2UserAuth(oauthUser)) just needs to be async?

    Hope I am not talking out my ass here, just typing this as I debug 😂

    opened by roblack 6
  • Unable to call into polls data

    Unable to call into polls data

    I'm trying to capture Poll data and having issues accessing the options portion. I'm accurately tagging posts with polls, but can't pull in the actual data.

    I'm also pulling in poll data in the expansion

    expansions: [.authorId(userFields: [\.profileImageUrl, \.verified]), .mediaKeys(mediaFields: [\.id, \.url, \.width, \.height, \.previewImageUrl]), .pollIds(pollFields: [\.id, \.options, \.endDatetime, \.votingStatus])],

    Any thoughts?

      /// Contains objects describing each choice in the referenced poll.
      public let options: [Option]
    

    Here's a rough sample of the code I'm just trying to get up and running

    
                   if let pollKeys = tweet.attachments?.pollIds {
                            ForEach(pollKeys, id: \.self) { key in
                                if let media = includes?.polls {
                                    ForEach(media){ poll in
                                        if poll.id == key {
                                            ForEach(poll.option, id: \.position) { item in
                                                Text(item.label)
                                            }
                                        }
                                    }
                                }
    
                            }
                        }
    
    
    
    opened by arbyruns 5
  • Update Twift+Streams.swift

    Update Twift+Streams.swift

    Fix "Expression is 'async' but is not marked with 'await'" error by adding await keyword at return of 'volumeStream' and 'filteredStream' functions

    opened by Qusea 5
  • Refresh Token Issue

    Refresh Token Issue

    Not sure if my implementation is not correct or if in the SPM itself, but still having the same refresh token issues 🤷‍♂️ Posting here just in case as these days I am quite in a time-crunch so will surely forget 😅

    Issue: After access token has expired, it either does not refresh properly or new token is not propagated.

    opened by roblack 5
  • Submitting to appstore requires the ability to report post

    Submitting to appstore requires the ability to report post

    I was rejected from the app store since I did not have a way for content to be reported. Just a heads up for other users that maybe using Twift.

    Guideline 1.2 - Safety - User Generated Content

    We found in our review that your app includes user-generated content but does not have all the required precautions. Apps with user-generated content must take specific steps to moderate content and prevent abusive behavior.

    Next Steps

    To resolve this issue, please revise your app to implement the following precautions:

    • Require that users agree to terms (EULA) and these terms must make it clear that there is no tolerance for objectionable content or abusive users

    • A mechanism for users to flag objectionable content

    Resources

    Learn more about our policies for user-generated content in App Store Review Guideline 1.2.

    opened by arbyruns 4
  • Fix token expiry date

    Fix token expiry date

    As detailed in this issue, token was getting new date on every encode/decode, therefore never expiring.

    This PR omits setting the expiresAt date and tries to only set it during first authentication and refresh.

    After this, we might want to explore the option of a force refresh if 401 response is received. That way expiry would never really need to be logged as we can always try with the old token and refresh if the bad response is received.

    opened by roblack 4
  • 'List' is ambiguous for type lookup in this context

    'List' is ambiguous for type lookup in this context

    There seems to be a collision for the List type, whenever I use it I get the following error.

    Maybe I am missing some simple solution to this? I know that if there is a name collision with other types you could say Twift.List, but here, all List types seem to be from Twift, but registered as different?

    Do advise :) Thank you!

    image
    opened by roblack 4
  • Linux Support

    Linux Support

    Swift Server folks might want to use this package, and most likely will be deploying via linux. Swift linux does not have the Foundation and CryptoKit frameworks. But there are implementations for linux called FoundationNetworking and Crypto which have the same API.

    Adding support should be as easy as adding

    #if canImport(FoundationNetworking)
    import FoundationNetworking
    #endif
    

    and

    Importing Crypto over CryptoKit

    opened by abdulajet 2
  • Add missing API methods

    Add missing API methods

    opened by daneden 0
Releases(v0.2.2)
  • v0.2.2(Aug 15, 2022)

    What's Changed

    • Fix contentMedia decoding for variants object by @roblack in https://github.com/daneden/Twift/pull/47

    Full Changelog: https://github.com/daneden/Twift/compare/v0.2.1...v0.2.2

    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(Aug 12, 2022)

    What's Changed

    • Update Twift+Streams.swift by @Qusea in https://github.com/daneden/Twift/pull/36
    • Extend media Type with variants property by @roblack in https://github.com/daneden/Twift/pull/44
    • Make variant properties accessible by @roblack in https://github.com/daneden/Twift/pull/45
    • Fix OAuth token refreshing by @daneden in https://github.com/daneden/Twift/pull/43

    New Contributors

    • @Qusea made their first contribution in https://github.com/daneden/Twift/pull/36

    Full Changelog: https://github.com/daneden/Twift/compare/v0.2.0...v0.2.1

    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Jun 10, 2022)

    What's Changed

    • New convenience initialisers
    • Make entities pertaining to urls, hashtags and mentions public by @roblack in https://github.com/daneden/Twift/pull/28
    • Make tag and mention properties public and accessible by @roblack in https://github.com/daneden/Twift/pull/29
    • Enable access for token refresh by @roblack in https://github.com/daneden/Twift/pull/31

    Full Changelog: https://github.com/daneden/Twift/compare/v0.1.2...v0.2.0

    Source code(tar.gz)
    Source code(zip)
  • v0.1.2(May 23, 2022)

    What's Changed

    • Rename property to use snake_case by @roblack in https://github.com/daneden/Twift/pull/26
    • Make authenticateUser function throwing by @Tunous in https://github.com/daneden/Twift/pull/27

    Full Changelog: https://github.com/daneden/Twift/compare/v0.1.1...v0.1.2

    Source code(tar.gz)
    Source code(zip)
  • v0.1.1(May 21, 2022)

    What's Changed

    • make mediaKeys and pollIds accessible to the user by @roblack in https://github.com/daneden/Twift/pull/22
    • Add reverse chronological timeline method, tests, and test views

    Full Changelog: https://github.com/daneden/Twift/compare/v0.1.0...v0.1.1

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Apr 30, 2022)

    I’m excited to publish this version of Twift as pre-1.0 stable!

    Now that Twift covers all but a handful of the v2 Twitter API endpoints and has a complete test suite, it’s ready for more broad use.

    What to expect for the v1.0 release

    Stable v1.0 of Twift is still going to take some time, mostly due to some major missing endpoints in Twitter's V2 API (specifically media endpoints). v1.0 of Twift will properly deprecate OAuth 1.0a user authentication in favour of OAuth 2.0.

    What's missing from this release

    The only v2 endpoints missing from this release are the compliance and tweet count endpoints, because frankly I’m impatient, and those endpoints seem less commonly-used than others. As always, contributions are welcome!

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0-beta.5(Apr 2, 2022)

    Beta 5 of Twift is a potentially breaking change that introduces OAuth 2.0 as the preferred authentication method.

    The new authentication function, Twift.Authentication().authenticateUser, is an async method unlike the callback-based OAuth 1.0a method. Media methods don't support OAuth 2.0, so have been marked as deprecated. In a future version of Twift, only OAuth 2.0 will be supported.

    What's Changed

    • Pass correct callback URL scheme to authentication by @Tunous in https://github.com/daneden/Twift/pull/4
    • Add demo app by @daneden in https://github.com/daneden/Twift/pull/14
    • Add "Create a List" method by @roblack in https://github.com/daneden/Twift/pull/7
    • Add OAuth 2.0 user authentication by @daneden in https://github.com/daneden/Twift/pull/16

    New Contributors

    • @Tunous made their first contribution in https://github.com/daneden/Twift/pull/4
    • @daneden made their first contribution in https://github.com/daneden/Twift/pull/14
    • @roblack made their first contribution in https://github.com/daneden/Twift/pull/7

    Full Changelog: https://github.com/daneden/Twift/compare/v0.1.0-beta.4...v0.1.0-beta.5

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0-beta.4(Jan 26, 2022)

    Beta 4 of Twift adds a stable uploadMedia method, and a helper method checkMediaUploadSuccessful for checking the processing status of large media.

    Full Changelog: https://github.com/daneden/Twift/compare/v0.1.0-beta.3...v0.1.0-beta.4

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0-beta.3(Jan 23, 2022)

    This release is an early preview of Twift, containing all the Twitter v2 API methods except the following:

    • PUT /2/lists/:id
    • POST /2/lists
    • GET /2/tweets/counts/all
    • GET /2/tweets/counts/recent
    • GET /2/compliance/jobs
    • GET /2/compliance/jobs/:id
    • POST /2/compliance/jobs

    That means you get the following types and methods: Users, Tweets, Polls, Spaces, Mutes, Blocks, Follows, Retweets, Lists*, Likes, Streams, reply hiding, and timelines!

    Please take Twift for a spin in your project and provide any feedback by opening issues and pull requests

    🚨 Call for contributions

    In order to make this library more complete, I need help getting Twitter's v1.1 media upload methods working! This is the area that needs the most attention; if anyone has experience working with the Twitter v1.1 API, I would greatly appreciate the help!

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0-beta.2(Jan 11, 2022)

Owner
Daniel Eden
Designer, writing & thinking about Design Systems.
Daniel Eden
Github iOS Client based on Github REST V3 API and GraphQL V4 API

ZLGithubClient Github iOS 客户端 by Existorlive Objective-c 2.0 Swift 5 Cocoapods 1.9.1 iOS >= 11.0 基于 Github REST V3 API 和 Github GraphQL V4 API 开发的iOS客

朱猛 46 Sep 4, 2022
Enables easy, convenient asynchronous asset loading in RealityKit for many different kinds of assets.

RealityKit Asset Loading Discussion This package includes classes and examples that enable easy, convenient asynchronous asset loading in RealityKit f

Grant Jarvis 3 Feb 13, 2022
This is a simple mobile app which is connect to the Twitter API

Project 3 - My Twitter My Twitter is a basic twitter app to read your tweets. Time spent on two parts: 8.5 hours spent in total Twitter - Part II This

Alem 1 Jun 12, 2022
Pexels API client library for the Swift programming language.

Pexels-Swift Pexels.com API client library for the Swift programming language. Overview This Swift Package is a wrapper for Pexels API to get access t

Lukas Pistrol 4 Sep 1, 2022
A Swift library for Discord REST/Gateway API in all platforms.

swift-discord main develop A Swift library for Discord API. Package Products Discord, alias library that contains DiscordREST, DiscordGateway. Discord

swift-discord 2 Aug 10, 2022
The Swift code generator for your assets, storyboards, Localizable.strings, … — Get rid of all String-based APIs!

SwiftGen SwiftGen is a tool to automatically generate Swift code for resources of your projects (like images, localised strings, etc), to make them ty

null 8.2k Sep 21, 2022
Type-based input validation.

Ensure Type-based input validation try Ensure<PackageIsCool>(wrappedValue: packages.ensure) Validators A Validator is a type that validates an input.

Build Passed 5 Jan 22, 2022
🛠 A flexible and easy template created to speed up the development of your iOS application based on the MVP pattern.

Model-View-Presenter template A flexible and easy template created to speed up the development of your iOS application based on the MVP pattern. This

Tamerlan Satualdypov 20 Mar 9, 2022
Control Nvidia jetbot which is based on Jetson Nano via iOS app

jetbot-remote-control This is very basic example project which control Nvidia Jetbot remotely via iOS app Based on jetbot of Nvidia, adding sample sou

Nguyen Quoc Thanh 13 Oct 6, 2021
XCode Preview template for UIkit based project.

SwiftPreview XCode Preview template for UIkit based project. Support custom file template class inherit from UIView and UIViewController. How to use?

Won Heo 10 Mar 31, 2022
Lightweight app to view your WoT (BB, Blitz) stats (XVM based)

KTTC Lite Приложение для танкистов, следящих за своей статистикой! Функционал Базовая статистика аккаунта WoT, WoT Blitz Расширенная статистика XVM (W

Ярослав Стрельников 3 Aug 31, 2022
This repository hosts the PushwooshGeozones iOS SDK as an XCFramework based Swift Package.

This repository hosts the PushwooshGeozones iOS SDK as an XCFramework based Swift Package. Use this repository's Swift Package in Xcode 12+

Pushwoosh 2 Nov 23, 2021
A navigation frameword based on the Coordinator pattern and is a compact version from XCoordinator.

Coordinator A navigation frameword based on the Coordinator pattern and is a compact version from XCoordinator. Example To run the example project, cl

Duc Pham 3 Jul 9, 2022
iPad Comic reader based on ComicFLow

Overview Finally a comic reader for iPad done right! ComicFlow was designed with one goal in mind: providing the best experience for comic fans with l

Pablo Clemente Pérez 0 Dec 2, 2021
A GUI based virtualisation tool for running Linux on macOS Big Sur (x86 or arm64)

Project Mendacius GUI based virtualization tool to run Linux, based on the Virtualization framework introduced by Apple for macOS Big Sur with support

Praneet 111 Sep 1, 2022
UIKit-based app project template for Swift Playgrounds 4

playgrounds-uikit-app This is a simplistic sample template for Swift Playgrounds 4 to begin with a UIKit-based app delegate & window scene instead of

Steven Troughton-Smith 39 Sep 19, 2022
OpenAPI specification generator for Vapor based Swift projects.

VaporToOpenAPI VaporToOpenAPI is a Swift library which can generate output compatible with OpenAPI version 3.0.1 from Vapor code. You can use generate

null 2 Aug 31, 2022
GraphQL based Jetpack Compose, Wear Compose and SwiftUI Kotlin Multiplatform sample

GraphQL based Jetpack Compose, Wear Compose and SwiftUI Kotlin Multiplatform sample

John O'Reilly 145 Sep 6, 2022
Contacts is an iOS app based on MVP (Model View Presenter) software architectural pattern.

Contacts Description Contacts is an iOS app based on MVP (Model View Presenter) software architectural pattern. Run Requirements Xcode 10.2.1 Swift 5.

Tirupati Balan 4 Apr 26, 2022