add protobuf contract back to front; make pokemon structs internal

This commit is contained in:
Wouter Groeneveld 2024-04-15 13:56:10 +02:00
parent 315527ee72
commit fd10dbbd13
15 changed files with 493 additions and 71 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.idea/
pokedex.db
pokedex

11
Makefile Normal file
View File

@ -0,0 +1,11 @@
.PHONY : build
.DEFAULT_GOAL := build
build:
rm -rf pokedex*
swag init
protoc -I=./ --go_out=../ ./pokemon/pokemon.proto
go build

View File

@ -7,7 +7,12 @@ A simple Go-powered REST API kata.
- KISS: Use built-in `http` package. https://gin-gonic.com/ looks cooler but also adds dozens of dependencies 😮 No need for a "fully-featured" web framework.
## Protobuf
- JSON mapping: https://protobuf.dev/programming-guides/proto3/#json
## Swagger
- Exposed at `http://localhost:8080/docs`
- Regenerate with `swag init`, see https://github.com/swaggo/http-swagger
- Annotation format: see https://github.com/swaggo/swag

View File

@ -27,13 +27,13 @@ const docTemplate = `{
"produces": [
"application/json"
],
"summary": "get all Pokemon",
"summary": "get all pokemon",
"operationId": "get-all-pokemon",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/pokemon.Pokemon"
"$ref": "#/definitions/pb.Pokemons"
}
}
}
@ -44,13 +44,13 @@ const docTemplate = `{
"produces": [
"application/json"
],
"summary": "Find a specific Pokemon by name",
"summary": "Find a specific pokemon by name",
"operationId": "get-specific-pokemon",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/pokemon.Pokemon"
"$ref": "#/definitions/pb.Pokemons"
}
},
"500": {
@ -64,34 +64,27 @@ const docTemplate = `{
}
},
"definitions": {
"pokemon.Move": {
"pb.Move": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"pokemonID": {
"description": "implicit; see https://gorm.io/docs/has_many.html",
"type": "integer"
},
"url": {
"type": "string"
}
}
},
"pokemon.Pokemon": {
"pb.Pokemon": {
"type": "object",
"properties": {
"height": {
"type": "integer"
},
"id": {
"type": "integer"
},
"moves": {
"type": "array",
"items": {
"$ref": "#/definitions/pokemon.Move"
"$ref": "#/definitions/pb.Move"
}
},
"name": {
@ -101,6 +94,17 @@ const docTemplate = `{
"type": "integer"
}
}
},
"pb.Pokemons": {
"type": "object",
"properties": {
"entries": {
"type": "array",
"items": {
"$ref": "#/definitions/pb.Pokemon"
}
}
}
}
}
}`

View File

@ -21,13 +21,13 @@
"produces": [
"application/json"
],
"summary": "get all Pokemon",
"summary": "get all pokemon",
"operationId": "get-all-pokemon",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/pokemon.Pokemon"
"$ref": "#/definitions/pb.Pokemons"
}
}
}
@ -38,13 +38,13 @@
"produces": [
"application/json"
],
"summary": "Find a specific Pokemon by name",
"summary": "Find a specific pokemon by name",
"operationId": "get-specific-pokemon",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/pokemon.Pokemon"
"$ref": "#/definitions/pb.Pokemons"
}
},
"500": {
@ -58,34 +58,27 @@
}
},
"definitions": {
"pokemon.Move": {
"pb.Move": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"pokemonID": {
"description": "implicit; see https://gorm.io/docs/has_many.html",
"type": "integer"
},
"url": {
"type": "string"
}
}
},
"pokemon.Pokemon": {
"pb.Pokemon": {
"type": "object",
"properties": {
"height": {
"type": "integer"
},
"id": {
"type": "integer"
},
"moves": {
"type": "array",
"items": {
"$ref": "#/definitions/pokemon.Move"
"$ref": "#/definitions/pb.Move"
}
},
"name": {
@ -95,6 +88,17 @@
"type": "integer"
}
}
},
"pb.Pokemons": {
"type": "object",
"properties": {
"entries": {
"type": "array",
"items": {
"$ref": "#/definitions/pb.Pokemon"
}
}
}
}
}
}

View File

@ -1,30 +1,32 @@
basePath: /
definitions:
pokemon.Move:
pb.Move:
properties:
name:
type: string
pokemonID:
description: implicit; see https://gorm.io/docs/has_many.html
type: integer
url:
type: string
type: object
pokemon.Pokemon:
pb.Pokemon:
properties:
height:
type: integer
id:
type: integer
moves:
items:
$ref: '#/definitions/pokemon.Move'
$ref: '#/definitions/pb.Move'
type: array
name:
type: string
weight:
type: integer
type: object
pb.Pokemons:
properties:
entries:
items:
$ref: '#/definitions/pb.Pokemon'
type: array
type: object
host: localhost:8080
info:
contact:
@ -46,8 +48,8 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/pokemon.Pokemon'
summary: get all Pokemon
$ref: '#/definitions/pb.Pokemons'
summary: get all pokemon
/pokemon/{name}:
get:
operationId: get-specific-pokemon
@ -57,10 +59,10 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/pokemon.Pokemon'
$ref: '#/definitions/pb.Pokemons'
"500":
description: error
schema:
type: string
summary: Find a specific Pokemon by name
summary: Find a specific pokemon by name
swagger: "2.0"

7
go.mod
View File

@ -3,6 +3,9 @@ module pokedex
go 1.22
require (
github.com/swaggo/http-swagger v1.3.4
github.com/swaggo/swag v1.16.3
google.golang.org/protobuf v1.33.0
gorm.io/driver/sqlite v1.5.5
gorm.io/gorm v1.25.9
)
@ -19,11 +22,7 @@ require (
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/swaggo/files v1.0.1 // indirect
github.com/swaggo/http-swagger v1.3.4 // indirect
github.com/swaggo/swag v1.16.3 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/tools v0.20.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

25
go.sum
View File

@ -1,5 +1,6 @@
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
@ -9,18 +10,28 @@ github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9Z
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww=
@ -31,6 +42,8 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@ -39,14 +52,14 @@ golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@ -60,9 +73,13 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E=

306
pb/pokemon.pb.go Normal file
View File

@ -0,0 +1,306 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.33.0
// protoc v5.26.1
// source: pokemon/pokemon.proto
package pb
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Move struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
}
func (x *Move) Reset() {
*x = Move{}
if protoimpl.UnsafeEnabled {
mi := &file_pokemon_pokemon_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Move) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Move) ProtoMessage() {}
func (x *Move) ProtoReflect() protoreflect.Message {
mi := &file_pokemon_pokemon_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Move.ProtoReflect.Descriptor instead.
func (*Move) Descriptor() ([]byte, []int) {
return file_pokemon_pokemon_proto_rawDescGZIP(), []int{0}
}
func (x *Move) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Move) GetUrl() string {
if x != nil {
return x.Url
}
return ""
}
type Pokemons struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Entries []*Pokemon `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"`
}
func (x *Pokemons) Reset() {
*x = Pokemons{}
if protoimpl.UnsafeEnabled {
mi := &file_pokemon_pokemon_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Pokemons) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Pokemons) ProtoMessage() {}
func (x *Pokemons) ProtoReflect() protoreflect.Message {
mi := &file_pokemon_pokemon_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Pokemons.ProtoReflect.Descriptor instead.
func (*Pokemons) Descriptor() ([]byte, []int) {
return file_pokemon_pokemon_proto_rawDescGZIP(), []int{1}
}
func (x *Pokemons) GetEntries() []*Pokemon {
if x != nil {
return x.Entries
}
return nil
}
type Pokemon struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Height int32 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"`
Weight int32 `protobuf:"varint,3,opt,name=weight,proto3" json:"weight,omitempty"`
Moves []*Move `protobuf:"bytes,4,rep,name=moves,proto3" json:"moves,omitempty"`
}
func (x *Pokemon) Reset() {
*x = Pokemon{}
if protoimpl.UnsafeEnabled {
mi := &file_pokemon_pokemon_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Pokemon) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Pokemon) ProtoMessage() {}
func (x *Pokemon) ProtoReflect() protoreflect.Message {
mi := &file_pokemon_pokemon_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Pokemon.ProtoReflect.Descriptor instead.
func (*Pokemon) Descriptor() ([]byte, []int) {
return file_pokemon_pokemon_proto_rawDescGZIP(), []int{2}
}
func (x *Pokemon) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Pokemon) GetHeight() int32 {
if x != nil {
return x.Height
}
return 0
}
func (x *Pokemon) GetWeight() int32 {
if x != nil {
return x.Weight
}
return 0
}
func (x *Pokemon) GetMoves() []*Move {
if x != nil {
return x.Moves
}
return nil
}
var File_pokemon_pokemon_proto protoreflect.FileDescriptor
var file_pokemon_pokemon_proto_rawDesc = []byte{
0x0a, 0x15, 0x70, 0x6f, 0x6b, 0x65, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x6f, 0x6b, 0x65, 0x6d, 0x6f,
0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2c, 0x0a, 0x04, 0x4d, 0x6f, 0x76, 0x65, 0x12,
0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x2e, 0x0a, 0x08, 0x50, 0x6f, 0x6b, 0x65, 0x6d, 0x6f, 0x6e,
0x73, 0x12, 0x22, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x08, 0x2e, 0x50, 0x6f, 0x6b, 0x65, 0x6d, 0x6f, 0x6e, 0x52, 0x07, 0x65, 0x6e,
0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x6a, 0x0a, 0x07, 0x50, 0x6f, 0x6b, 0x65, 0x6d, 0x6f, 0x6e,
0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02,
0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x16, 0x0a, 0x06,
0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x77, 0x65,
0x69, 0x67, 0x68, 0x74, 0x12, 0x1b, 0x0a, 0x05, 0x6d, 0x6f, 0x76, 0x65, 0x73, 0x18, 0x04, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x05, 0x2e, 0x4d, 0x6f, 0x76, 0x65, 0x52, 0x05, 0x6d, 0x6f, 0x76, 0x65,
0x73, 0x42, 0x0c, 0x5a, 0x0a, 0x70, 0x6f, 0x6b, 0x65, 0x64, 0x65, 0x78, 0x2f, 0x70, 0x62, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_pokemon_pokemon_proto_rawDescOnce sync.Once
file_pokemon_pokemon_proto_rawDescData = file_pokemon_pokemon_proto_rawDesc
)
func file_pokemon_pokemon_proto_rawDescGZIP() []byte {
file_pokemon_pokemon_proto_rawDescOnce.Do(func() {
file_pokemon_pokemon_proto_rawDescData = protoimpl.X.CompressGZIP(file_pokemon_pokemon_proto_rawDescData)
})
return file_pokemon_pokemon_proto_rawDescData
}
var file_pokemon_pokemon_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_pokemon_pokemon_proto_goTypes = []interface{}{
(*Move)(nil), // 0: Move
(*Pokemons)(nil), // 1: Pokemons
(*Pokemon)(nil), // 2: Pokemon
}
var file_pokemon_pokemon_proto_depIdxs = []int32{
2, // 0: Pokemons.entries:type_name -> Pokemon
0, // 1: Pokemon.moves:type_name -> Move
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_pokemon_pokemon_proto_init() }
func file_pokemon_pokemon_proto_init() {
if File_pokemon_pokemon_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_pokemon_pokemon_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Move); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_pokemon_pokemon_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Pokemons); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_pokemon_pokemon_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Pokemon); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_pokemon_pokemon_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_pokemon_pokemon_proto_goTypes,
DependencyIndexes: file_pokemon_pokemon_proto_depIdxs,
MessageInfos: file_pokemon_pokemon_proto_msgTypes,
}.Build()
File_pokemon_pokemon_proto = out.File
file_pokemon_pokemon_proto_rawDesc = nil
file_pokemon_pokemon_proto_goTypes = nil
file_pokemon_pokemon_proto_depIdxs = nil
}

View File

@ -7,10 +7,10 @@ import (
"pokedex/rest"
)
// @Summary Find a specific Pokemon by name
// @Summary Find a specific pokemon by name
// @ID get-specific-pokemon
// @Produce json
// @Success 200 {object} Pokemon
// @Success 200 {object} pb.Pokemons
// @failure 500 {string} string "error"
// @Router /pokemon/{name} [get]
func HandleFindSingle(db *gorm.DB, rw http.ResponseWriter, req *http.Request) {
@ -24,15 +24,13 @@ func HandleFindSingle(db *gorm.DB, rw http.ResponseWriter, req *http.Request) {
return
}
rest.Json(rw, []Pokemon{
pk,
})
rest.ProtoJson(rw, pk.ToPbWrapped())
}
// @Summary get all Pokemon
// @Summary get all pokemon
// @ID get-all-pokemon
// @Produce json
// @Success 200 {object} Pokemon
// @Success 200 {object} pb.Pokemons
// @Router /pokemon [get]
func HandleFindAll(db *gorm.DB, rw http.ResponseWriter, req *http.Request) {
repo := NewRepo(db)
@ -42,5 +40,5 @@ func HandleFindAll(db *gorm.DB, rw http.ResponseWriter, req *http.Request) {
return
}
rest.Json(rw, pokemons)
rest.ProtoJson(rw, ToPb(pokemons))
}

View File

@ -1,15 +1,57 @@
package pokemon
type Move struct {
import "pokedex/pb"
type move struct {
Name string
Url string
PokemonID uint // implicit; see https://gorm.io/docs/has_many.html
}
type Pokemon struct {
func (m move) ToPb() *pb.Move {
return &pb.Move{
Name: m.Name,
Url: m.Url,
}
}
type pokemon struct {
Id int
Name string
Height int
Weight int
Moves []Move
Moves []move
}
func ToPb(p []pokemon) *pb.Pokemons {
pbs := make([]*pb.Pokemon, len(p))
for i, m := range p {
pbs[i] = m.ToPb()
}
return &pb.Pokemons{
Entries: pbs,
}
}
func (p pokemon) ToPbWrapped() *pb.Pokemons {
pbs := make([]*pb.Pokemon, 1)
pbs = append(pbs, p.ToPb())
return &pb.Pokemons{
Entries: pbs,
}
}
func (p pokemon) ToPb() *pb.Pokemon {
moves := make([]*pb.Move, len(p.Moves))
for i, m := range p.Moves {
moves[i] = m.ToPb()
}
return &pb.Pokemon{
Name: p.Name,
Height: int32(p.Height),
Weight: int32(p.Weight),
Moves: moves,
}
}

20
pokemon/pokemon.proto Normal file
View File

@ -0,0 +1,20 @@
syntax = "proto3";
//package pb; -- https://protobuf.dev/programming-guides/proto3/#packages: ignored in Go
option go_package = "pokedex/pb";
message Move {
string name = 1;
string url = 2;
}
message Pokemons {
repeated Pokemon entries = 1;
}
message Pokemon {
string name = 1;
int32 height = 2;
int32 weight = 3;
repeated Move moves = 4;
}

View File

@ -15,19 +15,19 @@ func NewRepo(db *gorm.DB) Repo {
}
}
func (r Repo) Find(name string) (Pokemon, error) {
var pokemon Pokemon
result := r.db.Find(&pokemon, "name = ?", name) // .First() generates an error if none found
func (r Repo) Find(name string) (pokemon, error) {
var poke pokemon
result := r.db.Find(&poke, "name = ?", name) // .First() generates an error if none found
if result.Error != nil {
return Pokemon{}, fmt.Errorf("Unable to retrive pokemon named %s: %w", name, result.Error)
return pokemon{}, fmt.Errorf("Unable to retrive pokemon named %s: %w", name, result.Error)
}
return pokemon, nil
return poke, nil
}
func (r Repo) FindAll() ([]Pokemon, error) {
var pokemons []Pokemon
result := r.db.Model(&Pokemon{}).Preload("Moves").Find(&pokemons)
func (r Repo) FindAll() ([]pokemon, error) {
var pokemons []pokemon
result := r.db.Model(&pokemon{}).Preload("Moves").Find(&pokemons)
if result.Error != nil {
return nil, fmt.Errorf("Unable to retrive pokemons: %w", result.Error)
}

View File

@ -3,13 +3,13 @@ package pokemon
import "gorm.io/gorm"
func Seed(db *gorm.DB) {
pokemons := []Pokemon{
pokemons := []pokemon{
{
Id: 0,
Name: "Jaak",
Height: 0,
Weight: 0,
Moves: []Move{
Moves: []move{
{
Name: "Boojakasja",
Url: "http://sjakka.be",
@ -22,8 +22,8 @@ func Seed(db *gorm.DB) {
},
}
db.AutoMigrate(&Pokemon{})
db.AutoMigrate(&Move{})
db.AutoMigrate(&pokemon{})
db.AutoMigrate(&move{})
for _, pokemon := range pokemons {
res := db.Create(&pokemon)

View File

@ -2,6 +2,8 @@ package rest
import (
"encoding/json"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"net/http"
)
@ -16,6 +18,17 @@ func Json(w http.ResponseWriter, data any) {
w.Write(bytes)
}
func ProtoJson(w http.ResponseWriter, msg proto.Message) {
bytes, err := protojson.Marshal(msg)
if err != nil {
http.Error(w, "Oops, something went wrong", http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write(bytes)
}
func BadRequest(w http.ResponseWriter) {
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
}