Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2.0.0 #66

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
53 changes: 40 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ into:
let network = NetworkingClient(baseURL: "https://jsonplaceholder.typicode.com")

func post() async throws -> User {
try await network.post("/users", params: ["firstname" : "Alan", "lastname" : "Turing"])
try await network.post("/users", body: .urlEncoded(["firstname" : "Alan", "lastname" : "Turing"]))
}
```

Expand Down Expand Up @@ -114,30 +114,57 @@ let postsPublisher: AnyPublisher<[Post], Error> = client.get("")
```

### Pass params
Simply pass a `[String: CustomStringConvertible]` dictionary to the `params` parameter.

#### GET params
GET params are query params, you can put them directly in the URL like so:

```swift
try await client.get("/posts?limit=20&offset=60")
```
or use the `params` parameter like so:

```swift
let response: Data = try await client.posts("/posts/1", params: ["optin" : true ])
try await client.get("/posts", params: ["limit" : 20, "offset" : 60])
```

Parameters are `.urlEncoded` by default (`Content-Type: application/x-www-form-urlencoded`), to encode them as json
(`Content-Type: application/json`), you need to set the client's `parameterEncoding` to `.json` as follows:
Both are equivalent.

#### POST, PUT, PATCH body
Parameters to POST, PUT & PATCH requests are passed in the http body.
You can specify them using the `body` parameter.

##### URLEncoded
`Content-Type: application/x-www-form-urlencoded`

For url encoded body, use `HttpBody.urlEncoded` type for the `body` parameter with a `[String: CustomStringConvertible]` dictionary.
```swift
client.parameterEncoding = .json
try await client.post("/posts/1", body: .urlEncoded(["liked" : true ]))
```

##### JSON
`Content-Type: application/json`
For JSON encoded body, use `HttpBody.json` type for the `body` parameter with an `Encodable` object.

```swift
try await client.post("/posts/1", body: .json(["liked" : true ]))

or
try await client.post("/posts/1", body: .json(PostBody(liked: true))
// Where `PostBody` is Encodable`
```

### Upload multipart data
For multipart calls (post/put), just pass a `MultipartData` struct to the `multipartData` parameter.
For multipart calls (post/put), just pass a `HttpBody.multipart` type to the `body` parameter.
```swift
let params: [String: CustomStringConvertible] = [ "type_resource_id": 1, "title": photo.title]
let multipartData = MultipartData(name: "file",
fileData: photo.data,
fileName: "photo.jpg",
mimeType: "image/jpeg")
client.post("/photos/upload",
params: params,
multipartData: multipartData).sink(receiveCompletion: { _ in }) { (data:Data?, progress: Progress) in
body: .multipart(params: params,
parts: [multipartData]))
.sink(receiveCompletion: { _ in }) { (data:Data?, progress: Progress) in
if let data = data {
print("upload is complete : \(data)")
} else {
Expand Down Expand Up @@ -271,7 +298,7 @@ struct CRUDApi: NetworkingService {

// Create
func create(article a: Article) async throws -> Article {
try await post("/articles", params: ["title" : a.title, "content" : a.content])
try await post("/articles", body: .json(a))
}

// Read
Expand All @@ -281,7 +308,7 @@ struct CRUDApi: NetworkingService {

// Update
func update(article a: Article) async throws -> Article {
try await put("/articles/\(a.id)", params: ["title" : a.title, "content" : a.content])
try await put("/articles/\(a.id)", body: .json(["title" : a.title]))
}

// Delete
Expand All @@ -304,7 +331,7 @@ struct CRUDApi: NetworkingService {

// Create
func create(article a: Article) -> AnyPublisher<Article, Error> {
post("/articles", params: ["title" : a.title, "content" : a.content])
post("/articles", body: .json(a))
}

// Read
Expand All @@ -314,7 +341,7 @@ struct CRUDApi: NetworkingService {

// Update
func update(article a: Article) -> AnyPublisher<Article, Error> {
put("/articles/\(a.id)", params: ["title" : a.title, "content" : a.content])
put("/articles/\(a.id)", body: .json(["title" : a.title]))
}

// Delete
Expand Down
62 changes: 62 additions & 0 deletions Sources/Networking/Async Api/Delete.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// Delete.swift
//
//
// Created by Sacha Durand Saint Omer on 12/11/2023.
//

import Foundation

public extension NetworkingClient {

func delete(_ route: String) async throws {
let _:Data = try await delete(route)
}

func delete<T: Decodable>(_ route: String,
keypath: String? = nil) async throws -> T {
let json: Any = try await delete(route)
return try self.toModel(json, keypath: keypath)
}

func delete<T: Decodable>(_ route: String,
keypath: String? = nil) async throws -> T where T: Collection {
let keypath = keypath ?? defaultCollectionParsingKeyPath
let json: Any = try await delete(route)
return try self.toModel(json, keypath: keypath)
}

func delete(_ route: String) async throws -> Any {
let data: Data = try await delete(route)
return try JSONSerialization.jsonObject(with: data, options: [])
}

func delete(_ route: String) async throws -> Data {
try await request(.delete, route).execute()
}
}

public extension NetworkingService {

func delete(_ route: String) async throws {
return try await network.delete(route)
}

func delete<T: Decodable>(_ route: String,
keypath: String? = nil) async throws -> T {
try await network.delete(route, keypath: keypath)
}

func delete<T: Decodable>(_ route: String,
keypath: String? = nil) async throws -> T where T: Collection {
try await network.delete(route, keypath: keypath)
}

func delete(_ route: String) async throws -> Any {
try await network.delete(route)
}

func delete(_ route: String) async throws -> Data {
try await network.delete(route)
}
}
67 changes: 67 additions & 0 deletions Sources/Networking/Async Api/Get.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// Get.swift
//
//
// Created by Sacha Durand Saint Omer on 12/11/2023.
//

import Foundation

public extension NetworkingClient {

func get(_ route: String, params: Params? = nil) async throws {
let _:Data = try await get(route, params: params)
}

func get<T: Decodable>(_ route: String,
params: Params? = nil,
keypath: String? = nil) async throws -> T {
let json: Any = try await get(route, params: params)
return try self.toModel(json, keypath: keypath)
}

func get<T: Decodable>(_ route: String,
params: Params? = nil,
keypath: String? = nil) async throws -> T where T: Collection {
let keypath = keypath ?? defaultCollectionParsingKeyPath
let json: Any = try await get(route, params: params)
return try self.toModel(json, keypath: keypath)
}

func get(_ route: String, params: Params? = nil) async throws -> Any {
let data: Data = try await get(route, params: params)
return try JSONSerialization.jsonObject(with: data, options: [])
}

func get(_ route: String, params: Params? = nil) async throws -> Data {
try await request(.get, route, params: params).execute()
}
}

public extension NetworkingService {

func get(_ route: String, params: Params? = nil) async throws {
return try await network.get(route, params: params)
}

func get<T: Decodable>(_ route: String,
params: Params? = nil,
keypath: String? = nil) async throws -> T {
try await network.get(route, params: params, keypath: keypath)
}

func get<T: Decodable>(_ route: String,
params: Params? = nil,
keypath: String? = nil) async throws -> T where T: Collection {
try await network.get(route, params: params, keypath: keypath)
}


func get(_ route: String, params: Params? = nil) async throws -> Any {
try await network.get(route, params: params)
}

func get(_ route: String, params: Params? = nil) async throws -> Data {
try await network.get(route, params: params)
}
}
69 changes: 69 additions & 0 deletions Sources/Networking/Async Api/Patch.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// Patch.swift
//
//
// Created by Sacha Durand Saint Omer on 12/11/2023.
//

import Foundation

public extension NetworkingClient {

func patch(_ route: String, body: HTTPBody? = nil) async throws {
let req = request(.patch, route, body: body)
_ = try await req.execute()
}

func patch<T: Decodable>(_ route: String,
body: HTTPBody? = nil,
keypath: String? = nil) async throws -> T {
let json: Any = try await patch(route, body: body)
return try self.toModel(json, keypath: keypath)
}

func patch<T: Decodable>(_ route: String,
body: HTTPBody? = nil,
keypath: String? = nil) async throws -> T where T: Collection {
let keypath = keypath ?? defaultCollectionParsingKeyPath
let json: Any = try await patch(route, body: body)
return try self.toModel(json, keypath: keypath)
}

func patch(_ route: String, body: HTTPBody? = nil) async throws -> Any {
let req = request(.patch, route, body: body)
let data = try await req.execute()
return try JSONSerialization.jsonObject(with: data, options: [])
}

func patch(_ route: String, body: HTTPBody? = nil) async throws -> Data {
try await request(.patch, route, body: body).execute()
}

}

public extension NetworkingService {

func patch(_ route: String, body: HTTPBody? = nil) async throws {
return try await network.patch(route, body: body)
}

func patch<T: Decodable>(_ route: String,
body: HTTPBody? = nil,
keypath: String? = nil) async throws -> T {
try await network.patch(route, body: body, keypath: keypath)
}

func patch<T: Decodable>(_ route: String,
body: HTTPBody? = nil,
keypath: String? = nil) async throws -> T where T: Collection {
try await network.patch(route, body: body, keypath: keypath)
}

func patch(_ route: String, body: HTTPBody? = nil) async throws -> Any {
try await network.patch(route, body: body)
}

func patch(_ route: String, body: HTTPBody? = nil) async throws -> Data {
try await network.patch(route, body: body)
}
}
66 changes: 66 additions & 0 deletions Sources/Networking/Async Api/Post.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// Post.swift
//
//
// Created by Sacha Durand Saint Omer on 12/11/2023.
//

import Foundation

public extension NetworkingClient {

func post(_ route: String, body: HTTPBody? = nil) async throws {
let _: Data = try await post(route, body: body)
}

func post<T: Decodable>(_ route: String,
body: HTTPBody? = nil,
keypath: String? = nil) async throws -> T {
let json: Any = try await post(route, body: body)
return try toModel(json, keypath: keypath)
}

func post<T: Decodable>(_ route: String,
body: HTTPBody? = nil,
keypath: String? = nil) async throws -> T where T: Collection {
let keypath = keypath ?? defaultCollectionParsingKeyPath
let json: Any = try await post(route, body: body)
return try toModel(json, keypath: keypath)
}

func post(_ route: String, body: HTTPBody? = nil) async throws -> Any {
let data: Data = try await post(route, body: body)
return try JSONSerialization.jsonObject(with: data, options: [])
}

func post(_ route: String, body: HTTPBody? = nil) async throws -> Data {
try await request(.post, route, body: body).execute()
}
}

public extension NetworkingService {

func post(_ route: String, body: HTTPBody? = nil) async throws {
return try await network.post(route, body: body)
}

func post<T: Decodable>(_ route: String,
body: HTTPBody? = nil,
keypath: String? = nil) async throws -> T {
try await network.post(route, body: body, keypath: keypath)
}

func post<T: Decodable>(_ route: String,
body: HTTPBody? = nil,
keypath: String? = nil) async throws -> T where T: Collection {
try await network.post(route, body: body, keypath: keypath)
}

func post(_ route: String, body: HTTPBody? = nil) async throws -> Any {
try await network.post(route, body: body)
}

func post(_ route: String, body: HTTPBody? = nil) async throws -> Data {
try await network.post(route, body: body)
}
}
Loading
Loading