Skip to main content

Wheel of Fortune

Spin the Wheel of Fortune to win a price.

http://localhost:8080/wheel-of-fortune

This example shows the union feature as described here: ../service-interfaces/value-objects#union-types

Go service

Service interface defintion

package wof

type Trip struct {
Kind string `json:"kind" gotsrpc:"type:'Trip'"`
Name string `json:"name"`
Description string `json:"description"`
}

type (
Species struct {
LandAnimals *LandAnimals `json:"landAnimals,omitempty" gotsrpc:"union"`
WaterAnimals *WaterAnimals `json:"waterAnimals,omitempty" gotsrpc:"union"`
}
LandAnimals string
WaterAnimals string
)

const (
Cat LandAnimals = "cat"
Dog LandAnimals = "dog"
)

const (
Catfish WaterAnimals = "catfish"
Dogfish WaterAnimals = "dogfish"
)

type Pet struct {
Kind string `json:"kind" gotsrpc:"type:'Pet'"`
Name string `json:"name"`
Species Species `json:"species"`
}

type SeatCount int

const (
TwoSeats SeatCount = 2
FiveSeats SeatCount = 5
SevenSeats SeatCount = 7
)

type Car struct {
Kind string `json:"kind" gotsrpc:"type:'Car'"`
Brand string `json:"brand"`
Model string `json:"model"`
Seats SeatCount `json:"seats"`
Power int `json:"power"`
}

type Price struct {
Trip *Trip `json:"trip,omitempty" gotsrpc:"union"`
Car *Car `json:"car,omitempty" gotsrpc:"union"`
Pet *Pet `json:"pet,omitempty" gotsrpc:"union"`
}

type Service interface {
Spin() Price
}

Service implementation

package server

import (
"math/rand"
"runtime"
"time"

"github.com/foomo/gotsrpc-playground/server/services/wof"
)

type wofService struct {
r *rand.Rand
}

func NewWof() wof.Service {
return &wofService{
r: rand.New(rand.NewSource(time.Now().UnixMicro())),
}
}

func (s *wofService) Spin() wof.Price {
// it has to spin for a little time
time.Sleep(time.Second)

switch int(s.r.Float64() * 3) {
case 0:
return wof.Price{
Trip: &wof.Trip{
Kind: "Trip",
Name: "to the moon",
Description: "takes you to the moon",
},
}
case 1:
return wof.Price{
Car: &wof.Car{
Kind: "Car",
Brand: "gocart",
Model: "1.20",
Seats: wof.TwoSeats,
Power: runtime.NumCPU(),
},
}
case 2:
fallthrough
default:
species := wof.Catfish
return wof.Price{
Pet: &wof.Pet{
Kind: "Pet",
Name: "James",
Species: wof.Species{
WaterAnimals: &species,
},
},
}
}
}

Next.js TypeScript client

import { Car } from "@/components/wof/Car";
import { Trip } from "@/components/wof/Trip";
import { Pet } from "@/components/wof/Pet";
import { ServiceClient } from "@/services/generated/client-wof";

import classes from "@/styles/Wof.module.css";
import { useState } from "react";
import { Price } from "@/services/generated/vo-wof";
import { getClientWithTransportLog, useTransportLogStore } from "@/services/transportWithLog";

const NoPriceComp = () => {
return <div>No Price</div>;
};

const getComponentForPrice = (
price?: Price
): React.FunctionComponent<Price> => {
switch (price?.kind) {
case "Car":
return Car as React.FunctionComponent<Price>;
case "Trip":
return Trip as React.FunctionComponent<Price>;
case "Pet":
return Pet as React.FunctionComponent<Price>;
default:
return NoPriceComp;
}
};

const client = getClientWithTransportLog(ServiceClient);

const WheelOfFortune = () => {
const numRunningCalls = useTransportLogStore(
(state) => state.numRunningCalls
);

const [price, setPrice] = useState<Price>(undefined);

const PriceComp = getComponentForPrice(price);

return (
<div>
<aside>This example shows gotsrpc&apos;s union feature</aside>
<button
onClick={(_) => {
client.spin().then(setPrice);
setPrice(undefined);
}}
>
spin the wheel of fortune to win a price 🎰
</button>
{numRunningCalls > 0 && <p>the wheel of fortune is spinning ...</p>}
{price && (
<div className={classes.price}>
Your price is a ({price.kind})
<PriceComp {...price} />
</div>
)}
</div>
);
};

export default WheelOfFortune;