Skip to content

Commit 39f8738

Browse files
author
Pankaj Kulkarni
committed
Initial Commit
1 parent 7172260 commit 39f8738

File tree

12 files changed

+361
-0
lines changed

12 files changed

+361
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,4 @@ fastlane/test_output
8888
# https://github.com/johnno1962/injectionforxcode
8989

9090
iOSInjectionProject/
91+
contents.xcworkspacedata

NodeZooSDK/.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
5+
xcuserdata/
6+
DerivedData/
7+
.swiftpm/config/registries.json
8+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9+
.netrc

NodeZooSDK/Package.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// swift-tools-version: 5.7
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "NodeZooSDK",
8+
platforms: [.iOS(.v14)],
9+
products: [
10+
// Products define the executables and libraries a package produces, and make them visible to other packages.
11+
.library(
12+
name: "NodeZooSDK",
13+
targets: ["NodeZooSDK"]),
14+
],
15+
dependencies: [
16+
// Dependencies declare other packages that this package depends on.
17+
// .package(url: /* package url */, from: "1.0.0"),
18+
],
19+
targets: [
20+
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
21+
// Targets can depend on other targets in this package, and on products in packages this package depends on.
22+
.target(
23+
name: "NodeZooSDK",
24+
dependencies: []),
25+
.testTarget(
26+
name: "NodeZooSDKTests",
27+
dependencies: ["NodeZooSDK"]),
28+
]
29+
)

NodeZooSDK/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# NodeZooSDK
2+
3+
A description of this package.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//
2+
// APIService.swift
3+
//
4+
//
5+
// Created by Pankaj Kulkarni on 09/05/23.
6+
//
7+
8+
import Foundation
9+
10+
protocol APIServicingClosure {
11+
func search(request: URLRequest, completion: @escaping (Result<[NZPackage], Error>)->Void) -> URLSessionDataTask?
12+
}
13+
14+
struct ClosureBasedAPIService: APIServicingClosure {
15+
16+
var urlSession = URLSession.shared
17+
18+
19+
func search(request: URLRequest, completion: @escaping (Result<[NZPackage], Error>) -> Void) -> URLSessionDataTask? {
20+
21+
let dataTask = urlSession.dataTask(with: request) {data, response, error in
22+
print("Received response")
23+
guard let httpResponse = response as? HTTPURLResponse else {
24+
completion(.failure(NodeZooServiceError.invalidResponse))
25+
return
26+
}
27+
28+
// --- Debugging purpose only ---
29+
print("Status code: \(httpResponse.statusCode)")
30+
if let data = data {
31+
print("Data: \(String(describing: String(data: data, encoding: .utf8)))")
32+
}
33+
34+
guard httpResponse.statusCode == 200 else {
35+
completion(.failure(NodeZooServiceError.serverError))
36+
return
37+
}
38+
39+
guard let data = data else {
40+
completion(.failure(NodeZooServiceError.noData))
41+
return
42+
}
43+
44+
do {
45+
let searchResponse = try JSONDecoder().decode(SearchResponse.self, from: data)
46+
completion(.success(searchResponse.data.packages))
47+
} catch {
48+
completion(.failure(error))
49+
}
50+
}
51+
dataTask.resume()
52+
return dataTask
53+
}
54+
55+
56+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// SearchRequest.swift
3+
//
4+
//
5+
// Created by Pankaj Kulkarni on 09/05/23.
6+
//
7+
8+
import Foundation
9+
10+
// MARK: - SearchRequest
11+
internal struct SearchRequest: Encodable {
12+
let role = "web", scope = "public", search = "pkgs"
13+
let prefix: String
14+
15+
var body: Data? {
16+
var encodedData: Data? = nil
17+
do {
18+
encodedData = try JSONEncoder().encode(self)
19+
} catch {
20+
print("Error encoding: \(error)")
21+
}
22+
return encodedData
23+
}
24+
25+
}
26+
27+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// SearchResponse.swift
3+
//
4+
//
5+
// Created by Pankaj Kulkarni on 09/05/23.
6+
//
7+
8+
import Foundation
9+
10+
// MARK: - SearchResponse
11+
internal struct SearchResponse: Codable {
12+
let ok: Bool
13+
let data: DataClass
14+
let meta: Meta
15+
16+
enum CodingKeys: String, CodingKey {
17+
case ok, data
18+
case meta = "meta$"
19+
}
20+
}
21+
22+
// MARK: - DataClass
23+
internal struct DataClass: Codable {
24+
let packages: [NZPackage]
25+
enum CodingKeys: String, CodingKey {
26+
case packages = "pkgs"
27+
}
28+
}
29+
30+
// MARK: - Meta
31+
internal struct Meta: Codable {
32+
let id: String
33+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// NetworkManager.swift
3+
//
4+
//
5+
// Created by Pankaj Kulkarni on 09/05/23.
6+
//
7+
8+
import Foundation
9+
10+
struct NetworkManager {
11+
12+
let apiKey: String
13+
let apiService: APIServicingClosure
14+
15+
init(apiKey: String, apiService: APIServicingClosure = ClosureBasedAPIService()) {
16+
self.apiKey = apiKey
17+
self.apiService = apiService
18+
}
19+
20+
@discardableResult
21+
func search(package: String, completion: @escaping (Result<[NZPackage], Error>)->Void) -> URLSessionDataTask? {
22+
print("Searching for: \(package)")
23+
guard var request = createRequest() else {
24+
print("Invalid Request")
25+
completion(.failure(NodeZooServiceError.invalidRequest))
26+
return nil
27+
}
28+
let searchRequest = SearchRequest(prefix: package)
29+
print("Search request: \(searchRequest)")
30+
31+
request.httpBody = searchRequest.body
32+
33+
return apiService.search(request: request, completion: completion)
34+
35+
}
36+
37+
func createRequest() -> URLRequest? {
38+
guard let url = URL(string: "https://api.nodezoo.com/api/public") else {
39+
print("Invalid URL")
40+
return nil
41+
}
42+
43+
var request = URLRequest(url: url)
44+
request.addValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
45+
request.addValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
46+
request.httpMethod = "POST"
47+
return request
48+
}
49+
50+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// NZPackage.swift
3+
//
4+
//
5+
// Created by Pankaj Kulkarni on 09/05/23.
6+
//
7+
8+
import Foundation
9+
10+
11+
/// This struct contains the details of the NodeJS packages
12+
public struct NZPackage: Codable {
13+
/// Name of the package
14+
public let name: String
15+
/// version of the package
16+
public let version: String
17+
/// Description of the package
18+
public let desc: String
19+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//
2+
// NodeZooService.swift
3+
//
4+
//
5+
// Created by Pankaj Kulkarni on 09/05/23.
6+
//
7+
8+
import Foundation
9+
10+
/// Use NodeZooService to fetch the public search function of [nodezoo.com](nodezoo.com)
11+
///
12+
/// While instantiating the ``NodeZooService`` instance pass the API Key as follows:
13+
/// ```
14+
///import NodeZooService
15+
///
16+
///let nodeZooService = NodeZooService(apiKey: "<API Key of >"
17+
/// ```
18+
///
19+
/// And then search the public package as follows:
20+
///
21+
/// ```
22+
/// let dataTask = nodeZooService.search("express") { result in
23+
/// switch result {
24+
/// case .success(let packages):
25+
/// // packages is the array of the found packages
26+
/// case .failure(let error):
27+
/// // handle the error here.
28+
/// }
29+
/// ```
30+
/// The *dataTask* can be used to cancel the search.
31+
///
32+
public class NodeZooService {
33+
34+
private var networkManager: NetworkManager
35+
36+
/// Initializer of NodeZooService
37+
/// - Parameter apiKey: API Key to search packages from [nodezoo.com](nodezoo.com)
38+
public init(apiKey: String) {
39+
networkManager = NetworkManager(apiKey: apiKey)
40+
}
41+
42+
/// Search the packages
43+
/// - Parameters:
44+
/// - query: The query string to search for.
45+
/// - completion: The completion will be invoked with either success or failure.
46+
/// - Returns: Discardable data task. This can be used to cancel the search.
47+
///
48+
@discardableResult
49+
public func search(query: String, completion: @escaping (Result<[NZPackage], Error>)->Void) -> URLSessionDataTask? {
50+
return networkManager.search(package: query, completion: completion)
51+
}
52+
53+
}

0 commit comments

Comments
 (0)