From a2cefd9bb6492d407b2f35d8ca1d73ed5cdba729 Mon Sep 17 00:00:00 2001 From: Alexander Kauer Date: Thu, 9 Oct 2025 08:13:20 +0200 Subject: [PATCH 01/12] Added endpoints example --- .github/workflows/testing.yaml | 28 + .gitignore | 113 ++++ EndpointsExample.xcodeproj/project.pbxproj | 546 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/swiftpm/Package.resolved | 33 ++ .../xcschemes/EndpointsExample.xcscheme | 111 ++++ .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 + .../Assets.xcassets/Contents.json | 6 + EndpointsExample/DI.swift | 17 + EndpointsExample/EndpointsExampleApp.swift | 24 + .../ExampleAsyncReactor/ExampleReactor.swift | 41 ++ .../ExampleReactorView.swift | 26 + .../ExampleMVVM/ExampleModel.swift | 5 + .../ExampleMVVM/ExampleView.swift | 25 + .../ExampleMVVM/ExampleViewModel.swift | 36 ++ EndpointsExample/Networking/API.swift | 32 + .../Networking/HTTPBinClient.swift | 21 + .../Networking/ManipulatedHTTPBinClient.swift | 40 ++ .../Networking/PostmanEchoClient.swift | 19 + .../Preview Assets.xcassets/Contents.json | 6 + .../EndpointsExampleTests.swift | 35 ++ 23 files changed, 1203 insertions(+) create mode 100644 .github/workflows/testing.yaml create mode 100644 .gitignore create mode 100644 EndpointsExample.xcodeproj/project.pbxproj create mode 100644 EndpointsExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 EndpointsExample.xcodeproj/xcshareddata/xcschemes/EndpointsExample.xcscheme create mode 100644 EndpointsExample/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 EndpointsExample/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 EndpointsExample/Assets.xcassets/Contents.json create mode 100644 EndpointsExample/DI.swift create mode 100644 EndpointsExample/EndpointsExampleApp.swift create mode 100644 EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift create mode 100644 EndpointsExample/ExampleAsyncReactor/ExampleReactorView.swift create mode 100644 EndpointsExample/ExampleMVVM/ExampleModel.swift create mode 100644 EndpointsExample/ExampleMVVM/ExampleView.swift create mode 100644 EndpointsExample/ExampleMVVM/ExampleViewModel.swift create mode 100644 EndpointsExample/Networking/API.swift create mode 100644 EndpointsExample/Networking/HTTPBinClient.swift create mode 100644 EndpointsExample/Networking/ManipulatedHTTPBinClient.swift create mode 100644 EndpointsExample/Networking/PostmanEchoClient.swift create mode 100644 EndpointsExample/Preview Content/Preview Assets.xcassets/Contents.json create mode 100644 EndpointsExampleTests/EndpointsExampleTests.swift diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml new file mode 100644 index 0000000..cec22c6 --- /dev/null +++ b/.github/workflows/testing.yaml @@ -0,0 +1,28 @@ +name: Test + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + test: + name: Run Tests + runs-on: macos-15 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Select Xcode + run: sudo xcode-select -s /Applications/Xcode_26.0.0.app/Contents/Developer + + - name: Build and Test + run: | + xcodebuild test \ + -project EndpointsExample.xcodeproj \ + -scheme EndpointsExample \ + -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' \ + -enableCodeCoverage YES \ + | xcpretty && exit ${PIPESTATUS[0]} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b8a6972 --- /dev/null +++ b/.gitignore @@ -0,0 +1,113 @@ +# Xcode +# + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +# *.xcodeproj +# +# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata +# hence it is not needed unless you have added a package configuration file to your project +# .swiftpm + +.build/ + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +# Pods/ +# +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build/ + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ + +# macOS +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/EndpointsExample.xcodeproj/project.pbxproj b/EndpointsExample.xcodeproj/project.pbxproj new file mode 100644 index 0000000..47f6ac1 --- /dev/null +++ b/EndpointsExample.xcodeproj/project.pbxproj @@ -0,0 +1,546 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + 8211A84D2AFBDBFD00A36244 /* AsyncReactor in Frameworks */ = {isa = PBXBuildFile; productRef = 8211A84C2AFBDBFD00A36244 /* AsyncReactor */; }; + 82BA531E29DEE73D00F7726A /* Endpoints in Frameworks */ = {isa = PBXBuildFile; productRef = 82BA531D29DEE73D00F7726A /* Endpoints */; }; + FA1376D02E97832400AB27E1 /* Endpoints in Frameworks */ = {isa = PBXBuildFile; productRef = FA1376CF2E97832400AB27E1 /* Endpoints */; }; + FA1376D32E97839F00AB27E1 /* Endpoints in Frameworks */ = {isa = PBXBuildFile; productRef = FA1376D22E97839F00AB27E1 /* Endpoints */; }; + FA1376DA2E97849000AB27E1 /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = FA1376D92E97848C00AB27E1 /* .gitignore */; }; + FAD06B6B2E8C1C8C00E87155 /* Injection in Frameworks */ = {isa = PBXBuildFile; productRef = FAD06B6A2E8C1C8C00E87155 /* Injection */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 82BA52FE29DEE35D00F7726A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 82BA52E529DEE35C00F7726A /* Project object */; + proxyType = 1; + remoteGlobalIDString = 82BA52EC29DEE35C00F7726A; + remoteInfo = EndpointsTestbed; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 82BA52ED29DEE35C00F7726A /* EndpointsExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EndpointsExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 82BA52FD29DEE35D00F7726A /* EndpointsExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = EndpointsExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + FA1376D92E97848C00AB27E1 /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + FA07EB582E977E6900D9EA84 /* EndpointsExample */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = EndpointsExample; + sourceTree = ""; + }; + FA07EB672E977E6F00D9EA84 /* EndpointsExampleTests */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = EndpointsExampleTests; + sourceTree = ""; + }; + FA1376D42E9783AA00AB27E1 /* .github */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = .github; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + 82BA52EA29DEE35C00F7726A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FAD06B6B2E8C1C8C00E87155 /* Injection in Frameworks */, + FA1376D02E97832400AB27E1 /* Endpoints in Frameworks */, + 8211A84D2AFBDBFD00A36244 /* AsyncReactor in Frameworks */, + FA1376D32E97839F00AB27E1 /* Endpoints in Frameworks */, + 82BA531E29DEE73D00F7726A /* Endpoints in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 82BA52FA29DEE35D00F7726A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 82BA52E429DEE35C00F7726A = { + isa = PBXGroup; + children = ( + FA1376D92E97848C00AB27E1 /* .gitignore */, + FA1376D42E9783AA00AB27E1 /* .github */, + FA07EB582E977E6900D9EA84 /* EndpointsExample */, + FA07EB672E977E6F00D9EA84 /* EndpointsExampleTests */, + 82BA52EE29DEE35C00F7726A /* Products */, + 82BA531C29DEE73D00F7726A /* Frameworks */, + ); + sourceTree = ""; + }; + 82BA52EE29DEE35C00F7726A /* Products */ = { + isa = PBXGroup; + children = ( + 82BA52ED29DEE35C00F7726A /* EndpointsExample.app */, + 82BA52FD29DEE35D00F7726A /* EndpointsExampleTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 82BA531C29DEE73D00F7726A /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 82BA52EC29DEE35C00F7726A /* EndpointsExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 82BA531129DEE35D00F7726A /* Build configuration list for PBXNativeTarget "EndpointsExample" */; + buildPhases = ( + 82BA52E929DEE35C00F7726A /* Sources */, + 82BA52EA29DEE35C00F7726A /* Frameworks */, + 82BA52EB29DEE35C00F7726A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + FA07EB582E977E6900D9EA84 /* EndpointsExample */, + FA1376D42E9783AA00AB27E1 /* .github */, + ); + name = EndpointsExample; + packageProductDependencies = ( + 82BA531D29DEE73D00F7726A /* Endpoints */, + 8211A84C2AFBDBFD00A36244 /* AsyncReactor */, + FAD06B6A2E8C1C8C00E87155 /* Injection */, + FA1376CF2E97832400AB27E1 /* Endpoints */, + FA1376D22E97839F00AB27E1 /* Endpoints */, + ); + productName = EndpointsTestbed; + productReference = 82BA52ED29DEE35C00F7726A /* EndpointsExample.app */; + productType = "com.apple.product-type.application"; + }; + 82BA52FC29DEE35D00F7726A /* EndpointsExampleTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 82BA531429DEE35D00F7726A /* Build configuration list for PBXNativeTarget "EndpointsExampleTests" */; + buildPhases = ( + 82BA52F929DEE35D00F7726A /* Sources */, + 82BA52FA29DEE35D00F7726A /* Frameworks */, + 82BA52FB29DEE35D00F7726A /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 82BA52FF29DEE35D00F7726A /* PBXTargetDependency */, + ); + fileSystemSynchronizedGroups = ( + FA07EB672E977E6F00D9EA84 /* EndpointsExampleTests */, + ); + name = EndpointsExampleTests; + productName = EndpointsTestbedTests; + productReference = 82BA52FD29DEE35D00F7726A /* EndpointsExampleTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 82BA52E529DEE35C00F7726A /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1430; + LastUpgradeCheck = 2600; + TargetAttributes = { + 82BA52EC29DEE35C00F7726A = { + CreatedOnToolsVersion = 14.3; + }; + 82BA52FC29DEE35D00F7726A = { + CreatedOnToolsVersion = 14.3; + TestTargetID = 82BA52EC29DEE35C00F7726A; + }; + }; + }; + buildConfigurationList = 82BA52E829DEE35C00F7726A /* Build configuration list for PBXProject "EndpointsExample" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 82BA52E429DEE35C00F7726A; + packageReferences = ( + 8211A84B2AFBDBFD00A36244 /* XCRemoteSwiftPackageReference "AsyncReactor" */, + FAD06B692E8C1C8C00E87155 /* XCRemoteSwiftPackageReference "Injection" */, + FA1376D12E97839F00AB27E1 /* XCRemoteSwiftPackageReference "Endpoints" */, + ); + preferredProjectObjectVersion = 77; + productRefGroup = 82BA52EE29DEE35C00F7726A /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 82BA52EC29DEE35C00F7726A /* EndpointsExample */, + 82BA52FC29DEE35D00F7726A /* EndpointsExampleTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 82BA52EB29DEE35C00F7726A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FA1376DA2E97849000AB27E1 /* .gitignore in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 82BA52FB29DEE35D00F7726A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 82BA52E929DEE35C00F7726A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 82BA52F929DEE35D00F7726A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 82BA52FF29DEE35D00F7726A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 82BA52EC29DEE35C00F7726A /* EndpointsExample */; + targetProxy = 82BA52FE29DEE35D00F7726A /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 82BA530F29DEE35D00F7726A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 28TM58T3GZ; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_STRICT_CONCURRENCY = complete; + }; + name = Debug; + }; + 82BA531029DEE35D00F7726A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = 28TM58T3GZ; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_STRICT_CONCURRENCY = complete; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 82BA531229DEE35D00F7726A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"EndpointsExample/Preview Content\""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.EndpointsTestbed; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_STRICT_CONCURRENCY = complete; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 82BA531329DEE35D00F7726A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"EndpointsExample/Preview Content\""; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.EndpointsTestbed; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_STRICT_CONCURRENCY = complete; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 82BA531529DEE35D00F7726A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.EndpointsTestbedTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/EndpointsExample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/EndpointsExample"; + }; + name = Debug; + }; + 82BA531629DEE35D00F7726A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.EndpointsTestbedTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/EndpointsExample.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/EndpointsExample"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 82BA52E829DEE35C00F7726A /* Build configuration list for PBXProject "EndpointsExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 82BA530F29DEE35D00F7726A /* Debug */, + 82BA531029DEE35D00F7726A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 82BA531129DEE35D00F7726A /* Build configuration list for PBXNativeTarget "EndpointsExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 82BA531229DEE35D00F7726A /* Debug */, + 82BA531329DEE35D00F7726A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 82BA531429DEE35D00F7726A /* Build configuration list for PBXNativeTarget "EndpointsExampleTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 82BA531529DEE35D00F7726A /* Debug */, + 82BA531629DEE35D00F7726A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 8211A84B2AFBDBFD00A36244 /* XCRemoteSwiftPackageReference "AsyncReactor" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/diamirio/AsyncReactor"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; + FA1376D12E97839F00AB27E1 /* XCRemoteSwiftPackageReference "Endpoints" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/diamirio/Endpoints"; + requirement = { + branch = "feature/swift-6.2"; + kind = branch; + }; + }; + FAD06B692E8C1C8C00E87155 /* XCRemoteSwiftPackageReference "Injection" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/diamirio/Injection"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.1.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 8211A84C2AFBDBFD00A36244 /* AsyncReactor */ = { + isa = XCSwiftPackageProductDependency; + package = 8211A84B2AFBDBFD00A36244 /* XCRemoteSwiftPackageReference "AsyncReactor" */; + productName = AsyncReactor; + }; + 82BA531D29DEE73D00F7726A /* Endpoints */ = { + isa = XCSwiftPackageProductDependency; + productName = Endpoints; + }; + FA1376CF2E97832400AB27E1 /* Endpoints */ = { + isa = XCSwiftPackageProductDependency; + productName = Endpoints; + }; + FA1376D22E97839F00AB27E1 /* Endpoints */ = { + isa = XCSwiftPackageProductDependency; + package = FA1376D12E97839F00AB27E1 /* XCRemoteSwiftPackageReference "Endpoints" */; + productName = Endpoints; + }; + FAD06B6A2E8C1C8C00E87155 /* Injection */ = { + isa = XCSwiftPackageProductDependency; + package = FAD06B692E8C1C8C00E87155 /* XCRemoteSwiftPackageReference "Injection" */; + productName = Injection; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 82BA52E529DEE35C00F7726A /* Project object */; +} diff --git a/EndpointsExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/EndpointsExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/EndpointsExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..013c6c6 --- /dev/null +++ b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,33 @@ +{ + "originHash" : "a5c9ad3e5f327f0629803f1e32f52744cd2fb5a3983831d7e59b2c02273a8ac1", + "pins" : [ + { + "identity" : "asyncreactor", + "kind" : "remoteSourceControl", + "location" : "https://github.com/diamirio/AsyncReactor", + "state" : { + "revision" : "e3fde7f9c1fb4db349039796c5c138571c71dadd", + "version" : "1.2.1" + } + }, + { + "identity" : "endpoints", + "kind" : "remoteSourceControl", + "location" : "https://github.com/diamirio/Endpoints", + "state" : { + "branch" : "feature/swift-6.2", + "revision" : "db7c5b2e91a45efdc8db5f9ae5f72851c13beb26" + } + }, + { + "identity" : "injection", + "kind" : "remoteSourceControl", + "location" : "https://github.com/diamirio/Injection", + "state" : { + "revision" : "57a66d3f21ff5564542a6b157838ae97b67447f0", + "version" : "1.1.0" + } + } + ], + "version" : 3 +} diff --git a/EndpointsExample.xcodeproj/xcshareddata/xcschemes/EndpointsExample.xcscheme b/EndpointsExample.xcodeproj/xcshareddata/xcschemes/EndpointsExample.xcscheme new file mode 100644 index 0000000..f121ec4 --- /dev/null +++ b/EndpointsExample.xcodeproj/xcshareddata/xcschemes/EndpointsExample.xcscheme @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/EndpointsExample/Assets.xcassets/AccentColor.colorset/Contents.json b/EndpointsExample/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/EndpointsExample/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/EndpointsExample/Assets.xcassets/AppIcon.appiconset/Contents.json b/EndpointsExample/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..13613e3 --- /dev/null +++ b/EndpointsExample/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/EndpointsExample/Assets.xcassets/Contents.json b/EndpointsExample/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/EndpointsExample/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/EndpointsExample/DI.swift b/EndpointsExample/DI.swift new file mode 100644 index 0000000..782ccde --- /dev/null +++ b/EndpointsExample/DI.swift @@ -0,0 +1,17 @@ +import Endpoints +import Foundation +import Injection + +@MainActor +enum DI { + static func register() { + let postmanSession = Session(with: PostmanEchoClient()) + DependencyInjector.register(postmanSession) + + let httpBinSession = Session(with: HTTPBinClient()) + DependencyInjector.register(httpBinSession) + + let manipulatedHttpBinSession = Session(with: ManipulatedHTTPBinClient()) + DependencyInjector.register(manipulatedHttpBinSession) + } +} diff --git a/EndpointsExample/EndpointsExampleApp.swift b/EndpointsExample/EndpointsExampleApp.swift new file mode 100644 index 0000000..984478b --- /dev/null +++ b/EndpointsExample/EndpointsExampleApp.swift @@ -0,0 +1,24 @@ +import AsyncReactor +import SwiftUI + +@main +struct EndpointsExampleApp: App { + init() { + DI.register() + } + + var body: some Scene { + WindowGroup { + NavigationStack { + List { + Section { + NavigationLink("MVVM", destination: ExampleView()) + NavigationLink("AsyncReactor", destination: ReactorView(ExampleReactor()) { + ExampleReactorView() + }) + } + } + } + } + } +} diff --git a/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift b/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift new file mode 100644 index 0000000..54307bc --- /dev/null +++ b/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift @@ -0,0 +1,41 @@ +import AsyncReactor +import Endpoints +import Foundation +import Injection + +class ExampleReactor: AsyncReactor { + enum Action { + case executeRequests + } + + struct State { + var text = "" + } + + @Published + private(set) var state = State() + + @Inject + var postmanSession: Session + + func action(_ action: Action) async { + switch action { + case .executeRequests: + await executeRequest() + } + } + + private func executeRequest() async { + do { + let (body, response) = try await postmanSession.dataTask( + for: PostmanEchoClient.ExampleGetCall() + ) + + guard response.statusCode == 200 else { return } + state.text = body.url + } catch { + guard let error = error as? EndpointsError else { return } + print(error.response?.statusCode ?? "") + } + } +} diff --git a/EndpointsExample/ExampleAsyncReactor/ExampleReactorView.swift b/EndpointsExample/ExampleAsyncReactor/ExampleReactorView.swift new file mode 100644 index 0000000..79be285 --- /dev/null +++ b/EndpointsExample/ExampleAsyncReactor/ExampleReactorView.swift @@ -0,0 +1,26 @@ +import AsyncReactor +import SwiftUI + +struct ExampleReactorView: View { + @EnvironmentObject var reactor: ExampleReactor + + var body: some View { + VStack { + if reactor.state.text.isEmpty { + ProgressView() + } else { + Text(reactor.state.text) + .font(.headline) + } + } + .onAppear { + reactor.send(.executeRequests) + } + } +} + +#Preview { + ReactorView(ExampleReactor()) { + ExampleReactorView() + } +} diff --git a/EndpointsExample/ExampleMVVM/ExampleModel.swift b/EndpointsExample/ExampleMVVM/ExampleModel.swift new file mode 100644 index 0000000..701fa8c --- /dev/null +++ b/EndpointsExample/ExampleMVVM/ExampleModel.swift @@ -0,0 +1,5 @@ +import Foundation + +struct ExampleModel: Codable { + var url: String +} diff --git a/EndpointsExample/ExampleMVVM/ExampleView.swift b/EndpointsExample/ExampleMVVM/ExampleView.swift new file mode 100644 index 0000000..80186fc --- /dev/null +++ b/EndpointsExample/ExampleMVVM/ExampleView.swift @@ -0,0 +1,25 @@ +import SwiftUI + +struct ExampleView: View { + @StateObject var viewModel = ExampleViewModel() + + var body: some View { + VStack { + if viewModel.text.isEmpty { + ProgressView() + } else { + Text(viewModel.text) + .font(.headline) + } + } + .onAppear { + viewModel.executeRequests() + } + } +} + +struct ExampleView_Previews: PreviewProvider { + static var previews: some View { + ExampleView() + } +} diff --git a/EndpointsExample/ExampleMVVM/ExampleViewModel.swift b/EndpointsExample/ExampleMVVM/ExampleViewModel.swift new file mode 100644 index 0000000..b0d50e4 --- /dev/null +++ b/EndpointsExample/ExampleMVVM/ExampleViewModel.swift @@ -0,0 +1,36 @@ +import Endpoints +import Foundation +import Injection + +@MainActor +class ExampleViewModel: ObservableObject { + @Published + var text: String = "" + + @Inject + var postmanSession: Session + + @Inject + var manipulatedHttpBinSession: Session + + func executeRequests() { + Task { + let (body, response) = try await postmanSession.dataTask( + for: PostmanEchoClient.ExampleGetCall() + ) + guard response.statusCode == 200 else { return } + + await MainActor.run { + self.text = body.url + } + } + + Task { + let (_, response) = try await manipulatedHttpBinSession.dataTask( + for: ManipulatedHTTPBinClient.GetStatusCode(deliveredStatusCode: 220) + ) + guard response.statusCode == 200 else { return } + print("Success") + } + } +} diff --git a/EndpointsExample/Networking/API.swift b/EndpointsExample/Networking/API.swift new file mode 100644 index 0000000..bdd8c75 --- /dev/null +++ b/EndpointsExample/Networking/API.swift @@ -0,0 +1,32 @@ +// +// API.swift +// EndpointsTestbed +// +// Created by Alexander Kauer on 11.09.25. +// + +import Endpoints +import Foundation + +actor API { + var postmanSession: Session + var httpBinSession: Session + var manipulatedHttpBinSession: Session + + init() { + let postmanClient = PostmanEchoClient() + self.postmanSession = Session(with: postmanClient) + + let httpBinClient = HTTPBinClient() + self.httpBinSession = Session(with: httpBinClient) + + let manipulatedHttpBinClient = ManipulatedHTTPBinClient() + self.manipulatedHttpBinSession = Session(with: manipulatedHttpBinClient) + } + + func loadData() async throws -> (ExampleModel, HTTPURLResponse) { + try await postmanSession.dataTask( + for: PostmanEchoClient.ExampleGetCall() + ) + } +} diff --git a/EndpointsExample/Networking/HTTPBinClient.swift b/EndpointsExample/Networking/HTTPBinClient.swift new file mode 100644 index 0000000..51b492f --- /dev/null +++ b/EndpointsExample/Networking/HTTPBinClient.swift @@ -0,0 +1,21 @@ +import Endpoints +import Foundation + +struct HTTPBinClient: Client { + var client: Client + + init() { + let url = URL(string: "https://httpbin.org/")! + self.client = AnyClient(baseURL: url) + } + + struct GetStatusCode: Call { + let deliveredStatusCode: Int + + typealias Parser = JSONParser + + var request: URLRequestEncodable { + Request(.get, "/status/\(deliveredStatusCode)") + } + } +} diff --git a/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift b/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift new file mode 100644 index 0000000..273bd5a --- /dev/null +++ b/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift @@ -0,0 +1,40 @@ +import Endpoints +import Foundation + +struct ManipulatedHTTPBinClient: Client { + var client: Client + + init() { + let url = URL(string: "https://httpbin.org/")! + self.client = AnyClient(baseURL: url) + } + + func encode(call: some Endpoints.Call) async throws -> URLRequest { + // Custom manipulation i.e. OAuth implementation + print("- MANIPULATED encode -") + return try await client.encode(call: call) + } + + func parse(response: HTTPURLResponse?, data: Data?, for call: C) async throws -> C.Parser.OutputType + where C: Call { + // Custom manipulation i.e. react on error responses or invalid tokens + print("- MANIPULATED parse -") + return try await client.parse(response: response, data: data, for: call) + } + + func validate(response: HTTPURLResponse?, data: Data?) async throws { + // Custom validation if needed + print("- MANIPULATED validate -") + return try await client.validate(response: response, data: data) + } + + struct GetStatusCode: Call { + typealias Parser = JSONParser + + let deliveredStatusCode: Int + + var request: URLRequestEncodable { + Request(.get, "/status/\(deliveredStatusCode)") + } + } +} diff --git a/EndpointsExample/Networking/PostmanEchoClient.swift b/EndpointsExample/Networking/PostmanEchoClient.swift new file mode 100644 index 0000000..d05bf2f --- /dev/null +++ b/EndpointsExample/Networking/PostmanEchoClient.swift @@ -0,0 +1,19 @@ +import Endpoints +import Foundation + +struct PostmanEchoClient: Client { + let client: Client + + init() { + let baseURL = URL(string: "https://postman-echo.com")! + self.client = AnyClient(baseURL: baseURL) + } + + struct ExampleGetCall: Call { + typealias Parser = JSONParser + + var request: URLRequestEncodable { + Request(.get, "/get") + } + } +} diff --git a/EndpointsExample/Preview Content/Preview Assets.xcassets/Contents.json b/EndpointsExample/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/EndpointsExample/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/EndpointsExampleTests/EndpointsExampleTests.swift b/EndpointsExampleTests/EndpointsExampleTests.swift new file mode 100644 index 0000000..4d8b019 --- /dev/null +++ b/EndpointsExampleTests/EndpointsExampleTests.swift @@ -0,0 +1,35 @@ +// +// EndpointsTestbedTests.swift +// EndpointsTestbedTests +// +// Created by Alexander Kauer on 06.04.23. +// + +@testable import EndpointsExample +import XCTest + +final class EndpointsExampleTests: XCTestCase { + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions + // afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + measure { + // Put the code you want to measure the time of here. + } + } +} From 0704915fd9aaf044ab6859fcc7a5fa90dee03f8f Mon Sep 17 00:00:00 2001 From: Alexander Kauer Date: Thu, 16 Oct 2025 14:29:14 +0200 Subject: [PATCH 02/12] Cleanup workflow --- .github/workflows/testing.yaml | 7 ++--- EndpointsExample.xcodeproj/project.pbxproj | 26 +++++++++---------- .../xcshareddata/swiftpm/Package.resolved | 11 +------- 3 files changed, 17 insertions(+), 27 deletions(-) diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index cec22c6..3b4366c 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -15,14 +15,15 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Select Xcode - run: sudo xcode-select -s /Applications/Xcode_26.0.0.app/Contents/Developer + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '26.0.1' - name: Build and Test run: | xcodebuild test \ -project EndpointsExample.xcodeproj \ -scheme EndpointsExample \ - -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' \ + -destination 'platform=iOS Simulator,name=iPhone 17,OS=latest' \ -enableCodeCoverage YES \ | xcpretty && exit ${PIPESTATUS[0]} diff --git a/EndpointsExample.xcodeproj/project.pbxproj b/EndpointsExample.xcodeproj/project.pbxproj index 47f6ac1..85242af 100644 --- a/EndpointsExample.xcodeproj/project.pbxproj +++ b/EndpointsExample.xcodeproj/project.pbxproj @@ -10,8 +10,8 @@ 8211A84D2AFBDBFD00A36244 /* AsyncReactor in Frameworks */ = {isa = PBXBuildFile; productRef = 8211A84C2AFBDBFD00A36244 /* AsyncReactor */; }; 82BA531E29DEE73D00F7726A /* Endpoints in Frameworks */ = {isa = PBXBuildFile; productRef = 82BA531D29DEE73D00F7726A /* Endpoints */; }; FA1376D02E97832400AB27E1 /* Endpoints in Frameworks */ = {isa = PBXBuildFile; productRef = FA1376CF2E97832400AB27E1 /* Endpoints */; }; - FA1376D32E97839F00AB27E1 /* Endpoints in Frameworks */ = {isa = PBXBuildFile; productRef = FA1376D22E97839F00AB27E1 /* Endpoints */; }; FA1376DA2E97849000AB27E1 /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = FA1376D92E97848C00AB27E1 /* .gitignore */; }; + FA1377002E978A9000AB27E1 /* Endpoints in Frameworks */ = {isa = PBXBuildFile; productRef = FA1376FF2E978A9000AB27E1 /* Endpoints */; }; FAD06B6B2E8C1C8C00E87155 /* Injection in Frameworks */ = {isa = PBXBuildFile; productRef = FAD06B6A2E8C1C8C00E87155 /* Injection */; }; /* End PBXBuildFile section */ @@ -57,7 +57,7 @@ FAD06B6B2E8C1C8C00E87155 /* Injection in Frameworks */, FA1376D02E97832400AB27E1 /* Endpoints in Frameworks */, 8211A84D2AFBDBFD00A36244 /* AsyncReactor in Frameworks */, - FA1376D32E97839F00AB27E1 /* Endpoints in Frameworks */, + FA1377002E978A9000AB27E1 /* Endpoints in Frameworks */, 82BA531E29DEE73D00F7726A /* Endpoints in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -125,7 +125,7 @@ 8211A84C2AFBDBFD00A36244 /* AsyncReactor */, FAD06B6A2E8C1C8C00E87155 /* Injection */, FA1376CF2E97832400AB27E1 /* Endpoints */, - FA1376D22E97839F00AB27E1 /* Endpoints */, + FA1376FF2E978A9000AB27E1 /* Endpoints */, ); productName = EndpointsTestbed; productReference = 82BA52ED29DEE35C00F7726A /* EndpointsExample.app */; @@ -182,7 +182,7 @@ packageReferences = ( 8211A84B2AFBDBFD00A36244 /* XCRemoteSwiftPackageReference "AsyncReactor" */, FAD06B692E8C1C8C00E87155 /* XCRemoteSwiftPackageReference "Injection" */, - FA1376D12E97839F00AB27E1 /* XCRemoteSwiftPackageReference "Endpoints" */, + FA1376FE2E978A9000AB27E1 /* XCLocalSwiftPackageReference "../Endpoints" */, ); preferredProjectObjectVersion = 77; productRefGroup = 82BA52EE29DEE35C00F7726A /* Products */; @@ -489,6 +489,13 @@ }; /* End XCConfigurationList section */ +/* Begin XCLocalSwiftPackageReference section */ + FA1376FE2E978A9000AB27E1 /* XCLocalSwiftPackageReference "../Endpoints" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = ../Endpoints; + }; +/* End XCLocalSwiftPackageReference section */ + /* Begin XCRemoteSwiftPackageReference section */ 8211A84B2AFBDBFD00A36244 /* XCRemoteSwiftPackageReference "AsyncReactor" */ = { isa = XCRemoteSwiftPackageReference; @@ -498,14 +505,6 @@ minimumVersion = 1.0.0; }; }; - FA1376D12E97839F00AB27E1 /* XCRemoteSwiftPackageReference "Endpoints" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/diamirio/Endpoints"; - requirement = { - branch = "feature/swift-6.2"; - kind = branch; - }; - }; FAD06B692E8C1C8C00E87155 /* XCRemoteSwiftPackageReference "Injection" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/diamirio/Injection"; @@ -530,9 +529,8 @@ isa = XCSwiftPackageProductDependency; productName = Endpoints; }; - FA1376D22E97839F00AB27E1 /* Endpoints */ = { + FA1376FF2E978A9000AB27E1 /* Endpoints */ = { isa = XCSwiftPackageProductDependency; - package = FA1376D12E97839F00AB27E1 /* XCRemoteSwiftPackageReference "Endpoints" */; productName = Endpoints; }; FAD06B6A2E8C1C8C00E87155 /* Injection */ = { diff --git a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 013c6c6..f5d9794 100644 --- a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "a5c9ad3e5f327f0629803f1e32f52744cd2fb5a3983831d7e59b2c02273a8ac1", + "originHash" : "17cad9ff9bd4b7f701f17d4c3c0f3c505388b263736cba348514e50050c1af7a", "pins" : [ { "identity" : "asyncreactor", @@ -10,15 +10,6 @@ "version" : "1.2.1" } }, - { - "identity" : "endpoints", - "kind" : "remoteSourceControl", - "location" : "https://github.com/diamirio/Endpoints", - "state" : { - "branch" : "feature/swift-6.2", - "revision" : "db7c5b2e91a45efdc8db5f9ae5f72851c13beb26" - } - }, { "identity" : "injection", "kind" : "remoteSourceControl", From 8bd46a05c1fd221f7ac900b0324390278219c1c3 Mon Sep 17 00:00:00 2001 From: Alexander Kauer Date: Thu, 16 Oct 2025 14:59:09 +0200 Subject: [PATCH 03/12] Swift 6.2 branch --- EndpointsExample.xcodeproj/project.pbxproj | 25 +++++++++++++------ .../xcshareddata/swiftpm/Package.resolved | 11 +++++++- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/EndpointsExample.xcodeproj/project.pbxproj b/EndpointsExample.xcodeproj/project.pbxproj index 85242af..97ecb36 100644 --- a/EndpointsExample.xcodeproj/project.pbxproj +++ b/EndpointsExample.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 8211A84D2AFBDBFD00A36244 /* AsyncReactor in Frameworks */ = {isa = PBXBuildFile; productRef = 8211A84C2AFBDBFD00A36244 /* AsyncReactor */; }; 82BA531E29DEE73D00F7726A /* Endpoints in Frameworks */ = {isa = PBXBuildFile; productRef = 82BA531D29DEE73D00F7726A /* Endpoints */; }; + FA00E2132EA1235900F4B75A /* Endpoints in Frameworks */ = {isa = PBXBuildFile; productRef = FA00E2122EA1235900F4B75A /* Endpoints */; }; FA1376D02E97832400AB27E1 /* Endpoints in Frameworks */ = {isa = PBXBuildFile; productRef = FA1376CF2E97832400AB27E1 /* Endpoints */; }; FA1376DA2E97849000AB27E1 /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = FA1376D92E97848C00AB27E1 /* .gitignore */; }; FA1377002E978A9000AB27E1 /* Endpoints in Frameworks */ = {isa = PBXBuildFile; productRef = FA1376FF2E978A9000AB27E1 /* Endpoints */; }; @@ -57,6 +58,7 @@ FAD06B6B2E8C1C8C00E87155 /* Injection in Frameworks */, FA1376D02E97832400AB27E1 /* Endpoints in Frameworks */, 8211A84D2AFBDBFD00A36244 /* AsyncReactor in Frameworks */, + FA00E2132EA1235900F4B75A /* Endpoints in Frameworks */, FA1377002E978A9000AB27E1 /* Endpoints in Frameworks */, 82BA531E29DEE73D00F7726A /* Endpoints in Frameworks */, ); @@ -126,6 +128,7 @@ FAD06B6A2E8C1C8C00E87155 /* Injection */, FA1376CF2E97832400AB27E1 /* Endpoints */, FA1376FF2E978A9000AB27E1 /* Endpoints */, + FA00E2122EA1235900F4B75A /* Endpoints */, ); productName = EndpointsTestbed; productReference = 82BA52ED29DEE35C00F7726A /* EndpointsExample.app */; @@ -182,7 +185,7 @@ packageReferences = ( 8211A84B2AFBDBFD00A36244 /* XCRemoteSwiftPackageReference "AsyncReactor" */, FAD06B692E8C1C8C00E87155 /* XCRemoteSwiftPackageReference "Injection" */, - FA1376FE2E978A9000AB27E1 /* XCLocalSwiftPackageReference "../Endpoints" */, + FA00E2112EA1235900F4B75A /* XCRemoteSwiftPackageReference "Endpoints" */, ); preferredProjectObjectVersion = 77; productRefGroup = 82BA52EE29DEE35C00F7726A /* Products */; @@ -489,13 +492,6 @@ }; /* End XCConfigurationList section */ -/* Begin XCLocalSwiftPackageReference section */ - FA1376FE2E978A9000AB27E1 /* XCLocalSwiftPackageReference "../Endpoints" */ = { - isa = XCLocalSwiftPackageReference; - relativePath = ../Endpoints; - }; -/* End XCLocalSwiftPackageReference section */ - /* Begin XCRemoteSwiftPackageReference section */ 8211A84B2AFBDBFD00A36244 /* XCRemoteSwiftPackageReference "AsyncReactor" */ = { isa = XCRemoteSwiftPackageReference; @@ -505,6 +501,14 @@ minimumVersion = 1.0.0; }; }; + FA00E2112EA1235900F4B75A /* XCRemoteSwiftPackageReference "Endpoints" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/diamirio/Endpoints"; + requirement = { + branch = "feature/swift-6.2"; + kind = branch; + }; + }; FAD06B692E8C1C8C00E87155 /* XCRemoteSwiftPackageReference "Injection" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/diamirio/Injection"; @@ -525,6 +529,11 @@ isa = XCSwiftPackageProductDependency; productName = Endpoints; }; + FA00E2122EA1235900F4B75A /* Endpoints */ = { + isa = XCSwiftPackageProductDependency; + package = FA00E2112EA1235900F4B75A /* XCRemoteSwiftPackageReference "Endpoints" */; + productName = Endpoints; + }; FA1376CF2E97832400AB27E1 /* Endpoints */ = { isa = XCSwiftPackageProductDependency; productName = Endpoints; diff --git a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index f5d9794..e1a014e 100644 --- a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "17cad9ff9bd4b7f701f17d4c3c0f3c505388b263736cba348514e50050c1af7a", + "originHash" : "06743052361b4b7a9ca66b7fa3c9fb2bb5e55d19a61ce2f13f2ac3dc267d3ada", "pins" : [ { "identity" : "asyncreactor", @@ -10,6 +10,15 @@ "version" : "1.2.1" } }, + { + "identity" : "endpoints", + "kind" : "remoteSourceControl", + "location" : "https://github.com/diamirio/Endpoints", + "state" : { + "branch" : "feature/swift-6.2", + "revision" : "f94349bf4489be4b4829c759aed302ed8e308ce0" + } + }, { "identity" : "injection", "kind" : "remoteSourceControl", From 04c3dc8e3907744643c57f310d6b7161fe1631d6 Mon Sep 17 00:00:00 2001 From: Alexander Kauer Date: Thu, 16 Oct 2025 16:11:06 +0200 Subject: [PATCH 04/12] Updated README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3e6ef6a..c19a938 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ -# Endpoints-Example -Example for Endpoints framework +# Endpoints Example + +This is an example iOS application demonstrating the [Endpoints](https://github.com/diamirio/Endpoints) framework - a type-safe, declarative way to define and consume HTTP endpoints in Swift. From 04cdc91956f7b2b71c63006d0b4c63a91c55962d Mon Sep 17 00:00:00 2001 From: Alexander Kauer Date: Thu, 30 Oct 2025 09:34:54 +0100 Subject: [PATCH 05/12] Updated example for Swift 6.2 Client protocol adoptions --- .../xcshareddata/swiftpm/Package.resolved | 2 +- EndpointsExample/DI.swift | 23 +++++++++----- .../ExampleAsyncReactor/ExampleReactor.swift | 6 ++-- .../ExampleMVVM/ExampleView.swift | 6 ++-- .../ExampleMVVM/ExampleViewModel.swift | 13 ++------ EndpointsExample/Networking/API.swift | 30 ++++++++++++------- .../Networking/HTTPBinClient.swift | 9 +----- .../Networking/ManipulatedHTTPBinClient.swift | 2 +- .../Networking/PostmanEchoClient.swift | 8 +---- 9 files changed, 46 insertions(+), 53 deletions(-) diff --git a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index e1a014e..1eadd70 100644 --- a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -16,7 +16,7 @@ "location" : "https://github.com/diamirio/Endpoints", "state" : { "branch" : "feature/swift-6.2", - "revision" : "f94349bf4489be4b4829c759aed302ed8e308ce0" + "revision" : "221eae9356e9d5d29f4f3fb519658f2be893982a" } }, { diff --git a/EndpointsExample/DI.swift b/EndpointsExample/DI.swift index 782ccde..418097d 100644 --- a/EndpointsExample/DI.swift +++ b/EndpointsExample/DI.swift @@ -5,13 +5,20 @@ import Injection @MainActor enum DI { static func register() { - let postmanSession = Session(with: PostmanEchoClient()) - DependencyInjector.register(postmanSession) - - let httpBinSession = Session(with: HTTPBinClient()) - DependencyInjector.register(httpBinSession) - - let manipulatedHttpBinSession = Session(with: ManipulatedHTTPBinClient()) - DependencyInjector.register(manipulatedHttpBinSession) + let postmanEchoUrl = URL(string: "https://postman-echo.com")! + let postmanClient = AnyClient(baseURL: postmanEchoUrl) + + let httpBinUrl = URL(string: "https://httpbin.org/")! + let httpBinClient = AnyClient(baseURL: httpBinUrl) + + let manipulatedHttpBinSession = ManipulatedHTTPBinClient() + + let api = ExampleAPI( + postmanClient: postmanClient, + httpBinClient: httpBinClient, + manipulatedHttpBinClient: manipulatedHttpBinSession + ) + + DependencyInjector.register(api, as: API.self) } } diff --git a/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift b/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift index 54307bc..2b44646 100644 --- a/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift +++ b/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift @@ -16,7 +16,7 @@ class ExampleReactor: AsyncReactor { private(set) var state = State() @Inject - var postmanSession: Session + private var api: API func action(_ action: Action) async { switch action { @@ -27,9 +27,7 @@ class ExampleReactor: AsyncReactor { private func executeRequest() async { do { - let (body, response) = try await postmanSession.dataTask( - for: PostmanEchoClient.ExampleGetCall() - ) + let (body, response) = try await api.loadExampleData() guard response.statusCode == 200 else { return } state.text = body.url diff --git a/EndpointsExample/ExampleMVVM/ExampleView.swift b/EndpointsExample/ExampleMVVM/ExampleView.swift index 80186fc..ddb46d3 100644 --- a/EndpointsExample/ExampleMVVM/ExampleView.swift +++ b/EndpointsExample/ExampleMVVM/ExampleView.swift @@ -18,8 +18,6 @@ struct ExampleView: View { } } -struct ExampleView_Previews: PreviewProvider { - static var previews: some View { - ExampleView() - } +#Preview { + ExampleView() } diff --git a/EndpointsExample/ExampleMVVM/ExampleViewModel.swift b/EndpointsExample/ExampleMVVM/ExampleViewModel.swift index b0d50e4..8e80ded 100644 --- a/EndpointsExample/ExampleMVVM/ExampleViewModel.swift +++ b/EndpointsExample/ExampleMVVM/ExampleViewModel.swift @@ -8,16 +8,11 @@ class ExampleViewModel: ObservableObject { var text: String = "" @Inject - var postmanSession: Session - - @Inject - var manipulatedHttpBinSession: Session + private var api: API func executeRequests() { Task { - let (body, response) = try await postmanSession.dataTask( - for: PostmanEchoClient.ExampleGetCall() - ) + let (body, response) = try await api.loadExampleData() guard response.statusCode == 200 else { return } await MainActor.run { @@ -26,9 +21,7 @@ class ExampleViewModel: ObservableObject { } Task { - let (_, response) = try await manipulatedHttpBinSession.dataTask( - for: ManipulatedHTTPBinClient.GetStatusCode(deliveredStatusCode: 220) - ) + let (_, response) = try await api.loadManipulatedData(deliveredStatusCode: 220) guard response.statusCode == 200 else { return } print("Success") } diff --git a/EndpointsExample/Networking/API.swift b/EndpointsExample/Networking/API.swift index bdd8c75..dbbe15a 100644 --- a/EndpointsExample/Networking/API.swift +++ b/EndpointsExample/Networking/API.swift @@ -8,25 +8,35 @@ import Endpoints import Foundation -actor API { - var postmanSession: Session - var httpBinSession: Session +protocol API: Actor { + func loadExampleData() async throws -> (ExampleModel, HTTPURLResponse) + func loadManipulatedData(deliveredStatusCode: Int) async throws -> (String, HTTPURLResponse) +} + +actor ExampleAPI: API { + var postmanSession: Session + var httpBinSession: Session var manipulatedHttpBinSession: Session - init() { - let postmanClient = PostmanEchoClient() + init( + postmanClient: AnyClient, + httpBinClient: AnyClient, + manipulatedHttpBinClient: ManipulatedHTTPBinClient, + ) { self.postmanSession = Session(with: postmanClient) - - let httpBinClient = HTTPBinClient() self.httpBinSession = Session(with: httpBinClient) - - let manipulatedHttpBinClient = ManipulatedHTTPBinClient() self.manipulatedHttpBinSession = Session(with: manipulatedHttpBinClient) } - func loadData() async throws -> (ExampleModel, HTTPURLResponse) { + func loadExampleData() async throws -> (ExampleModel, HTTPURLResponse) { try await postmanSession.dataTask( for: PostmanEchoClient.ExampleGetCall() ) } + + func loadManipulatedData(deliveredStatusCode: Int) async throws -> (String, HTTPURLResponse) { + try await manipulatedHttpBinSession.dataTask( + for: ManipulatedHTTPBinClient.GetStatusCode(deliveredStatusCode: deliveredStatusCode) + ) + } } diff --git a/EndpointsExample/Networking/HTTPBinClient.swift b/EndpointsExample/Networking/HTTPBinClient.swift index 51b492f..4a70f9b 100644 --- a/EndpointsExample/Networking/HTTPBinClient.swift +++ b/EndpointsExample/Networking/HTTPBinClient.swift @@ -1,14 +1,7 @@ import Endpoints import Foundation -struct HTTPBinClient: Client { - var client: Client - - init() { - let url = URL(string: "https://httpbin.org/")! - self.client = AnyClient(baseURL: url) - } - +enum HTTPBinClient { struct GetStatusCode: Call { let deliveredStatusCode: Int diff --git a/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift b/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift index 273bd5a..7447913 100644 --- a/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift +++ b/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift @@ -2,7 +2,7 @@ import Endpoints import Foundation struct ManipulatedHTTPBinClient: Client { - var client: Client + private var client: Client init() { let url = URL(string: "https://httpbin.org/")! diff --git a/EndpointsExample/Networking/PostmanEchoClient.swift b/EndpointsExample/Networking/PostmanEchoClient.swift index d05bf2f..413726f 100644 --- a/EndpointsExample/Networking/PostmanEchoClient.swift +++ b/EndpointsExample/Networking/PostmanEchoClient.swift @@ -1,14 +1,8 @@ import Endpoints import Foundation -struct PostmanEchoClient: Client { - let client: Client - - init() { - let baseURL = URL(string: "https://postman-echo.com")! - self.client = AnyClient(baseURL: baseURL) - } +enum PostmanEchoClient { struct ExampleGetCall: Call { typealias Parser = JSONParser From da1b5b8774203a5ab12a3d80ce38c76bb246a1cf Mon Sep 17 00:00:00 2001 From: Alexander Kauer Date: Thu, 30 Oct 2025 09:47:55 +0100 Subject: [PATCH 06/12] Adopted based on new Client protocol --- .../{DI.swift => DependencyInjection.swift} | 4 +++- EndpointsExample/EndpointsExampleApp.swift | 4 +++- .../ExampleAsyncReactor/ExampleReactor.swift | 2 ++ .../ExampleAsyncReactor/ExampleReactorView.swift | 2 ++ EndpointsExample/ExampleMVVM/ExampleModel.swift | 2 ++ EndpointsExample/ExampleMVVM/ExampleView.swift | 2 ++ EndpointsExample/ExampleMVVM/ExampleViewModel.swift | 2 ++ EndpointsExample/Networking/API.swift | 13 ++++--------- EndpointsExample/Networking/HTTPBinClient.swift | 2 ++ .../Networking/ManipulatedHTTPBinClient.swift | 2 ++ EndpointsExample/Networking/PostmanEchoClient.swift | 3 ++- EndpointsExampleTests/EndpointsExampleTests.swift | 7 +------ 12 files changed, 27 insertions(+), 18 deletions(-) rename EndpointsExample/{DI.swift => DependencyInjection.swift} (89%) diff --git a/EndpointsExample/DI.swift b/EndpointsExample/DependencyInjection.swift similarity index 89% rename from EndpointsExample/DI.swift rename to EndpointsExample/DependencyInjection.swift index 418097d..8d65646 100644 --- a/EndpointsExample/DI.swift +++ b/EndpointsExample/DependencyInjection.swift @@ -1,9 +1,11 @@ +// Copyright © 2025 DIAMIR. All Rights Reserved. + import Endpoints import Foundation import Injection @MainActor -enum DI { +enum DependencyInjection { static func register() { let postmanEchoUrl = URL(string: "https://postman-echo.com")! let postmanClient = AnyClient(baseURL: postmanEchoUrl) diff --git a/EndpointsExample/EndpointsExampleApp.swift b/EndpointsExample/EndpointsExampleApp.swift index 984478b..9848328 100644 --- a/EndpointsExample/EndpointsExampleApp.swift +++ b/EndpointsExample/EndpointsExampleApp.swift @@ -1,10 +1,12 @@ +// Copyright © 2025 DIAMIR. All Rights Reserved. + import AsyncReactor import SwiftUI @main struct EndpointsExampleApp: App { init() { - DI.register() + DependencyInjection.register() } var body: some Scene { diff --git a/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift b/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift index 2b44646..b80836a 100644 --- a/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift +++ b/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift @@ -1,3 +1,5 @@ +// Copyright © 2025 DIAMIR. All Rights Reserved. + import AsyncReactor import Endpoints import Foundation diff --git a/EndpointsExample/ExampleAsyncReactor/ExampleReactorView.swift b/EndpointsExample/ExampleAsyncReactor/ExampleReactorView.swift index 79be285..3f5916c 100644 --- a/EndpointsExample/ExampleAsyncReactor/ExampleReactorView.swift +++ b/EndpointsExample/ExampleAsyncReactor/ExampleReactorView.swift @@ -1,3 +1,5 @@ +// Copyright © 2025 DIAMIR. All Rights Reserved. + import AsyncReactor import SwiftUI diff --git a/EndpointsExample/ExampleMVVM/ExampleModel.swift b/EndpointsExample/ExampleMVVM/ExampleModel.swift index 701fa8c..b599384 100644 --- a/EndpointsExample/ExampleMVVM/ExampleModel.swift +++ b/EndpointsExample/ExampleMVVM/ExampleModel.swift @@ -1,3 +1,5 @@ +// Copyright © 2025 DIAMIR. All Rights Reserved. + import Foundation struct ExampleModel: Codable { diff --git a/EndpointsExample/ExampleMVVM/ExampleView.swift b/EndpointsExample/ExampleMVVM/ExampleView.swift index ddb46d3..538ffe3 100644 --- a/EndpointsExample/ExampleMVVM/ExampleView.swift +++ b/EndpointsExample/ExampleMVVM/ExampleView.swift @@ -1,3 +1,5 @@ +// Copyright © 2025 DIAMIR. All Rights Reserved. + import SwiftUI struct ExampleView: View { diff --git a/EndpointsExample/ExampleMVVM/ExampleViewModel.swift b/EndpointsExample/ExampleMVVM/ExampleViewModel.swift index 8e80ded..a783156 100644 --- a/EndpointsExample/ExampleMVVM/ExampleViewModel.swift +++ b/EndpointsExample/ExampleMVVM/ExampleViewModel.swift @@ -1,3 +1,5 @@ +// Copyright © 2025 DIAMIR. All Rights Reserved. + import Endpoints import Foundation import Injection diff --git a/EndpointsExample/Networking/API.swift b/EndpointsExample/Networking/API.swift index dbbe15a..7de5fd3 100644 --- a/EndpointsExample/Networking/API.swift +++ b/EndpointsExample/Networking/API.swift @@ -1,9 +1,4 @@ -// -// API.swift -// EndpointsTestbed -// -// Created by Alexander Kauer on 11.09.25. -// +// Copyright © 2025 DIAMIR. All Rights Reserved. import Endpoints import Foundation @@ -14,9 +9,9 @@ protocol API: Actor { } actor ExampleAPI: API { - var postmanSession: Session - var httpBinSession: Session - var manipulatedHttpBinSession: Session + private let postmanSession: Session + private let httpBinSession: Session + private let manipulatedHttpBinSession: Session init( postmanClient: AnyClient, diff --git a/EndpointsExample/Networking/HTTPBinClient.swift b/EndpointsExample/Networking/HTTPBinClient.swift index 4a70f9b..1e18f1c 100644 --- a/EndpointsExample/Networking/HTTPBinClient.swift +++ b/EndpointsExample/Networking/HTTPBinClient.swift @@ -1,3 +1,5 @@ +// Copyright © 2025 DIAMIR. All Rights Reserved. + import Endpoints import Foundation diff --git a/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift b/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift index 7447913..a4e748d 100644 --- a/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift +++ b/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift @@ -1,3 +1,5 @@ +// Copyright © 2025 DIAMIR. All Rights Reserved. + import Endpoints import Foundation diff --git a/EndpointsExample/Networking/PostmanEchoClient.swift b/EndpointsExample/Networking/PostmanEchoClient.swift index 413726f..fbe57d0 100644 --- a/EndpointsExample/Networking/PostmanEchoClient.swift +++ b/EndpointsExample/Networking/PostmanEchoClient.swift @@ -1,7 +1,8 @@ +// Copyright © 2025 DIAMIR. All Rights Reserved. + import Endpoints import Foundation - enum PostmanEchoClient { struct ExampleGetCall: Call { typealias Parser = JSONParser diff --git a/EndpointsExampleTests/EndpointsExampleTests.swift b/EndpointsExampleTests/EndpointsExampleTests.swift index 4d8b019..97071a8 100644 --- a/EndpointsExampleTests/EndpointsExampleTests.swift +++ b/EndpointsExampleTests/EndpointsExampleTests.swift @@ -1,9 +1,4 @@ -// -// EndpointsTestbedTests.swift -// EndpointsTestbedTests -// -// Created by Alexander Kauer on 06.04.23. -// +// Copyright © 2023 DIAMIR. All Rights Reserved. @testable import EndpointsExample import XCTest From c4a1a1e59c69478187cfe680db045ccf870599eb Mon Sep 17 00:00:00 2001 From: Alexander Kauer Date: Thu, 30 Oct 2025 10:51:25 +0100 Subject: [PATCH 07/12] Added correct file header template --- .../xcshareddata/IDETemplateMacros.plist | 8 ++++++++ EndpointsExampleTests/EndpointsExampleTests.swift | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 EndpointsExample.xcodeproj/xcshareddata/IDETemplateMacros.plist diff --git a/EndpointsExample.xcodeproj/xcshareddata/IDETemplateMacros.plist b/EndpointsExample.xcodeproj/xcshareddata/IDETemplateMacros.plist new file mode 100644 index 0000000..e7f0ded --- /dev/null +++ b/EndpointsExample.xcodeproj/xcshareddata/IDETemplateMacros.plist @@ -0,0 +1,8 @@ + + + + + FILEHEADER + Copyright © ___YEAR___ DIAMIR. All Rights Reserved. + + diff --git a/EndpointsExampleTests/EndpointsExampleTests.swift b/EndpointsExampleTests/EndpointsExampleTests.swift index 97071a8..18e27a0 100644 --- a/EndpointsExampleTests/EndpointsExampleTests.swift +++ b/EndpointsExampleTests/EndpointsExampleTests.swift @@ -1,4 +1,4 @@ -// Copyright © 2023 DIAMIR. All Rights Reserved. +// Copyright © 2025 DIAMIR. All Rights Reserved. @testable import EndpointsExample import XCTest From be564f5ea0392b52fee0c31236b8ee2f1a285995 Mon Sep 17 00:00:00 2001 From: Alexander Kauer Date: Fri, 31 Oct 2025 11:00:03 +0100 Subject: [PATCH 08/12] Cleanup example project, Adopted to `DefaultClient`, PR feedback --- .../xcshareddata/swiftpm/Package.resolved | 2 +- EndpointsExample/DependencyInjection.swift | 8 +++---- .../ExampleAsyncReactor/ExampleReactor.swift | 4 ++-- .../ExampleReactorView.swift | 8 ++++--- .../ExampleMVVM/ExampleViewModel.swift | 4 ++-- EndpointsExample/Networking/API.swift | 22 +++++++++---------- ...nt.swift => CustomizedHTTPBinClient.swift} | 10 ++++----- 7 files changed, 30 insertions(+), 28 deletions(-) rename EndpointsExample/Networking/{ManipulatedHTTPBinClient.swift => CustomizedHTTPBinClient.swift} (84%) diff --git a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1eadd70..15ae592 100644 --- a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -16,7 +16,7 @@ "location" : "https://github.com/diamirio/Endpoints", "state" : { "branch" : "feature/swift-6.2", - "revision" : "221eae9356e9d5d29f4f3fb519658f2be893982a" + "revision" : "c7b65b4350f42807a19f04995c9ba40f058e024b" } }, { diff --git a/EndpointsExample/DependencyInjection.swift b/EndpointsExample/DependencyInjection.swift index 8d65646..adffefb 100644 --- a/EndpointsExample/DependencyInjection.swift +++ b/EndpointsExample/DependencyInjection.swift @@ -8,17 +8,17 @@ import Injection enum DependencyInjection { static func register() { let postmanEchoUrl = URL(string: "https://postman-echo.com")! - let postmanClient = AnyClient(baseURL: postmanEchoUrl) + let postmanClient = DefaultClient(baseURL: postmanEchoUrl) let httpBinUrl = URL(string: "https://httpbin.org/")! - let httpBinClient = AnyClient(baseURL: httpBinUrl) + let httpBinClient = DefaultClient(baseURL: httpBinUrl) - let manipulatedHttpBinSession = ManipulatedHTTPBinClient() + let customizedHttpBinSession = CustomizedHTTPBinClient() let api = ExampleAPI( postmanClient: postmanClient, httpBinClient: httpBinClient, - manipulatedHttpBinClient: manipulatedHttpBinSession + customizedHttpBinSession: customizedHttpBinSession, ) DependencyInjector.register(api, as: API.self) diff --git a/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift b/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift index b80836a..0133e80 100644 --- a/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift +++ b/EndpointsExample/ExampleAsyncReactor/ExampleReactor.swift @@ -7,7 +7,7 @@ import Injection class ExampleReactor: AsyncReactor { enum Action { - case executeRequests + case executeRequest } struct State { @@ -22,7 +22,7 @@ class ExampleReactor: AsyncReactor { func action(_ action: Action) async { switch action { - case .executeRequests: + case .executeRequest: await executeRequest() } } diff --git a/EndpointsExample/ExampleAsyncReactor/ExampleReactorView.swift b/EndpointsExample/ExampleAsyncReactor/ExampleReactorView.swift index 3f5916c..4e6eefe 100644 --- a/EndpointsExample/ExampleAsyncReactor/ExampleReactorView.swift +++ b/EndpointsExample/ExampleAsyncReactor/ExampleReactorView.swift @@ -4,7 +4,9 @@ import AsyncReactor import SwiftUI struct ExampleReactorView: View { - @EnvironmentObject var reactor: ExampleReactor + + @EnvironmentObject + private var reactor: ExampleReactor var body: some View { VStack { @@ -15,8 +17,8 @@ struct ExampleReactorView: View { .font(.headline) } } - .onAppear { - reactor.send(.executeRequests) + .task { + await reactor.action(.executeRequest) } } } diff --git a/EndpointsExample/ExampleMVVM/ExampleViewModel.swift b/EndpointsExample/ExampleMVVM/ExampleViewModel.swift index a783156..49efd75 100644 --- a/EndpointsExample/ExampleMVVM/ExampleViewModel.swift +++ b/EndpointsExample/ExampleMVVM/ExampleViewModel.swift @@ -23,8 +23,8 @@ class ExampleViewModel: ObservableObject { } Task { - let (_, response) = try await api.loadManipulatedData(deliveredStatusCode: 220) - guard response.statusCode == 200 else { return } + let (_, response) = try await api.loadCustomizedData(deliveredStatusCode: 220) + guard response.statusCode == 220 else { return } print("Success") } } diff --git a/EndpointsExample/Networking/API.swift b/EndpointsExample/Networking/API.swift index 7de5fd3..4f15a95 100644 --- a/EndpointsExample/Networking/API.swift +++ b/EndpointsExample/Networking/API.swift @@ -5,22 +5,22 @@ import Foundation protocol API: Actor { func loadExampleData() async throws -> (ExampleModel, HTTPURLResponse) - func loadManipulatedData(deliveredStatusCode: Int) async throws -> (String, HTTPURLResponse) + func loadCustomizedData(deliveredStatusCode: Int) async throws -> (String, HTTPURLResponse) } actor ExampleAPI: API { - private let postmanSession: Session - private let httpBinSession: Session - private let manipulatedHttpBinSession: Session + private let postmanSession: Session + private let httpBinSession: Session + private let customizedHttpBinSession: Session init( - postmanClient: AnyClient, - httpBinClient: AnyClient, - manipulatedHttpBinClient: ManipulatedHTTPBinClient, + postmanClient: DefaultClient, + httpBinClient: DefaultClient, + customizedHttpBinSession: CustomizedHTTPBinClient, ) { self.postmanSession = Session(with: postmanClient) self.httpBinSession = Session(with: httpBinClient) - self.manipulatedHttpBinSession = Session(with: manipulatedHttpBinClient) + self.customizedHttpBinSession = Session(with: customizedHttpBinSession) } func loadExampleData() async throws -> (ExampleModel, HTTPURLResponse) { @@ -29,9 +29,9 @@ actor ExampleAPI: API { ) } - func loadManipulatedData(deliveredStatusCode: Int) async throws -> (String, HTTPURLResponse) { - try await manipulatedHttpBinSession.dataTask( - for: ManipulatedHTTPBinClient.GetStatusCode(deliveredStatusCode: deliveredStatusCode) + func loadCustomizedData(deliveredStatusCode: Int) async throws -> (String, HTTPURLResponse) { + try await customizedHttpBinSession.dataTask( + for: CustomizedHTTPBinClient.GetStatusCode(deliveredStatusCode: deliveredStatusCode) ) } } diff --git a/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift b/EndpointsExample/Networking/CustomizedHTTPBinClient.swift similarity index 84% rename from EndpointsExample/Networking/ManipulatedHTTPBinClient.swift rename to EndpointsExample/Networking/CustomizedHTTPBinClient.swift index a4e748d..bdd27f4 100644 --- a/EndpointsExample/Networking/ManipulatedHTTPBinClient.swift +++ b/EndpointsExample/Networking/CustomizedHTTPBinClient.swift @@ -3,30 +3,30 @@ import Endpoints import Foundation -struct ManipulatedHTTPBinClient: Client { +struct CustomizedHTTPBinClient: Client { private var client: Client init() { let url = URL(string: "https://httpbin.org/")! - self.client = AnyClient(baseURL: url) + self.client = DefaultClient(baseURL: url) } func encode(call: some Endpoints.Call) async throws -> URLRequest { // Custom manipulation i.e. OAuth implementation - print("- MANIPULATED encode -") + print("- CUSTOMIZED encode -") return try await client.encode(call: call) } func parse(response: HTTPURLResponse?, data: Data?, for call: C) async throws -> C.Parser.OutputType where C: Call { // Custom manipulation i.e. react on error responses or invalid tokens - print("- MANIPULATED parse -") + print("- CUSTOMIZED parse -") return try await client.parse(response: response, data: data, for: call) } func validate(response: HTTPURLResponse?, data: Data?) async throws { // Custom validation if needed - print("- MANIPULATED validate -") + print("- CUSTOMIZED validate -") return try await client.validate(response: response, data: data) } From 9271f936aa392df76c5e97b7dffd1fed6c813c6b Mon Sep 17 00:00:00 2001 From: Alexander Kauer Date: Tue, 4 Nov 2025 11:57:03 +0100 Subject: [PATCH 09/12] Finalised adoptions --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 2 +- EndpointsExample/DependencyInjection.swift | 4 ++-- EndpointsExample/Networking/CustomizedHTTPBinClient.swift | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 15ae592..d181ee3 100644 --- a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -16,7 +16,7 @@ "location" : "https://github.com/diamirio/Endpoints", "state" : { "branch" : "feature/swift-6.2", - "revision" : "c7b65b4350f42807a19f04995c9ba40f058e024b" + "revision" : "82d7773d760288135e6cb82d91e19e85e905bdc0" } }, { diff --git a/EndpointsExample/DependencyInjection.swift b/EndpointsExample/DependencyInjection.swift index adffefb..87123be 100644 --- a/EndpointsExample/DependencyInjection.swift +++ b/EndpointsExample/DependencyInjection.swift @@ -8,10 +8,10 @@ import Injection enum DependencyInjection { static func register() { let postmanEchoUrl = URL(string: "https://postman-echo.com")! - let postmanClient = DefaultClient(baseURL: postmanEchoUrl) + let postmanClient = DefaultClient(url: postmanEchoUrl) let httpBinUrl = URL(string: "https://httpbin.org/")! - let httpBinClient = DefaultClient(baseURL: httpBinUrl) + let httpBinClient = DefaultClient(url: httpBinUrl) let customizedHttpBinSession = CustomizedHTTPBinClient() diff --git a/EndpointsExample/Networking/CustomizedHTTPBinClient.swift b/EndpointsExample/Networking/CustomizedHTTPBinClient.swift index bdd27f4..c93c3c9 100644 --- a/EndpointsExample/Networking/CustomizedHTTPBinClient.swift +++ b/EndpointsExample/Networking/CustomizedHTTPBinClient.swift @@ -8,7 +8,7 @@ struct CustomizedHTTPBinClient: Client { init() { let url = URL(string: "https://httpbin.org/")! - self.client = DefaultClient(baseURL: url) + self.client = DefaultClient(url: url) } func encode(call: some Endpoints.Call) async throws -> URLRequest { From 0407c4aad01d4eab148109f1a54afa003016e323 Mon Sep 17 00:00:00 2001 From: Alexander Kauer Date: Thu, 6 Nov 2025 14:59:04 +0100 Subject: [PATCH 10/12] Fixed naming --- EndpointsExample/DependencyInjection.swift | 4 ++-- EndpointsExample/Networking/API.swift | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/EndpointsExample/DependencyInjection.swift b/EndpointsExample/DependencyInjection.swift index 87123be..ffc3002 100644 --- a/EndpointsExample/DependencyInjection.swift +++ b/EndpointsExample/DependencyInjection.swift @@ -13,12 +13,12 @@ enum DependencyInjection { let httpBinUrl = URL(string: "https://httpbin.org/")! let httpBinClient = DefaultClient(url: httpBinUrl) - let customizedHttpBinSession = CustomizedHTTPBinClient() + let customizedHttpBinClient = CustomizedHTTPBinClient() let api = ExampleAPI( postmanClient: postmanClient, httpBinClient: httpBinClient, - customizedHttpBinSession: customizedHttpBinSession, + customizedHttpBinClient: customizedHttpBinClient, ) DependencyInjector.register(api, as: API.self) diff --git a/EndpointsExample/Networking/API.swift b/EndpointsExample/Networking/API.swift index 4f15a95..0bb0ce8 100644 --- a/EndpointsExample/Networking/API.swift +++ b/EndpointsExample/Networking/API.swift @@ -16,11 +16,11 @@ actor ExampleAPI: API { init( postmanClient: DefaultClient, httpBinClient: DefaultClient, - customizedHttpBinSession: CustomizedHTTPBinClient, + customizedHttpBinClient: CustomizedHTTPBinClient, ) { self.postmanSession = Session(with: postmanClient) self.httpBinSession = Session(with: httpBinClient) - self.customizedHttpBinSession = Session(with: customizedHttpBinSession) + self.customizedHttpBinSession = Session(with: customizedHttpBinClient) } func loadExampleData() async throws -> (ExampleModel, HTTPURLResponse) { From 1187e8cddadefd3095d0112e9c61793fb700fea3 Mon Sep 17 00:00:00 2001 From: Alexander Kauer Date: Mon, 1 Dec 2025 10:42:44 +0100 Subject: [PATCH 11/12] Updated to Endpoints 4.0.0 and Xcode 26.1.0 --- .github/workflows/testing.yaml | 2 +- EndpointsExample.xcodeproj/project.pbxproj | 4 ++-- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index 3b4366c..d008f83 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -17,7 +17,7 @@ jobs: - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '26.0.1' + xcode-version: '26.1.0' - name: Build and Test run: | diff --git a/EndpointsExample.xcodeproj/project.pbxproj b/EndpointsExample.xcodeproj/project.pbxproj index 97ecb36..b6db740 100644 --- a/EndpointsExample.xcodeproj/project.pbxproj +++ b/EndpointsExample.xcodeproj/project.pbxproj @@ -505,8 +505,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/diamirio/Endpoints"; requirement = { - branch = "feature/swift-6.2"; - kind = branch; + kind = upToNextMajorVersion; + minimumVersion = 4.0.0; }; }; FAD06B692E8C1C8C00E87155 /* XCRemoteSwiftPackageReference "Injection" */ = { diff --git a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d181ee3..1c30c57 100644 --- a/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/EndpointsExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/diamirio/Endpoints", "state" : { - "branch" : "feature/swift-6.2", - "revision" : "82d7773d760288135e6cb82d91e19e85e905bdc0" + "revision" : "22acf3704ff43c029595c34728eeb15b68ae5f99", + "version" : "4.0.0" } }, { From 70237d33e20b2de670d342ac1180ad65b4c84ae7 Mon Sep 17 00:00:00 2001 From: Alexander Kauer Date: Mon, 1 Dec 2025 10:43:53 +0100 Subject: [PATCH 12/12] Use Xcode 26.1.1 --- .github/workflows/testing.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index d008f83..ce95625 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -17,7 +17,7 @@ jobs: - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: '26.1.0' + xcode-version: '26.1.1' - name: Build and Test run: |