work in progress
This commit is contained in:
parent
b291de6e58
commit
8b3aad50b0
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/bin/
|
||||
/cmd/multini/multini
|
29
LICENSE
29
LICENSE
@ -1,24 +1,13 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
Copyright (C) 2021 GenZmeY <genzmey@gmail.com>
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
23
Makefile
Normal file
23
Makefile
Normal file
@ -0,0 +1,23 @@
|
||||
NAME = go-jsonapi-example
|
||||
GOCMD = go
|
||||
GOBUILD = $(GOCMD) build
|
||||
SRCMAIN = ./cmd/$(NAME)
|
||||
BINDIR = bin
|
||||
BIN = $(BINDIR)/$(NAME)
|
||||
|
||||
.PHONY: all prep build check-build clean
|
||||
|
||||
all: build
|
||||
|
||||
prep: clean
|
||||
go mod init $(NAME); go mod tidy
|
||||
mkdir $(BINDIR)
|
||||
|
||||
build: prep
|
||||
$(GOBUILD) -o $(BIN) $(SRCMAIN)
|
||||
|
||||
check-build:
|
||||
test -e $(BIN)
|
||||
|
||||
clean:
|
||||
rm -rf $(BINDIR)
|
36
cmd/go-jsonapi-example/main.go
Normal file
36
cmd/go-jsonapi-example/main.go
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
Разработать CRUD (REST API) для модели автомобиля, который имеет следующие поля:
|
||||
|
||||
1. Уникальный идентификатор (любой тип, общение с БД не является критерием чего-либо, можно сделать и in-memory хранилище на время жизни сервиса)
|
||||
2. Бренд автомобиля (текст)
|
||||
3. Модель автомобиля (текст)
|
||||
4. Цена автомобиля (целое, не может быть меньше 0)
|
||||
5. Статус автомобиля (В пути, На складе, Продан, Снят с продажи)
|
||||
6. Пробег (целое)
|
||||
|
||||
Формат ответа api - json api (https://jsonapi.org/)
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"go-jsonapi-example/internal/model"
|
||||
"go-jsonapi-example/internal/resource"
|
||||
"go-jsonapi-example/internal/storage"
|
||||
|
||||
"github.com/manyminds/api2go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
port := 8080
|
||||
baseURL := fmt.Sprintf("http://localhost:%d", port)
|
||||
api := api2go.NewAPIWithBaseURL("v1", baseURL)
|
||||
carStorage := storage.NewCarStorage()
|
||||
api.AddResource(model.Car{}, resource.CarResource{CarStorage: carStorage})
|
||||
|
||||
fmt.Printf("Listening on :%d", port)
|
||||
http.ListenAndServe(fmt.Sprintf(":%d", port), api.Handler())
|
||||
}
|
8
go.mod
Normal file
8
go.mod
Normal file
@ -0,0 +1,8 @@
|
||||
module go-jsonapi-example
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/manyminds/api2go v0.0.0-20210211132652-5457038544fa
|
||||
)
|
103
go.sum
Normal file
103
go.sum
Normal file
@ -0,0 +1,103 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
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/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ=
|
||||
github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.2 h1:88crIK23zO6TqlQBt+f9FrPJNKm9ZEr7qjp9vl/d5TM=
|
||||
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
|
||||
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
||||
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/manyminds/api2go v0.0.0-20210211132652-5457038544fa h1:rqhEZu3Xpi8KZauuX9f2ZWxu+5NlNJbomtKhgZzHHck=
|
||||
github.com/manyminds/api2go v0.0.0-20210211132652-5457038544fa/go.mod h1:7X0DU7oiyM2xvWleZb5baM1LxOUHtQvaC1Swq0yYUt4=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
|
||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
|
||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8 h1:fpnn/HnJONpIu6hkXi1u/7rR0NzilgWr4T0JmWkEitk=
|
||||
golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/guregu/null.v3 v3.4.0 h1:AOpMtZ85uElRhQjEDsFx21BkXqFPwA7uoJukd4KErIs=
|
||||
gopkg.in/guregu/null.v3 v3.4.0/go.mod h1:E4tX2Qe3h7QdL+uZ3a0vqvYwKQsRSQKM5V4YltdgH9Y=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
56
internal/model/model_car.go
Normal file
56
internal/model/model_car.go
Normal file
@ -0,0 +1,56 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/manyminds/api2go/jsonapi"
|
||||
)
|
||||
|
||||
type Car struct {
|
||||
ID string `json:"-"`
|
||||
Brand string `json:"brand"`
|
||||
Model string `json:"model"`
|
||||
Price uint `json:"price"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// GetID to satisfy jsonapi.MarshalIdentifier interface
|
||||
func (u Car) GetID() string {
|
||||
return u.ID
|
||||
}
|
||||
|
||||
// SetID to satisfy jsonapi.UnmarshalIdentifier interface
|
||||
func (u *Car) SetID(id string) error {
|
||||
u.ID = id
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetReferences to satisfy the jsonapi.MarshalReferences interface
|
||||
func (u Car) GetReferences() []jsonapi.Reference {
|
||||
return []jsonapi.Reference{}
|
||||
}
|
||||
|
||||
// GetReferencedIDs to satisfy the jsonapi.MarshalLinkedRelations interface
|
||||
func (u Car) GetReferencedIDs() []jsonapi.ReferenceID {
|
||||
return []jsonapi.ReferenceID{}
|
||||
}
|
||||
|
||||
// GetReferencedStructs to satisfy the jsonapi.MarhsalIncludedRelations interface
|
||||
func (u Car) GetReferencedStructs() []jsonapi.MarshalIdentifier {
|
||||
return []jsonapi.MarshalIdentifier{}
|
||||
}
|
||||
|
||||
// SetToManyReferenceIDs sets the sweets reference IDs and satisfies the jsonapi.UnmarshalToManyRelations interface
|
||||
func (u *Car) SetToManyReferenceIDs(name string, IDs []string) error {
|
||||
return errors.New("There is no to-many relationship with the name " + name)
|
||||
}
|
||||
|
||||
// AddToManyIDs adds some new sweets that a users loves so much
|
||||
func (u *Car) AddToManyIDs(name string, IDs []string) error {
|
||||
return errors.New("There is no to-many relationship with the name " + name)
|
||||
}
|
||||
|
||||
// DeleteToManyIDs removes some sweets from a users because they made him very sick
|
||||
func (u *Car) DeleteToManyIDs(name string, IDs []string) error {
|
||||
return errors.New("There is no to-many relationship with the name " + name)
|
||||
}
|
146
internal/resource/resource_car.go
Normal file
146
internal/resource/resource_car.go
Normal file
@ -0,0 +1,146 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"go-jsonapi-example/internal/model"
|
||||
"go-jsonapi-example/internal/storage"
|
||||
|
||||
"github.com/manyminds/api2go"
|
||||
)
|
||||
|
||||
// CarResource for api2go routes
|
||||
type CarResource struct {
|
||||
CarStorage *storage.CarStorage
|
||||
}
|
||||
|
||||
// FindAll to satisfy api2go data source interface
|
||||
func (s CarResource) FindAll(r api2go.Request) (api2go.Responder, error) {
|
||||
var result []model.Car
|
||||
cars := s.CarStorage.GetAll()
|
||||
|
||||
for _, car := range cars {
|
||||
result = append(result, *car)
|
||||
}
|
||||
|
||||
return &Response{Res: result}, nil
|
||||
}
|
||||
|
||||
// PaginatedFindAll can be used to load cars in chunks
|
||||
func (s CarResource) PaginatedFindAll(r api2go.Request) (uint, api2go.Responder, error) {
|
||||
var (
|
||||
result []model.Car
|
||||
number, size, offset, limit string
|
||||
keys []int
|
||||
)
|
||||
cars := s.CarStorage.GetAll()
|
||||
|
||||
for k := range cars {
|
||||
i, err := strconv.ParseInt(k, 10, 64)
|
||||
if err != nil {
|
||||
return 0, &Response{}, err
|
||||
}
|
||||
|
||||
keys = append(keys, int(i))
|
||||
}
|
||||
sort.Ints(keys)
|
||||
|
||||
numberQuery, ok := r.QueryParams["page[number]"]
|
||||
if ok {
|
||||
number = numberQuery[0]
|
||||
}
|
||||
sizeQuery, ok := r.QueryParams["page[size]"]
|
||||
if ok {
|
||||
size = sizeQuery[0]
|
||||
}
|
||||
offsetQuery, ok := r.QueryParams["page[offset]"]
|
||||
if ok {
|
||||
offset = offsetQuery[0]
|
||||
}
|
||||
limitQuery, ok := r.QueryParams["page[limit]"]
|
||||
if ok {
|
||||
limit = limitQuery[0]
|
||||
}
|
||||
|
||||
if size != "" {
|
||||
sizeI, err := strconv.ParseUint(size, 10, 64)
|
||||
if err != nil {
|
||||
return 0, &Response{}, err
|
||||
}
|
||||
|
||||
numberI, err := strconv.ParseUint(number, 10, 64)
|
||||
if err != nil {
|
||||
return 0, &Response{}, err
|
||||
}
|
||||
|
||||
start := sizeI * (numberI - 1)
|
||||
for i := start; i < start+sizeI; i++ {
|
||||
if i >= uint64(len(cars)) {
|
||||
break
|
||||
}
|
||||
result = append(result, *cars[strconv.FormatInt(int64(keys[i]), 10)])
|
||||
}
|
||||
} else {
|
||||
limitI, err := strconv.ParseUint(limit, 10, 64)
|
||||
if err != nil {
|
||||
return 0, &Response{}, err
|
||||
}
|
||||
|
||||
offsetI, err := strconv.ParseUint(offset, 10, 64)
|
||||
if err != nil {
|
||||
return 0, &Response{}, err
|
||||
}
|
||||
|
||||
for i := offsetI; i < offsetI+limitI; i++ {
|
||||
if i >= uint64(len(cars)) {
|
||||
break
|
||||
}
|
||||
result = append(result, *cars[strconv.FormatInt(int64(keys[i]), 10)])
|
||||
}
|
||||
}
|
||||
|
||||
return uint(len(cars)), &Response{Res: result}, nil
|
||||
}
|
||||
|
||||
// FindOne to satisfy `api2go.DataSource` interface
|
||||
// this method should return the car with the given ID, otherwise an error
|
||||
func (s CarResource) FindOne(ID string, r api2go.Request) (api2go.Responder, error) {
|
||||
car, err := s.CarStorage.GetOne(ID)
|
||||
if err != nil {
|
||||
return &Response{}, api2go.NewHTTPError(err, err.Error(), http.StatusNotFound)
|
||||
}
|
||||
return &Response{Res: car}, nil
|
||||
}
|
||||
|
||||
// Create method to satisfy `api2go.DataSource` interface
|
||||
func (s CarResource) Create(obj interface{}, r api2go.Request) (api2go.Responder, error) {
|
||||
car, ok := obj.(model.Car)
|
||||
if !ok {
|
||||
return &Response{}, api2go.NewHTTPError(errors.New("Invalid instance given"), "Invalid instance given", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
id := s.CarStorage.Insert(car)
|
||||
car.ID = id
|
||||
|
||||
return &Response{Res: car, Code: http.StatusCreated}, nil
|
||||
}
|
||||
|
||||
// Delete to satisfy `api2go.DataSource` interface
|
||||
func (s CarResource) Delete(id string, r api2go.Request) (api2go.Responder, error) {
|
||||
err := s.CarStorage.Delete(id)
|
||||
return &Response{Code: http.StatusNoContent}, err
|
||||
}
|
||||
|
||||
//Update stores all changes on the car
|
||||
func (s CarResource) Update(obj interface{}, r api2go.Request) (api2go.Responder, error) {
|
||||
car, ok := obj.(model.Car)
|
||||
if !ok {
|
||||
return &Response{}, api2go.NewHTTPError(errors.New("Invalid instance given"), "Invalid instance given", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
err := s.CarStorage.Update(car)
|
||||
return &Response{Res: car, Code: http.StatusNoContent}, err
|
||||
}
|
23
internal/resource/response.go
Normal file
23
internal/resource/response.go
Normal file
@ -0,0 +1,23 @@
|
||||
package resource
|
||||
|
||||
// The Response struct implements api2go.Responder
|
||||
type Response struct {
|
||||
Res interface{}
|
||||
Code int
|
||||
}
|
||||
|
||||
func (r Response) Metadata() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"author": "GenZmeY",
|
||||
"license": "wtfpl",
|
||||
"license-url": "http://www.wtfpl.net",
|
||||
}
|
||||
}
|
||||
|
||||
func (r Response) Result() interface{} {
|
||||
return r.Res
|
||||
}
|
||||
|
||||
func (r Response) StatusCode() int {
|
||||
return r.Code
|
||||
}
|
61
internal/storage/storage_car.go
Normal file
61
internal/storage/storage_car.go
Normal file
@ -0,0 +1,61 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"go-jsonapi-example/internal/model"
|
||||
|
||||
"github.com/manyminds/api2go"
|
||||
)
|
||||
|
||||
type CarStorage struct {
|
||||
cars map[string]*model.Car
|
||||
idCount int
|
||||
}
|
||||
|
||||
func NewCarStorage() *CarStorage {
|
||||
return &CarStorage{make(map[string]*model.Car), 1}
|
||||
}
|
||||
|
||||
func (s CarStorage) GetAll() map[string]*model.Car {
|
||||
return s.cars
|
||||
}
|
||||
|
||||
func (s CarStorage) GetOne(id string) (model.Car, error) {
|
||||
user, ok := s.cars[id]
|
||||
if ok {
|
||||
return *user, nil
|
||||
}
|
||||
errMessage := fmt.Sprintf("Car for id %s not found", id)
|
||||
return model.Car{}, api2go.NewHTTPError(errors.New(errMessage), errMessage, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func (s *CarStorage) Insert(c model.Car) string {
|
||||
id := fmt.Sprintf("%d", s.idCount)
|
||||
c.ID = id
|
||||
s.cars[id] = &c
|
||||
s.idCount++
|
||||
return id
|
||||
}
|
||||
|
||||
func (s *CarStorage) Delete(id string) error {
|
||||
_, exists := s.cars[id]
|
||||
if !exists {
|
||||
return fmt.Errorf("Car with id %s does not exist", id)
|
||||
}
|
||||
delete(s.cars, id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *CarStorage) Update(c model.Car) error {
|
||||
_, exists := s.cars[c.ID]
|
||||
if !exists {
|
||||
return fmt.Errorf("Car with id %s does not exist", c.ID)
|
||||
}
|
||||
s.cars[c.ID] = &c
|
||||
|
||||
return nil
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user