-
Notifications
You must be signed in to change notification settings - Fork 3
/
TwirpError.php
178 lines (147 loc) · 6.71 KB
/
TwirpError.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
<?php
namespace Twirfony;
use Throwable;
class TwirpError extends \Exception
{
// Canceled indicates the operation was cancelled (typically by the caller).
const CANCELED = "canceled";
// Unknown error. For example when handling errors raised by APIs that do not
// return enough error information.
const UNKNOWN = "unknown";
// InvalidArgument indicates client specified an invalid argument. It
// indicates arguments that are problematic regardless of the state of the
// system (i.e. a malformed file name, required argument, number out of range,
// etc.).
const INVALID_ARGUMENT = "invalid_argument";
// DeadlineExceeded means operation expired before completion. For operations
// that change the state of the system, this error may be returned even if the
// operation has completed successfully (timeout).
const DEADLINE_EXCEEDED = "deadline_exceeded";
// NotFound means some requested entity was not found.
const NOT_FOUND = "not_found";
// BadRoute means that the requested URL path wasn't routable to a Twirp
// service and method. This is returned by the generated server, and usually
// shouldn't be returned by applications. Instead, applications should use
// NotFound or Unimplemented.
const BAD_ROUTE = "bad_route";
// AlreadyExists means an attempt to create an entity failed because one
// already exists.
const ALREADY_EXISTS = "already_exists";
// PermissionDenied indicates the caller does not have permission to execute
// the specified operation. It must not be used if the caller cannot be
// identified (Unauthenticated).
const PERMISSION_DENIED = "permission_denied";
// Unauthenticated indicates the request does not have valid authentication
// credentials for the operation.
const UNAUTHENTICATED = "unauthenticated";
// ResourceExhausted indicates some resource has been exhausted, perhaps a
// per-user quota, or perhaps the entire file system is out of space.
const RESOURCE_EXHAUSTED = "resource_exhausted";
// FailedPrecondition indicates operation was rejected because the system is
// not in a state required for the operation's execution. For example, doing
// an rmdir operation on a directory that is non-empty, or on a non-directory
// object, or when having conflicting read-modify-write on the same resource.
const FAILED_PRECONDITION = "failed_precondition";
// Aborted indicates the operation was aborted, typically due to a concurrency
// issue like sequencer check failures, transaction aborts, etc.
const ABORTED = "aborted";
// OutOfRange means operation was attempted past the valid range. For example,
// seeking or reading past end of a paginated collection.
//
// Unlike InvalidArgument, this error indicates a problem that may be fixed if
// the system state changes (i.e. adding more items to the collection).
//
// There is a fair bit of overlap between FailedPrecondition and OutOfRange.
// We recommend using OutOfRange (the more specific error) when it applies so
// that callers who are iterating through a space can easily look for an
// OutOfRange error to detect when they are done.
const OUT_OF_RANGE = "out_of_range";
// Unimplemented indicates operation is not implemented or not
// supported/enabled in this service.
const UNIMPLEMENTED = "unimplemented";
// Internal errors. When some invariants expected by the underlying system
// have been broken. In other words, something bad happened in the library or
// backend service. Do not confuse with HTTP Internal Server Error; an
// Internal error could also happen on the client code, i.e. when parsing a
// server response.
const INTERNAL = "internal";
// Unavailable indicates the service is currently unavailable. This is a most
// likely a transient condition and may be corrected by retrying with a
// backoff.
const UNAVAILABLE = "unavailable";
// DataLoss indicates unrecoverable data loss or corruption.
const DATA_LOSS = "data_loss";
// Gone indicates the target resource is no longer available and that this
// condition is likely to be permanent.
const GONE = "gone";
private static $statusCodeMap = [
self::CANCELED => 408, // RequestTimeout
self::UNKNOWN => 500, // Internal Server Error
self::INVALID_ARGUMENT => 400, // BadRequest
self::DEADLINE_EXCEEDED => 408, // RequestTimeout
self::NOT_FOUND => 404, // Not Found
self::BAD_ROUTE => 404, // Not Found
self::ALREADY_EXISTS => 409, // Conflict
self::PERMISSION_DENIED => 403, // Forbidden
self::UNAUTHENTICATED => 401, // Unauthorized
self::RESOURCE_EXHAUSTED => 403, // Forbidden
self::FAILED_PRECONDITION => 412, // Precondition Failed
self::ABORTED => 409, // Conflict
self::OUT_OF_RANGE => 400, // Bad Request
self::UNIMPLEMENTED => 501, // Not Implemented
self::INTERNAL => 500, // Internal Server Error
self::UNAVAILABLE => 503, // Service Unavailable
self::DATA_LOSS => 500, // Internal Server Error
self::GONE => 410, // Gone
];
private $twirpCode;
private $meta = [];
public static function internalError($message)
{
return new self(self::INTERNAL, $message);
}
public static function internalErrorWith(\Throwable $exception)
{
$err = new self(self::INTERNAL, $exception->getMessage(), $exception);
$err->addMeta('cause', get_class($exception));
return $err;
}
public static function notFoundError($message)
{
return new self(self::NOT_FOUND, $message);
}
public static function invalidArgumentError($argument, $message)
{
$err = new self(self::INVALID_ARGUMENT, $argument . ' ' . $message);
$err->addMeta('argument', $argument);
return $err;
}
public static function requiredArgumentError($argument)
{
return self::invalidArgumentError($argument, 'is required');
}
public function __construct($code, $message, Throwable $previous = null)
{
$this->twirpCode = $code;
parent::__construct($message, $this->getStatusCode(), $previous);
}
public function addMeta($key, $value)
{
$this->meta[$key] = $value;
return $this;
}
public function getStatusCode() {
if (isset(self::$statusCodeMap[$this->twirpCode])) {
return self::$statusCodeMap[$this->twirpCode];
}
return self::UNKNOWN;
}
public function toWireFormat()
{
return [
'msg' => $this->getMessage(),
'code' => $this->twirpCode,
'meta' => $this->meta,
];
}
}