work in progress

This commit is contained in:
GenZmeY 2021-03-18 21:52:41 +03:00
parent b291de6e58
commit 8b3aad50b0
10 changed files with 467 additions and 20 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/bin/
/cmd/multini/multini

29
LICENSE
View File

@ -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
View 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)

View 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
View 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
View 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=

View 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)
}

View 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
}

View 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
}

View 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
}