starting accounts
This commit is contained in:
parent
7ebd3f0657
commit
dcc5df8300
25 changed files with 130 additions and 58 deletions
|
@ -4,7 +4,7 @@
|
||||||
"build": {
|
"build": {
|
||||||
"dockerfile": "Dockerfile",
|
"dockerfile": "Dockerfile",
|
||||||
"args": {
|
"args": {
|
||||||
"GO_VERSION": "1.24.0",
|
"GO_VERSION": "1.24.1",
|
||||||
"GOLANGCI_LINT_VERSION": "1.64.5",
|
"GOLANGCI_LINT_VERSION": "1.64.5",
|
||||||
"MIGRATE_VERSION": "4.18.2"
|
"MIGRATE_VERSION": "4.18.2"
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.qpismont.fr/qpismont/trepa/internal/accounts"
|
"gitea.qpismont.fr/qpismont/trepa/internal/accounts/api"
|
||||||
"gitea.qpismont.fr/qpismont/trepa/internal/core"
|
"gitea.qpismont.fr/qpismont/trepa/internal/core"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
)
|
)
|
||||||
|
@ -105,7 +105,7 @@ func setupDB() *sqlx.DB {
|
||||||
func setupRouter(db *sqlx.DB) *core.ServerMux {
|
func setupRouter(db *sqlx.DB) *core.ServerMux {
|
||||||
router := core.NewServerMux()
|
router := core.NewServerMux()
|
||||||
|
|
||||||
accounts.BindRoutes(router, db)
|
api.BindRoutes(router, db)
|
||||||
|
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
7
go.mod
7
go.mod
|
@ -14,12 +14,19 @@ require (
|
||||||
require (
|
require (
|
||||||
github.com/cockroachdb/apd v1.1.0 // indirect
|
github.com/cockroachdb/apd v1.1.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.25.0 // indirect
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
github.com/gofrs/uuid v4.4.0+incompatible // indirect
|
||||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
|
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/shopspring/decimal v1.4.0 // indirect
|
github.com/shopspring/decimal v1.4.0 // indirect
|
||||||
golang.org/x/crypto v0.33.0 // indirect
|
golang.org/x/crypto v0.33.0 // indirect
|
||||||
|
golang.org/x/net v0.34.0 // indirect
|
||||||
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
golang.org/x/text v0.22.0 // indirect
|
golang.org/x/text v0.22.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
14
go.sum
14
go.sum
|
@ -4,6 +4,14 @@ github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
|
||||||
|
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
|
||||||
|
@ -18,6 +26,8 @@ github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
||||||
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
||||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
|
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
|
||||||
|
@ -34,6 +44,10 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||||
|
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||||
|
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||||
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
|
33
internal/accounts/api/controller.go
Normal file
33
internal/accounts/api/controller.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"gitea.qpismont.fr/qpismont/trepa/internal/accounts/domain"
|
||||||
|
"gitea.qpismont.fr/qpismont/trepa/internal/core"
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
)
|
||||||
|
|
||||||
|
var validate *validator.Validate
|
||||||
|
|
||||||
|
type Controller struct {
|
||||||
|
service domain.AccountService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewController(service domain.AccountService) Controller {
|
||||||
|
return Controller{service: service}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) Login(w *core.Response, r *http.Request) {
|
||||||
|
var request LoginAccountRequest
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||||||
|
w.WriteError(core.ErrInvalidStruct)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validate.Struct(request); err != nil {
|
||||||
|
w.WriteError(core.ErrInvalidStruct)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
6
internal/accounts/api/dto.go
Normal file
6
internal/accounts/api/dto.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
type LoginAccountRequest struct {
|
||||||
|
Username string `json:"username" validate:"required"`
|
||||||
|
Password string `json:"password" validate:"required"`
|
||||||
|
}
|
16
internal/accounts/api/routes.go
Normal file
16
internal/accounts/api/routes.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.qpismont.fr/qpismont/trepa/internal/accounts/repository"
|
||||||
|
"gitea.qpismont.fr/qpismont/trepa/internal/accounts/service"
|
||||||
|
"gitea.qpismont.fr/qpismont/trepa/internal/core"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BindRoutes(srv *core.ServerMux, db *sqlx.DB) {
|
||||||
|
repository := repository.NewRepository(db)
|
||||||
|
service := service.NewService(repository)
|
||||||
|
controller := NewController(service)
|
||||||
|
|
||||||
|
srv.HandleFunc("POST /accounts/login", controller.Login)
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
package accounts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"gitea.qpismont.fr/qpismont/trepa/internal/core"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Controller struct {
|
|
||||||
service Service
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewController(service Service) Controller {
|
|
||||||
return Controller{service: service}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Controller) CreateAccount(w *core.Response, r *http.Request) {
|
|
||||||
w.WriteHeader(http.StatusCreated)
|
|
||||||
w.Json([]byte("test"))
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package accounts
|
package domain
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Id int `db:"id" json:"id"`
|
Id int `db:"id" json:"id"`
|
|
@ -1,4 +1,4 @@
|
||||||
package accounts
|
package domain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
6
internal/accounts/domain/repository.go
Normal file
6
internal/accounts/domain/repository.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
type AccountRepository interface {
|
||||||
|
Insert(account *Account) (int, error)
|
||||||
|
FetchOneByUsername(username string) (*Account, error)
|
||||||
|
}
|
4
internal/accounts/domain/service.go
Normal file
4
internal/accounts/domain/service.go
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
type AccountService interface {
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
package accounts
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
|
"gitea.qpismont.fr/qpismont/trepa/internal/accounts/domain"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,11 +11,11 @@ type Repository struct {
|
||||||
db *sqlx.DB
|
db *sqlx.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRepository(db *sqlx.DB) Repository {
|
func NewRepository(db *sqlx.DB) domain.AccountRepository {
|
||||||
return Repository{db: db}
|
return &Repository{db: db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) Insert(account *Account) (int, error) {
|
func (r *Repository) Insert(account *domain.Account) (int, error) {
|
||||||
var id int
|
var id int
|
||||||
|
|
||||||
stmt, err := r.db.Prepare(SqlInsert)
|
stmt, err := r.db.Prepare(SqlInsert)
|
||||||
|
@ -32,8 +33,8 @@ func (r *Repository) Insert(account *Account) (int, error) {
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) FetchOneByUsername(username string) (*Account, error) {
|
func (r *Repository) FetchOneByUsername(username string) (*domain.Account, error) {
|
||||||
var account Account
|
var account domain.Account
|
||||||
|
|
||||||
err := r.db.Get(&account, SqlFetchOneByUsername, username)
|
err := r.db.Get(&account, SqlFetchOneByUsername, username)
|
||||||
if err != nil {
|
if err != nil {
|
|
@ -1,8 +1,9 @@
|
||||||
package accounts
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"gitea.qpismont.fr/qpismont/trepa/internal/accounts/domain"
|
||||||
"gitea.qpismont.fr/qpismont/trepa/test"
|
"gitea.qpismont.fr/qpismont/trepa/test"
|
||||||
"github.com/magiconair/properties/assert"
|
"github.com/magiconair/properties/assert"
|
||||||
)
|
)
|
||||||
|
@ -13,7 +14,7 @@ func TestRepository_Insert(t *testing.T) {
|
||||||
|
|
||||||
repo := NewRepository(db)
|
repo := NewRepository(db)
|
||||||
|
|
||||||
account := &Account{
|
account := &domain.Account{
|
||||||
Username: "test",
|
Username: "test",
|
||||||
Password: "test",
|
Password: "test",
|
||||||
RoleId: 1,
|
RoleId: 1,
|
|
@ -1,4 +1,4 @@
|
||||||
package accounts
|
package repository
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SqlInsert = "INSERT INTO accounts (username, password, role_id) VALUES ($1, $2, $3) RETURNING id"
|
SqlInsert = "INSERT INTO accounts (username, password, role_id) VALUES ($1, $2, $3) RETURNING id"
|
|
@ -1,14 +0,0 @@
|
||||||
package accounts
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gitea.qpismont.fr/qpismont/trepa/internal/core"
|
|
||||||
"github.com/jmoiron/sqlx"
|
|
||||||
)
|
|
||||||
|
|
||||||
func BindRoutes(srv *core.ServerMux, db *sqlx.DB) {
|
|
||||||
repository := NewRepository(db)
|
|
||||||
service := NewService(repository)
|
|
||||||
controller := NewController(service)
|
|
||||||
|
|
||||||
srv.HandleFunc("GET /accounts", controller.CreateAccount)
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package accounts
|
|
||||||
|
|
||||||
type Service struct {
|
|
||||||
repository Repository
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewService(repository Repository) Service {
|
|
||||||
return Service{repository: repository}
|
|
||||||
}
|
|
11
internal/accounts/service/account.go
Normal file
11
internal/accounts/service/account.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import "gitea.qpismont.fr/qpismont/trepa/internal/accounts/domain"
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
repository domain.AccountRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(repository domain.AccountRepository) domain.AccountService {
|
||||||
|
return &Service{repository: repository}
|
||||||
|
}
|
|
@ -1,11 +1,13 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidToken = NewHTTPError(http.StatusUnauthorized, "Invalid token", nil)
|
ErrInvalidToken = NewHTTPError(http.StatusUnauthorized, "Invalid token", nil)
|
||||||
|
ErrInvalidStruct = NewHTTPError(http.StatusBadRequest, "Invalid struct", nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
type HTTPError struct {
|
type HTTPError struct {
|
||||||
|
@ -23,6 +25,14 @@ func (e *HTTPError) Unwrap() error {
|
||||||
return e.Cause
|
return e.Cause
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *HTTPError) IntoJsonBytes() []byte {
|
||||||
|
json, err := json.Marshal(e)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
|
||||||
func NewHTTPError(code int, message string, cause error) *HTTPError {
|
func NewHTTPError(code int, message string, cause error) *HTTPError {
|
||||||
details := ""
|
details := ""
|
||||||
if cause != nil {
|
if cause != nil {
|
||||||
|
|
|
@ -26,6 +26,12 @@ func (r *Response) WriteHeader(status int) {
|
||||||
r.Status = status
|
r.Status = status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Response) WriteError(err *HTTPError) {
|
||||||
|
r.Header().Set("Content-Type", "application/json")
|
||||||
|
r.WriteHeader(err.Code)
|
||||||
|
r.Write(err.IntoJsonBytes())
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Response) Json(json []byte) {
|
func (r *Response) Json(json []byte) {
|
||||||
r.Header().Set("Content-Type", "application/json")
|
r.Header().Set("Content-Type", "application/json")
|
||||||
r.Write(json)
|
r.Write(json)
|
||||||
|
|
Loading…
Reference in a new issue