{"id":16943158,"url":"https://github.com/idevid/voyager","last_synced_at":"2025-03-21T07:23:18.558Z","repository":{"id":208328178,"uuid":"630208834","full_name":"iDevid/Voyager","owner":"iDevid","description":"A lightweight and testable protocol oriented network layer","archived":false,"fork":false,"pushed_at":"2023-04-19T22:44:35.000Z","size":24,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-26T04:12:01.161Z","etag":null,"topics":["network-layer","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iDevid.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-04-19T22:40:28.000Z","updated_at":"2023-04-19T22:44:16.000Z","dependencies_parsed_at":"2023-11-20T23:46:25.591Z","dependency_job_id":"118432b8-45c6-45a7-928c-b1610a127272","html_url":"https://github.com/iDevid/Voyager","commit_stats":null,"previous_names":["idevid/voyager"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iDevid%2FVoyager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iDevid%2FVoyager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iDevid%2FVoyager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iDevid%2FVoyager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iDevid","download_url":"https://codeload.github.com/iDevid/Voyager/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244753511,"owners_count":20504544,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["network-layer","swift"],"created_at":"2024-10-13T21:13:47.499Z","updated_at":"2025-03-21T07:23:18.525Z","avatar_url":"https://github.com/iDevid.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Voyager\n\nA lightweight and testable protocol oriented network layer\n\n\n## Installation\n\n### Swift Package Manager\n\nThe Swift Package Manager is a tool for automating the distribution of Swift code and is integrated into the swift compiler.\n\nOnce you have your Swift package set up, adding Voyager as a dependency is as easy as adding it to the dependencies value of your Package.swift.\n```swift\ndependencies: [\n    .package(url: \"https://github.com/iDevid/Voyager.git\", .upToNextMajor(from: \"1.0.0\"))\n]\n```\n    \n## Usage/Examples\n\nUsing Voyager for your networking calls it's really easy, you should just define a service that inherits from `NetworkService`\n\n```swift\nimport Voyager\n\nstruct PokemonListService: NetworkService {\n\n    typealias ResponseModel = PokemonListResponse\n    \n    var rootEndpoint: String { \"https://pokeapi.co/api/v2/\" }\n    var endpoint: String { \"pokemon\" }\n}\n\n// MARK: - Response Models\n\nstruct PokemonListResponse: Decodable {\n    let count: Int\n    let results: [PokemonReference]\n}\n\nstruct PokemonReference: Decodable {\n    let name: String\n    let url: String\n}\n```\n\n### Using the service\n\n```swift\nlet service = PokemonListService()\nservice.perform { result in\n    switch result {\n    case let .failure(error):\n        print(\"Error: \\(error)\")\n    \n    case let .success(responseModel):\n        print(\"Response: \\(responseModel)\")\n    }\n}\n```\n\n### How to perform query requests\n\nTo perform a query request you have to just define a `typealias QueryRequestModel` inside your service like this:\n```swift\nstruct PokemonListService: NetworkService {\n    typealias QueryRequestModel = PokemonListQueryRequest\n}\n\nstruct PokemonListQueryRequest: NetworkRequest {\n    let limit: Int\n    let offset: Int\n}\n```\nAnd then you should call the `perform` method with the defined query model, it will be converted automatically to query items:\n```swift\nlet service = PokemonListService()\nservice.perform(queryRequest: PokemonListQueryRequest(limit: 1000, offset: 5)) { result in\n    ...\n}\n```\n### How to perform body requests\n\nThis applies also for body request, just define a `typealias BodyRequestModel = MyModel` and then use it in the perform method:\n\n```swift\nservice.perform(bodyRequest: MyModel()) {\n    ...\n}\n```\n\n## Mocking a service\n\nTo mock a service in your unit tests you should use the protocol approach to define them. Let's consider the previous PokemonListService, it should be defined in this way:\n```swift\nprotocol PokemonListServiceProtocol: NetworkService where ResponseModel == PokemonListResponse {}\nextension PokemonListServiceProtocol {\n    var rootEndpoint: String { \"https://pokeapi.co/api/v2/\" }\n    var endpoint: String { \"pokemon\" }\n}\n\n// Concrete Type:\nstruct PokemonListService: PokemonListServiceProtocol {}\n\nclass ClassToTest {\n    let service: any PokemonListServiceProtocol\n    \n    init(service: any PokemonListServiceProtocol) {\n        self.service = service\n    }\n}\n```\n\nNow in your app you can instantiate the class just in this way:\n```swift\nClassToTest(service: PokemonListService())\n```\n\nTo create a mock you should import `VoyagerMock` framework and declaring a new service (it should be an object) that inherits from `PokemonListServiceProtocol` and also `MockedService`, this will automatically mock the `perform` method of the network service\n\n```swift\nimport VoyagerMock\n\nclass PokemonListMockService: MockedService, PokemonListServiceProtocol {}\n```\n\nThe `MockedService` has the following APIs to set the response:\n```swift\nlet service = PokemonListMockService()\nservice.setNextResponse(MockType)\n```\nwhere `MockType` it's defined in this way:\n\n```swift\npublic enum MockType {\n    case json(name: String, bundle: Bundle = .main)\n    case model(_ model: ResponseModel)\n    case failure(_ error: Error)\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fidevid%2Fvoyager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fidevid%2Fvoyager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fidevid%2Fvoyager/lists"}