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