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