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  )