Union Errors
Go Service
Service interface defintion
package ouch
type BadErrorCause string
const (
BadErrorCauseTooHard BadErrorCause = "too hard"
BadErrorCauseTooGoodToBeTrue BadErrorCause = "too good to be true"
)
type BadError struct {
Kind string `json:"kind" gotsrpc:"type:'BadError'"`
Cause BadErrorCause `json:"cause"`
}
func (be *BadError) Error() string {
return string(be.Cause)
}
type AwfulError struct {
Kind string `json:"kind" gotsrpc:"type:'AwfulError'"`
}
func (ae *AwfulError) Error() string {
return "this is simply awful"
}
// Ouch error is a union error type example
type OuchError struct {
Awful *AwfulError `json:"awful,omitempty" gotsrpc:"union"`
Bad *BadError `json:"bad,omitempty" gotsrpc:"union"`
}
type Service interface {
WhatCouldGoWrong() *OuchError
}
Service implementation
package server
import (
"math/rand"
"time"
"github.com/foomo/gotsrpc-playground/server/services/ouch"
)
type ouchService struct {
r *rand.Rand
}
func NewOuch() ouch.Service {
return &ouchService{
r: rand.New(rand.NewSource(time.Now().UnixMicro())),
}
}
func (s *ouchService) WhatCouldGoWrong() *ouch.OuchError {
if int(s.r.Float64()*2) == 0 {
var cause ouch.BadErrorCause
if int(s.r.Float64()*2) == 0 {
cause = ouch.BadErrorCauseTooHard
} else {
cause = ouch.BadErrorCauseTooGoodToBeTrue
}
return &ouch.OuchError{
Bad: &ouch.BadError{
Kind: "BadError",
Cause: cause,
},
}
} else {
return &ouch.OuchError{
Awful: &ouch.AwfulError{
Kind: "AwfulError",
},
}
}
}
Next.js TypeScript client
import { DocsAside } from "@/components/DocsAside";
import { ServiceClient } from "@/services/generated/client-ouch";
import { AwfulError, BadError, OuchError } from "@/services/generated/vo-ouch";
import { getClientWithTransportLog } from "@/services/transportWithLog";
import classes from "@/styles/Ouch.module.css";
import { useState } from "react";
const AwfulErrorComp = (err: AwfulError) => {
return <div className={classes.errorAwful}>AWFUL ERROR</div>;
};
const BadErrorComp = (err: BadError) => {
return <div className={classes.errorBad}>BAD ERROR - cause: {err.cause}</div>;
};
const getComponentForErr = (
err?: OuchError
): React.FunctionComponent<OuchError> | null => {
if (!err) {
return null;
}
switch (err?.kind) {
case "AwfulError":
return AwfulErrorComp as React.FunctionComponent<OuchError>;
case "BadError":
return BadErrorComp as React.FunctionComponent<OuchError>;
default:
return null;
}
};
const client = getClientWithTransportLog(ServiceClient);
const Ouch = () => {
const [err, setErr] = useState<OuchError | null>(null);
const ErrComp = getComponentForErr(err!);
return (
<div>
<DocsAside examplePage="ouch">
This example shows gotsrpc's union feature for errors
<ul>
<li>Every call will result in an error</li>
<li>the error uses gotsrpc union feature</li>
<li>
Use this feature to handle errors from complex underlying domains
</li>
</ul>
</DocsAside>
<button
onClick={(_) => {
client.whatCouldGoWrong().then(setErr);
setErr(null);
}}
>
what could go wrong?
</button>
{err && ErrComp && <ErrComp {...err} />}
</div>
);
};
export default Ouch;