github.com/vcilabs/webrpc@v0.5.2-0.20201116131534-162e27b1b33b/_examples/hello-webrpc/server/hello_api.gen.go (about) 1 // hello-webrpc v1.0.0 c929128d878e94653f3a856f80c4671008e22a45 2 // -- 3 // This file has been generated by https://github.com/webrpc/webrpc using gen/golang 4 // Do not edit by hand. Update your webrpc schema and re-generate. 5 package main 6 7 import ( 8 "bytes" 9 "context" 10 "encoding/json" 11 "fmt" 12 "io/ioutil" 13 "net/http" 14 "strings" 15 "time" 16 ) 17 18 // WebRPC description and code-gen version 19 func WebRPCVersion() string { 20 return "v1" 21 } 22 23 // Schema version of your RIDL schema 24 func WebRPCSchemaVersion() string { 25 return "v1.0.0" 26 } 27 28 // Schema hash generated from your RIDL schema 29 func WebRPCSchemaHash() string { 30 return "c929128d878e94653f3a856f80c4671008e22a45" 31 } 32 33 // 34 // Types 35 // 36 37 type Kind uint32 38 39 const ( 40 Kind_USER Kind = 1 41 Kind_ADMIN Kind = 2 42 ) 43 44 var Kind_name = map[uint32]string{ 45 1: "USER", 46 2: "ADMIN", 47 } 48 49 var Kind_value = map[string]uint32{ 50 "USER": 1, 51 "ADMIN": 2, 52 } 53 54 func (x Kind) String() string { 55 return Kind_name[uint32(x)] 56 } 57 58 func (x Kind) MarshalJSON() ([]byte, error) { 59 buf := bytes.NewBufferString(`"`) 60 buf.WriteString(Kind_name[uint32(x)]) 61 buf.WriteString(`"`) 62 return buf.Bytes(), nil 63 } 64 65 func (x *Kind) UnmarshalJSON(b []byte) error { 66 var j string 67 err := json.Unmarshal(b, &j) 68 if err != nil { 69 return err 70 } 71 *x = Kind(Kind_value[j]) 72 return nil 73 } 74 75 type Empty struct { 76 } 77 78 type User struct { 79 ID uint64 `json:"id" db:"id"` 80 Username string `json:"USERNAME" db:"username"` 81 CreatedAt *time.Time `json:"created_at,omitempty" db:"created_at"` 82 } 83 84 type ExampleService interface { 85 Ping(ctx context.Context) (bool, error) 86 GetUser(ctx context.Context, userID uint64) (*User, error) 87 } 88 89 var WebRPCServices = map[string][]string{ 90 "ExampleService": { 91 "Ping", 92 "GetUser", 93 }, 94 } 95 96 // 97 // Server 98 // 99 100 type WebRPCServer interface { 101 http.Handler 102 } 103 104 type exampleServiceServer struct { 105 ExampleService 106 } 107 108 func NewExampleServiceServer(svc ExampleService) WebRPCServer { 109 return &exampleServiceServer{ 110 ExampleService: svc, 111 } 112 } 113 114 func (s *exampleServiceServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { 115 ctx := r.Context() 116 ctx = context.WithValue(ctx, HTTPResponseWriterCtxKey, w) 117 ctx = context.WithValue(ctx, HTTPRequestCtxKey, r) 118 ctx = context.WithValue(ctx, ServiceNameCtxKey, "ExampleService") 119 120 if r.Method != "POST" { 121 err := Errorf(ErrBadRoute, "unsupported method %q (only POST is allowed)", r.Method) 122 RespondWithError(w, err) 123 return 124 } 125 126 switch r.URL.Path { 127 case "/rpc/ExampleService/Ping": 128 s.servePing(ctx, w, r) 129 return 130 case "/rpc/ExampleService/GetUser": 131 s.serveGetUser(ctx, w, r) 132 return 133 default: 134 err := Errorf(ErrBadRoute, "no handler for path %q", r.URL.Path) 135 RespondWithError(w, err) 136 return 137 } 138 } 139 140 func (s *exampleServiceServer) servePing(ctx context.Context, w http.ResponseWriter, r *http.Request) { 141 header := r.Header.Get("Content-Type") 142 i := strings.Index(header, ";") 143 if i == -1 { 144 i = len(header) 145 } 146 147 switch strings.TrimSpace(strings.ToLower(header[:i])) { 148 case "application/json": 149 s.servePingJSON(ctx, w, r) 150 default: 151 err := Errorf(ErrBadRoute, "unexpected Content-Type: %q", r.Header.Get("Content-Type")) 152 RespondWithError(w, err) 153 } 154 } 155 156 func (s *exampleServiceServer) servePingJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { 157 var err error 158 ctx = context.WithValue(ctx, MethodNameCtxKey, "Ping") 159 160 // Call service method 161 var ret0 bool 162 func() { 163 defer func() { 164 // In case of a panic, serve a 500 error and then panic. 165 if rr := recover(); rr != nil { 166 RespondWithError(w, ErrorInternal("internal service panic")) 167 panic(rr) 168 } 169 }() 170 ret0, err = s.ExampleService.Ping(ctx) 171 }() 172 respContent := struct { 173 Ret0 bool `json:"status"` 174 }{ret0} 175 176 if err != nil { 177 RespondWithError(w, err) 178 return 179 } 180 respBody, err := json.Marshal(respContent) 181 if err != nil { 182 err = WrapError(ErrInternal, err, "failed to marshal json response") 183 RespondWithError(w, err) 184 return 185 } 186 187 w.Header().Set("Content-Type", "application/json") 188 w.WriteHeader(http.StatusOK) 189 w.Write(respBody) 190 } 191 192 func (s *exampleServiceServer) serveGetUser(ctx context.Context, w http.ResponseWriter, r *http.Request) { 193 header := r.Header.Get("Content-Type") 194 i := strings.Index(header, ";") 195 if i == -1 { 196 i = len(header) 197 } 198 199 switch strings.TrimSpace(strings.ToLower(header[:i])) { 200 case "application/json": 201 s.serveGetUserJSON(ctx, w, r) 202 default: 203 err := Errorf(ErrBadRoute, "unexpected Content-Type: %q", r.Header.Get("Content-Type")) 204 RespondWithError(w, err) 205 } 206 } 207 208 func (s *exampleServiceServer) serveGetUserJSON(ctx context.Context, w http.ResponseWriter, r *http.Request) { 209 var err error 210 ctx = context.WithValue(ctx, MethodNameCtxKey, "GetUser") 211 reqContent := struct { 212 Arg0 uint64 `json:"userID"` 213 }{} 214 215 reqBody, err := ioutil.ReadAll(r.Body) 216 if err != nil { 217 err = WrapError(ErrInternal, err, "failed to read request data") 218 RespondWithError(w, err) 219 return 220 } 221 defer r.Body.Close() 222 223 err = json.Unmarshal(reqBody, &reqContent) 224 if err != nil { 225 err = WrapError(ErrInvalidArgument, err, "failed to unmarshal request data") 226 RespondWithError(w, err) 227 return 228 } 229 230 // Call service method 231 var ret0 *User 232 func() { 233 defer func() { 234 // In case of a panic, serve a 500 error and then panic. 235 if rr := recover(); rr != nil { 236 RespondWithError(w, ErrorInternal("internal service panic")) 237 panic(rr) 238 } 239 }() 240 ret0, err = s.ExampleService.GetUser(ctx, reqContent.Arg0) 241 }() 242 respContent := struct { 243 Ret0 *User `json:"user"` 244 }{ret0} 245 246 if err != nil { 247 RespondWithError(w, err) 248 return 249 } 250 respBody, err := json.Marshal(respContent) 251 if err != nil { 252 err = WrapError(ErrInternal, err, "failed to marshal json response") 253 RespondWithError(w, err) 254 return 255 } 256 257 w.Header().Set("Content-Type", "application/json") 258 w.WriteHeader(http.StatusOK) 259 w.Write(respBody) 260 } 261 262 func RespondWithError(w http.ResponseWriter, err error) { 263 rpcErr, ok := err.(Error) 264 if !ok { 265 rpcErr = WrapError(ErrInternal, err, "webrpc error") 266 } 267 268 statusCode := HTTPStatusFromErrorCode(rpcErr.Code()) 269 270 w.Header().Set("Content-Type", "application/json") 271 w.WriteHeader(statusCode) 272 273 respBody, _ := json.Marshal(rpcErr.Payload()) 274 w.Write(respBody) 275 } 276 277 // 278 // Helpers 279 // 280 281 type ErrorPayload struct { 282 Status int `json:"status"` 283 Code string `json:"code"` 284 Cause string `json:"cause,omitempty"` 285 Msg string `json:"msg"` 286 Error string `json:"error"` 287 } 288 289 type Error interface { 290 // Code is of the valid error codes 291 Code() ErrorCode 292 293 // Msg returns a human-readable, unstructured messages describing the error 294 Msg() string 295 296 // Cause is reason for the error 297 Cause() error 298 299 // Error returns a string of the form "webrpc error <Code>: <Msg>" 300 Error() string 301 302 // Error response payload 303 Payload() ErrorPayload 304 } 305 306 func Errorf(code ErrorCode, msgf string, args ...interface{}) Error { 307 msg := fmt.Sprintf(msgf, args...) 308 if IsValidErrorCode(code) { 309 return &rpcErr{code: code, msg: msg} 310 } 311 return &rpcErr{code: ErrInternal, msg: "invalid error type " + string(code)} 312 } 313 314 func WrapError(code ErrorCode, cause error, format string, args ...interface{}) Error { 315 msg := fmt.Sprintf(format, args...) 316 if IsValidErrorCode(code) { 317 return &rpcErr{code: code, msg: msg, cause: cause} 318 } 319 return &rpcErr{code: ErrInternal, msg: "invalid error type " + string(code), cause: cause} 320 } 321 322 func ErrorNotFound(format string, args ...interface{}) Error { 323 return Errorf(ErrNotFound, format, args...) 324 } 325 326 func ErrorInvalidArgument(argument string, validationMsg string) Error { 327 return Errorf(ErrInvalidArgument, argument+" "+validationMsg) 328 } 329 330 func ErrorRequiredArgument(argument string) Error { 331 return ErrorInvalidArgument(argument, "is required") 332 } 333 334 func ErrorInternal(format string, args ...interface{}) Error { 335 return Errorf(ErrInternal, format, args...) 336 } 337 338 type ErrorCode string 339 340 const ( 341 // Canceled indicates the operation was cancelled (typically by the caller). 342 ErrCanceled ErrorCode = "canceled" 343 344 // Unknown error. For example when handling errors raised by APIs that do not 345 // return enough error information. 346 ErrUnknown ErrorCode = "unknown" 347 348 // InvalidArgument indicates client specified an invalid argument. It 349 // indicates arguments that are problematic regardless of the state of the 350 // system (i.e. a malformed file name, required argument, number out of range, 351 // etc.). 352 ErrInvalidArgument ErrorCode = "invalid argument" 353 354 // DeadlineExceeded means operation expired before completion. For operations 355 // that change the state of the system, this error may be returned even if the 356 // operation has completed successfully (timeout). 357 ErrDeadlineExceeded ErrorCode = "deadline exceeded" 358 359 // NotFound means some requested entity was not found. 360 ErrNotFound ErrorCode = "not found" 361 362 // BadRoute means that the requested URL path wasn't routable to a webrpc 363 // service and method. This is returned by the generated server, and usually 364 // shouldn't be returned by applications. Instead, applications should use 365 // NotFound or Unimplemented. 366 ErrBadRoute ErrorCode = "bad route" 367 368 // AlreadyExists means an attempt to create an entity failed because one 369 // already exists. 370 ErrAlreadyExists ErrorCode = "already exists" 371 372 // PermissionDenied indicates the caller does not have permission to execute 373 // the specified operation. It must not be used if the caller cannot be 374 // identified (Unauthenticated). 375 ErrPermissionDenied ErrorCode = "permission denied" 376 377 // Unauthenticated indicates the request does not have valid authentication 378 // credentials for the operation. 379 ErrUnauthenticated ErrorCode = "unauthenticated" 380 381 // ResourceExhausted indicates some resource has been exhausted, perhaps a 382 // per-user quota, or perhaps the entire file system is out of space. 383 ErrResourceExhausted ErrorCode = "resource exhausted" 384 385 // FailedPrecondition indicates operation was rejected because the system is 386 // not in a state required for the operation's execution. For example, doing 387 // an rmdir operation on a directory that is non-empty, or on a non-directory 388 // object, or when having conflicting read-modify-write on the same resource. 389 ErrFailedPrecondition ErrorCode = "failed precondition" 390 391 // Aborted indicates the operation was aborted, typically due to a concurrency 392 // issue like sequencer check failures, transaction aborts, etc. 393 ErrAborted ErrorCode = "aborted" 394 395 // OutOfRange means operation was attempted past the valid range. For example, 396 // seeking or reading past end of a paginated collection. 397 // 398 // Unlike InvalidArgument, this error indicates a problem that may be fixed if 399 // the system state changes (i.e. adding more items to the collection). 400 // 401 // There is a fair bit of overlap between FailedPrecondition and OutOfRange. 402 // We recommend using OutOfRange (the more specific error) when it applies so 403 // that callers who are iterating through a space can easily look for an 404 // OutOfRange error to detect when they are done. 405 ErrOutOfRange ErrorCode = "out of range" 406 407 // Unimplemented indicates operation is not implemented or not 408 // supported/enabled in this service. 409 ErrUnimplemented ErrorCode = "unimplemented" 410 411 // Internal errors. When some invariants expected by the underlying system 412 // have been broken. In other words, something bad happened in the library or 413 // backend service. Do not confuse with HTTP Internal Server Error; an 414 // Internal error could also happen on the client code, i.e. when parsing a 415 // server response. 416 ErrInternal ErrorCode = "internal" 417 418 // Unavailable indicates the service is currently unavailable. This is a most 419 // likely a transient condition and may be corrected by retrying with a 420 // backoff. 421 ErrUnavailable ErrorCode = "unavailable" 422 423 // DataLoss indicates unrecoverable data loss or corruption. 424 ErrDataLoss ErrorCode = "data loss" 425 426 // ErrNone is the zero-value, is considered an empty error and should not be 427 // used. 428 ErrNone ErrorCode = "" 429 ) 430 431 func HTTPStatusFromErrorCode(code ErrorCode) int { 432 switch code { 433 case ErrCanceled: 434 return 408 // RequestTimeout 435 case ErrUnknown: 436 return 500 // Internal Server Error 437 case ErrInvalidArgument: 438 return 400 // BadRequest 439 case ErrDeadlineExceeded: 440 return 408 // RequestTimeout 441 case ErrNotFound: 442 return 404 // Not Found 443 case ErrBadRoute: 444 return 404 // Not Found 445 case ErrAlreadyExists: 446 return 409 // Conflict 447 case ErrPermissionDenied: 448 return 403 // Forbidden 449 case ErrUnauthenticated: 450 return 401 // Unauthorized 451 case ErrResourceExhausted: 452 return 403 // Forbidden 453 case ErrFailedPrecondition: 454 return 412 // Precondition Failed 455 case ErrAborted: 456 return 409 // Conflict 457 case ErrOutOfRange: 458 return 400 // Bad Request 459 case ErrUnimplemented: 460 return 501 // Not Implemented 461 case ErrInternal: 462 return 500 // Internal Server Error 463 case ErrUnavailable: 464 return 503 // Service Unavailable 465 case ErrDataLoss: 466 return 500 // Internal Server Error 467 case ErrNone: 468 return 200 // OK 469 default: 470 return 0 // Invalid! 471 } 472 } 473 474 func IsErrorCode(err error, code ErrorCode) bool { 475 if rpcErr, ok := err.(Error); ok { 476 if rpcErr.Code() == code { 477 return true 478 } 479 } 480 return false 481 } 482 483 func IsValidErrorCode(code ErrorCode) bool { 484 return HTTPStatusFromErrorCode(code) != 0 485 } 486 487 type rpcErr struct { 488 code ErrorCode 489 msg string 490 cause error 491 } 492 493 func (e *rpcErr) Code() ErrorCode { 494 return e.code 495 } 496 497 func (e *rpcErr) Msg() string { 498 return e.msg 499 } 500 501 func (e *rpcErr) Cause() error { 502 return e.cause 503 } 504 505 func (e *rpcErr) Error() string { 506 if e.cause != nil && e.cause.Error() != "" { 507 if e.msg != "" { 508 return fmt.Sprintf("webrpc %s error: %s -- %s", e.code, e.cause.Error(), e.msg) 509 } else { 510 return fmt.Sprintf("webrpc %s error: %s", e.code, e.cause.Error()) 511 } 512 } else { 513 return fmt.Sprintf("webrpc %s error: %s", e.code, e.msg) 514 } 515 } 516 517 func (e *rpcErr) Payload() ErrorPayload { 518 statusCode := HTTPStatusFromErrorCode(e.Code()) 519 errPayload := ErrorPayload{ 520 Status: statusCode, 521 Code: string(e.Code()), 522 Msg: e.Msg(), 523 Error: e.Error(), 524 } 525 if e.Cause() != nil { 526 errPayload.Cause = e.Cause().Error() 527 } 528 return errPayload 529 } 530 531 type contextKey struct { 532 name string 533 } 534 535 func (k *contextKey) String() string { 536 return "webrpc context value " + k.name 537 } 538 539 var ( 540 // For Client 541 HTTPClientRequestHeadersCtxKey = &contextKey{"HTTPClientRequestHeaders"} 542 543 // For Server 544 HTTPResponseWriterCtxKey = &contextKey{"HTTPResponseWriter"} 545 546 HTTPRequestCtxKey = &contextKey{"HTTPRequest"} 547 548 ServiceNameCtxKey = &contextKey{"ServiceName"} 549 550 MethodNameCtxKey = &contextKey{"MethodName"} 551 )