mirror of
https://github.com/zhigang1992/swift-request.git
synced 2026-01-12 22:52:42 +08:00
feat: add support for bodyField and namespaced type
This commit is contained in:
@@ -10,5 +10,8 @@ public macro Header(_ name: String = "") = #externalMacro(module: "SwiftRequestM
|
||||
@attached(member)
|
||||
public macro FormField(_ name: String = "") = #externalMacro(module: "SwiftRequestMacros", type: "ParamMacro")
|
||||
|
||||
@attached(member)
|
||||
public macro BodyField(_ name: String = "") = #externalMacro(module: "SwiftRequestMacros", type: "ParamMacro")
|
||||
|
||||
@attached(member)
|
||||
public macro Body() = #externalMacro(module: "SwiftRequestMacros", type: "BodyMacro")
|
||||
|
||||
@@ -34,6 +34,8 @@ public extension Request {
|
||||
} else {
|
||||
request.httpBody = try JSONEncoder().encode(body)
|
||||
}
|
||||
} else if let bodyFields {
|
||||
request.httpBody = try JSONSerialization.data(withJSONObject: bodyFields)
|
||||
}
|
||||
|
||||
if let headers {
|
||||
|
||||
@@ -6,9 +6,11 @@ public struct Request {
|
||||
let queryParams: Params?
|
||||
let headers: Params?
|
||||
let formFields: Params?
|
||||
let bodyFields: BodyParams?
|
||||
let body: (any Encodable)?
|
||||
|
||||
public typealias Params = [String: (any CustomStringConvertible)?]
|
||||
public typealias BodyParams = [String: (any Encodable)?]
|
||||
|
||||
public init(
|
||||
url: URL,
|
||||
@@ -16,6 +18,7 @@ public struct Request {
|
||||
queryParams: Params? = nil,
|
||||
headers: Params? = nil,
|
||||
formFields: Params? = nil,
|
||||
bodyFields: BodyParams? = nil,
|
||||
body: (any Encodable)? = nil
|
||||
) {
|
||||
self.url = url
|
||||
@@ -23,6 +26,7 @@ public struct Request {
|
||||
self.queryParams = queryParams
|
||||
self.headers = headers
|
||||
self.formFields = formFields
|
||||
self.bodyFields = bodyFields
|
||||
self.body = body
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class MethodMacro: PeerMacro {
|
||||
outputType: TypeSyntax,
|
||||
in context: some MacroExpansionContext
|
||||
) -> Bool {
|
||||
if outputType.is(SimpleTypeIdentifierSyntax.self) {
|
||||
if outputType.is(SimpleTypeIdentifierSyntax.self) || outputType.is(MemberTypeIdentifierSyntax.self) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,10 @@ class ServiceMethodExpander {
|
||||
TupleExprElementSyntax(label: "formFields", expression: formFields)
|
||||
}
|
||||
|
||||
if let bodyFields = expandParameter("BodyField", of: declaration, in: context) {
|
||||
TupleExprElementSyntax(label: "bodyFields", expression: bodyFields)
|
||||
}
|
||||
|
||||
if let body = expandBody(of: declaration, in: context) {
|
||||
TupleExprElementSyntax(label: "body", expression: IdentifierExprSyntax(identifier: body))
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@ final class ServiceTests: XCTestCase {
|
||||
let testMacros: [String: Macro.Type] = [
|
||||
"Service": ServiceMacro.self,
|
||||
"GET": MethodMacro.self,
|
||||
"POST": MethodMacro.self,
|
||||
"BodyField": ParamMacro.self,
|
||||
"QueryParam": ParamMacro.self,
|
||||
]
|
||||
|
||||
func testMacro() {
|
||||
@@ -32,12 +35,75 @@ final class ServiceTests: XCTestCase {
|
||||
|
||||
func getRandomQuotes(limit: Int? = nil) async throws -> [Quote] {
|
||||
let request = Request(url: resourceURL.appendingPathComponent("random"), queryParams: ["limit": limit])
|
||||
return try await session.execute(request)
|
||||
return try await executor(request)
|
||||
}
|
||||
|
||||
func getQuote(by id: String) async throws -> Quote {
|
||||
let request = Request(url: resourceURL.appendingPathComponent("\\(id)"))
|
||||
return try await session.execute(request)
|
||||
return try await executor(request)
|
||||
}
|
||||
}
|
||||
""",
|
||||
macros: testMacros
|
||||
)
|
||||
}
|
||||
|
||||
func testBodyFieldMacro() {
|
||||
assertMacroExpansion(
|
||||
"""
|
||||
@Service(resource: "quotes")
|
||||
protocol QuoteService {
|
||||
@POST("random")
|
||||
func getRandomQuotes(@BodyField limit: Int?) async throws -> [Quote]
|
||||
}
|
||||
""",
|
||||
expandedSource: """
|
||||
|
||||
protocol QuoteService {
|
||||
func getRandomQuotes(@BodyField limit: Int?) async throws -> [Quote]
|
||||
}
|
||||
class QuoteServiceImpl: Service, QuoteService {
|
||||
private lazy var resourceURL: URL = baseURL.appendingPathComponent("quotes")
|
||||
|
||||
func getRandomQuotes(limit: Int? = nil) async throws -> [Quote] {
|
||||
let request = Request(url: resourceURL.appendingPathComponent("random"), method: "POST", bodyFields: ["limit": limit])
|
||||
return try await executor(request)
|
||||
}
|
||||
}
|
||||
""",
|
||||
macros: testMacros
|
||||
)
|
||||
}
|
||||
|
||||
func testNestedTypeMacro() {
|
||||
assertMacroExpansion(
|
||||
"""
|
||||
struct Namespace {
|
||||
struct Output: Codable {
|
||||
let hello: String
|
||||
}
|
||||
}
|
||||
@Service(resource: "quotes")
|
||||
protocol QuoteService {
|
||||
@POST("random")
|
||||
func getRandomQuotes(@BodyField limit: Int?) async throws -> Namespace.Output
|
||||
}
|
||||
""",
|
||||
expandedSource: """
|
||||
struct Namespace {
|
||||
struct Output: Codable {
|
||||
let hello: String
|
||||
}
|
||||
}
|
||||
protocol QuoteService {
|
||||
func getRandomQuotes(@BodyField limit: Int?) async throws -> Namespace.Output
|
||||
}
|
||||
class QuoteServiceImpl: Service, QuoteService {
|
||||
private lazy var resourceURL: URL = baseURL.appendingPathComponent("quotes")
|
||||
|
||||
func getRandomQuotes(limit: Int? = nil) async throws -> Namespace.Output {
|
||||
let request = Request(url: resourceURL.appendingPathComponent("random"), method: "POST", bodyFields: ["limit": limit])
|
||||
return try await executor(request)
|
||||
}
|
||||
}
|
||||
""",
|
||||
|
||||
Reference in New Issue
Block a user