Skip to content

Commit

Permalink
Implement search endpoint.
Browse files Browse the repository at this point in the history
This endpoint is not officially documented and was reverse-engineered
from the raider.io website.
  • Loading branch information
sgade committed Mar 10, 2022
1 parent fc98caf commit 5792a81
Show file tree
Hide file tree
Showing 13 changed files with 307 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Added

* Added search endpoint.
* Make slug types equatable with their rawValue.

### Fixed
Expand Down
22 changes: 22 additions & 0 deletions Sources/RaiderIO/Class.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// Class.swift
// RaiderIO
//
// Created by Sören Gade on 10.03.22.
//


import Foundation


public struct Class {

public let id: Int
public let name: String
public let slug: String

}

// MARK: - Decodable

extension Class: Decodable {}
8 changes: 6 additions & 2 deletions Sources/RaiderIO/Expansion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,15 @@ extension Expansion: ExpressibleByIntegerLiteral {

extension Expansion {

public static func ==(lhs: Expansion, rhs: Int) -> Bool {
public static func == (lhs: Expansion, rhs: Expansion) -> Bool {
lhs.rawValue == rhs.rawValue
}

public static func == (lhs: Expansion, rhs: Int) -> Bool {
lhs.rawValue == rhs
}

public static func ==(lhs: Int, rhs: Expansion) -> Bool {
public static func == (lhs: Int, rhs: Expansion) -> Bool {
lhs == rhs.rawValue
}

Expand Down
8 changes: 6 additions & 2 deletions Sources/RaiderIO/Guild/BossKill.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ public struct BossKill {
public let id: Int
// public let covenant: Any // TODO: define object
public let name: String
// public let race: Any // TODO: define object
// public let `class`: Any // TODO: define object
public let race: Race
public let `class`: Class
// public let spec: Any // TODO: define object
public let talents: String
// public let talentsDetails: [Any] // TODO: define object
Expand All @@ -66,6 +66,8 @@ public struct BossKill {

public init(id: Int,
name: String,
race: Race,
class: Class,
talents: String,
gender: Gender,
thumbnail: URL,
Expand All @@ -75,6 +77,8 @@ public struct BossKill {
region: Region) {
self.id = id
self.name = name
self.race = race
self.class = `class`
self.talents = talents
self.gender = gender
self.thumbnail = thumbnail
Expand Down
23 changes: 23 additions & 0 deletions Sources/RaiderIO/Race.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// Race.swift
// RaiderIO
//
// Created by Sören Gade on 10.03.22.
//


import Foundation


public struct Race {

public let id: Int
public let name: String
public let slug: String
public let faction: Faction

}

// MARK: - Decodable

extension Race: Decodable {}
4 changes: 4 additions & 0 deletions Sources/RaiderIO/RaidSlug.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ extension RaidSlug: ExpressibleByStringLiteral {

extension RaidSlug {

public static func == (lhs: RaidSlug, rhs: RaidSlug) -> Bool {
lhs.rawValue == rhs.rawValue
}

public static func == (lhs: RaidSlug, rhs: String) -> Bool {
lhs.rawValue == rhs
}
Expand Down
4 changes: 4 additions & 0 deletions Sources/RaiderIO/RegionSlug.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ extension RegionSlug {

extension RegionSlug {

public static func == (lhs: RegionSlug, rhs: RegionSlug) -> Bool {
lhs.rawValue == rhs.rawValue
}

public static func == (lhs: RegionSlug, rhs: String) -> Bool {
lhs.rawValue == rhs
}
Expand Down
25 changes: 25 additions & 0 deletions Sources/RaiderIO/Search/CharacterSearchResult.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// CharacterSearchResult.swift
// RaiderIO
//
// Created by Sören Gade on 10.03.22.
//


import Foundation


public struct CharacterSearchResult {

public let id: Int
public let name: String
public let faction: Faction
public let region: Region
public let realm: Realm
public let `class`: Class

}

// MARK: - Decodable

extension CharacterSearchResult: Decodable {}
25 changes: 25 additions & 0 deletions Sources/RaiderIO/Search/GuildSearchResult.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// GuildSearchResult.swift
// RaiderIO
//
// Created by Sören Gade on 10.03.22.
//


import Foundation


public struct GuildSearchResult {

public let id: Int
public let name: String
public let faction: Faction
public let realm: Realm
public let region: Region
public let path: String

}

// MARK: - Decodable

extension GuildSearchResult: Decodable {}
38 changes: 38 additions & 0 deletions Sources/RaiderIO/Search/RaiderIO+Search.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// RaideRIO+Search.swift
// RaiderIO
//
// Created by Sören Gade on 10.03.22.
//


import Foundation


extension RaiderIO {

private struct SearchResponse: Decodable {

public let matches: [SearchResult]

}

private static let searchUrl = URL(string: "https://raider.io/api/search")!

public func search(for term: String) async throws -> [SearchResult] {
guard var urlComponents = URLComponents(url: RaiderIO.searchUrl, resolvingAgainstBaseURL: true) else {
throw Errors.invalidUrlParameters
}
urlComponents.queryItems = [
URLQueryItem(name: "term", value: term)
]

guard let url = urlComponents.url else {
throw Errors.invalidUrlParameters
}

let response: SearchResponse = try await request(url: url)
return response.matches
}

}
69 changes: 69 additions & 0 deletions Sources/RaiderIO/Search/SearchResult.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// SearchResult.swift
// RaiderIO
//
// Created by Sören Gade on 10.03.22.
//


import Foundation


public struct SearchResult {

public enum ResultType: String {

case character
case guild
case team

}

public enum ResultData {

case character(CharacterSearchResult)
case guild(GuildSearchResult)
case team(TeamSearchResult)

}

public let type: ResultType
public let name: String
public let data: ResultData

}

// MARK: - Decodable

extension SearchResult: Decodable {

private enum CodingKeys: String, CodingKey {

case type
case name
case data

}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

type = try container.decode(ResultType.self, forKey: .type)
name = try container.decode(String.self, forKey: .name)

switch type {
case .character:
let result = try container.decode(CharacterSearchResult.self, forKey: .data)
data = .character(result)
case .guild:
let result = try container.decode(GuildSearchResult.self, forKey: .data)
data = .guild(result)
case .team:
let result = try container.decode(TeamSearchResult.self, forKey: .data)
data = .team(result)
}
}

}
extension SearchResult.ResultType: Decodable {}
extension SearchResult.ResultData: Decodable {}
44 changes: 44 additions & 0 deletions Sources/RaiderIO/Search/TeamSearchResult.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// TeamSearchResult.swift
// RaiderIO
//
// Created by Sören Gade on 10.03.22.
//


import Foundation


public struct TeamSearchResult {

public let keystonePlatoonId: Int?
public let charterId: Int
public let platoonId: Int?
public let name: String
public let slug: String
public let faction: Faction
public let region: Region
public let subRegion: Region?
public let path: String

}

// MARK: - Decodable

extension TeamSearchResult: Decodable {

private enum CodingKeys: String, CodingKey {

case keystonePlatoonId = "keystone_platoon_id"
case charterId = "charter_id"
case platoonId = "platoon_id"
case name
case slug
case faction
case region
case subRegion
case path

}

}
40 changes: 40 additions & 0 deletions Tests/RaiderIOTests/SearchTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// SearchTests.swift
// RaiderIOTests
//
// Created by Sören Gade on 10.03.22.
//


import Foundation
import XCTest
@testable import RaiderIO


final class SearchTests: XCTestCase {

var client: RaiderIO!

override func setUp() {
client = RaiderIO(urlSession: .shared)
}

func testSearchForCharacter() async throws {
do {
let results = try await client.search(for: "Kiaro")

let expectedResult = results.first(where: {
if case .character(let character) = $0.data {
return character.region.slug == .eu && character.realm.name == "Frostwolf" && character.name == "Kiaro"
}
return false
})

XCTAssertNotNil(expectedResult)
} catch {
print(error)
throw error
}
}

}

0 comments on commit 5792a81

Please sign in to comment.