diff --git a/Sources/GRPCCore/Status.swift b/Sources/GRPCCore/Status.swift index 7a78c12e1..eba8d54f0 100644 --- a/Sources/GRPCCore/Status.swift +++ b/Sources/GRPCCore/Status.swift @@ -296,3 +296,32 @@ extension Status.Code { /// operation. public static let unauthenticated = Self(code: .unauthenticated) } + +extension Status { + /// Create a status from an HTTP status code for a response which didn't include a gRPC status. + /// + /// - Parameter httpStatusCode: The HTTP status code to map to a status. + public init(httpStatusCode: Int) { + // See the "http-grpc-status-mapping.md" doc in grpc/grpc GitHub repo. + switch httpStatusCode { + case 400: + self = Status(code: .internalError, message: "HTTP 400: Bad Request") + case 401: + self = Status(code: .unauthenticated, message: "HTTP 401: Unauthorized") + case 403: + self = Status(code: .permissionDenied, message: "HTTP 403: Forbidden") + case 404: + self = Status(code: .unimplemented, message: "HTTP 404: Not Found") + case 429: + self = Status(code: .unavailable, message: "HTTP 429: Too Many Requests") + case 502: + self = Status(code: .unavailable, message: "HTTP 502: Bad Gateway") + case 503: + self = Status(code: .unavailable, message: "HTTP 503: Service Unavailable") + case 504: + self = Status(code: .unavailable, message: "HTTP 504: Gateway Timeout") + default: + self = Status(code: .unknown, message: "HTTP \(httpStatusCode)") + } + } +} diff --git a/Tests/GRPCCoreTests/StatusTests.swift b/Tests/GRPCCoreTests/StatusTests.swift index 936ff8e41..fd442586a 100644 --- a/Tests/GRPCCoreTests/StatusTests.swift +++ b/Tests/GRPCCoreTests/StatusTests.swift @@ -69,4 +69,23 @@ struct StatusTests { func fitsInExistentialContainer() { #expect(MemoryLayout.size <= 24) } + + @Test( + "From HTTP status code", + arguments: [ + (400, Status(code: .internalError, message: "HTTP 400: Bad Request")), + (401, Status(code: .unauthenticated, message: "HTTP 401: Unauthorized")), + (403, Status(code: .permissionDenied, message: "HTTP 403: Forbidden")), + (404, Status(code: .unimplemented, message: "HTTP 404: Not Found")), + (429, Status(code: .unavailable, message: "HTTP 429: Too Many Requests")), + (502, Status(code: .unavailable, message: "HTTP 502: Bad Gateway")), + (503, Status(code: .unavailable, message: "HTTP 503: Service Unavailable")), + (504, Status(code: .unavailable, message: "HTTP 504: Gateway Timeout")), + (418, Status(code: .unknown, message: "HTTP 418")), + ] + ) + func convertFromHTTPStatusCode(code: Int, expected: Status) { + let status = Status(httpStatusCode: code) + #expect(status == expected) + } }