Add openAPI documentation (#68)
This commit is contained in:
parent
c6178e9cd3
commit
7d2e0a8819
@ -93,7 +93,7 @@ func (server *Server) getAccount(ctx *gin.Context) {
|
|||||||
ctx.JSON(http.StatusUnauthorized, errorResponse(err))
|
ctx.JSON(http.StatusUnauthorized, errorResponse(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
//v4.public.eyJlbWFpbCI6ImFAYi5jZSIsImV4cCI6IjIwMjMtMTAtMDRUMDA6NDY6NDYrMDI6MDAiLCJpYXQiOiIyMDIzLTEwLTA0VDAwOjMxOjQ2KzAyOjAwIiwiaWQiOiJhZWU0MGE0NC0yMGIwLTQ3YmYtYmI5Yy04M2Y3ZmI5ZTU0MTEiLCJuYmYiOiIyMDIzLTEwLTA0VDAwOjMxOjQ2KzAyOjAwIn2ZcKWD7cA7y_aHnfUtYOnaR6iCYFaFOY5BbUQkyTpu-ZK9xyaHO1_j9GqAZ6GbntmtWktojWRBkLpoWEntMuQM
|
||||||
ctx.JSON(http.StatusOK, account)
|
ctx.JSON(http.StatusOK, account)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ func (server *Server) updateAccountPrivacy(ctx *gin.Context) {
|
|||||||
account, err = server.store.UpdateAccountPrivacyTx(ctx, db.UpdateAccountPrivacyTxParams{
|
account, err = server.store.UpdateAccountPrivacyTx(ctx, db.UpdateAccountPrivacyTxParams{
|
||||||
ID: req.ID,
|
ID: req.ID,
|
||||||
Changer: authPayload.Email,
|
Changer: authPayload.Email,
|
||||||
PrivacyAccepted: *req.PrivacyAccepted,
|
PrivacyAccepted: req.PrivacyAccepted,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
|
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
|
||||||
|
@ -163,7 +163,7 @@ func TestCreateAccountAPI(t *testing.T) {
|
|||||||
store := mockdb.NewMockStore(ctrl)
|
store := mockdb.NewMockStore(ctrl)
|
||||||
tc.buildStubs(store)
|
tc.buildStubs(store)
|
||||||
|
|
||||||
server, err := NewServer(config, store)
|
server, err := NewServer(config, store, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
@ -299,7 +299,7 @@ func TestGetAccountAPI(t *testing.T) {
|
|||||||
store := mockdb.NewMockStore(ctrl)
|
store := mockdb.NewMockStore(ctrl)
|
||||||
tc.buildStubs(store)
|
tc.buildStubs(store)
|
||||||
|
|
||||||
server, err := NewServer(config, store)
|
server, err := NewServer(config, store, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
@ -447,7 +447,7 @@ func TestUpdateAccountTxAPI(t *testing.T) {
|
|||||||
store := mockdb.NewMockStore(ctrl)
|
store := mockdb.NewMockStore(ctrl)
|
||||||
tc.buildStubs(store)
|
tc.buildStubs(store)
|
||||||
|
|
||||||
server, err := NewServer(config, store)
|
server, err := NewServer(config, store, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
@ -601,7 +601,7 @@ func TestListAccountsAPI(t *testing.T) {
|
|||||||
store := mockdb.NewMockStore(ctrl)
|
store := mockdb.NewMockStore(ctrl)
|
||||||
tc.buildStubs(store)
|
tc.buildStubs(store)
|
||||||
|
|
||||||
server, err := NewServer(config, store)
|
server, err := NewServer(config, store, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
@ -643,9 +643,10 @@ func TestUpdateAccountPrivacyTxAPI(t *testing.T) {
|
|||||||
addAuthorization(t, request, tokenMaker, authorizationTypeBearer, account.Email, time.Minute)
|
addAuthorization(t, request, tokenMaker, authorizationTypeBearer, account.Email, time.Minute)
|
||||||
},
|
},
|
||||||
buildStubs: func(store *mockdb.MockStore) {
|
buildStubs: func(store *mockdb.MockStore) {
|
||||||
|
trueBool := true
|
||||||
arg := db.UpdateAccountPrivacyTxParams{
|
arg := db.UpdateAccountPrivacyTxParams{
|
||||||
ID: account.ID,
|
ID: account.ID,
|
||||||
PrivacyAccepted: true,
|
PrivacyAccepted: &trueBool,
|
||||||
Changer: account.Email,
|
Changer: account.Email,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -689,9 +690,11 @@ func TestUpdateAccountPrivacyTxAPI(t *testing.T) {
|
|||||||
addAuthorization(t, request, tokenMaker, authorizationTypeBearer, account.Email, time.Minute)
|
addAuthorization(t, request, tokenMaker, authorizationTypeBearer, account.Email, time.Minute)
|
||||||
},
|
},
|
||||||
buildStubs: func(store *mockdb.MockStore) {
|
buildStubs: func(store *mockdb.MockStore) {
|
||||||
|
trueBool := true
|
||||||
|
|
||||||
arg := db.UpdateAccountPrivacyTxParams{
|
arg := db.UpdateAccountPrivacyTxParams{
|
||||||
ID: account.ID,
|
ID: account.ID,
|
||||||
PrivacyAccepted: true,
|
PrivacyAccepted: &trueBool,
|
||||||
Changer: account.Email,
|
Changer: account.Email,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -735,9 +738,11 @@ func TestUpdateAccountPrivacyTxAPI(t *testing.T) {
|
|||||||
addAuthorization(t, request, tokenMaker, authorizationTypeBearer, account.Email, time.Minute)
|
addAuthorization(t, request, tokenMaker, authorizationTypeBearer, account.Email, time.Minute)
|
||||||
},
|
},
|
||||||
buildStubs: func(store *mockdb.MockStore) {
|
buildStubs: func(store *mockdb.MockStore) {
|
||||||
|
falseBool := false
|
||||||
|
|
||||||
arg := db.UpdateAccountPrivacyTxParams{
|
arg := db.UpdateAccountPrivacyTxParams{
|
||||||
ID: account.ID,
|
ID: account.ID,
|
||||||
PrivacyAccepted: false,
|
PrivacyAccepted: &falseBool,
|
||||||
Changer: account.Email,
|
Changer: account.Email,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -806,7 +811,7 @@ func TestUpdateAccountPrivacyTxAPI(t *testing.T) {
|
|||||||
store := mockdb.NewMockStore(ctrl)
|
store := mockdb.NewMockStore(ctrl)
|
||||||
tc.buildStubs(store)
|
tc.buildStubs(store)
|
||||||
|
|
||||||
server, err := NewServer(config, store)
|
server, err := NewServer(config, store, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
|
@ -91,7 +91,7 @@ func TestAuthMiddleware(t *testing.T) {
|
|||||||
|
|
||||||
store := mockdb.NewMockStore(ctrl)
|
store := mockdb.NewMockStore(ctrl)
|
||||||
|
|
||||||
server, err := NewServer(config, store)
|
server, err := NewServer(config, store, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
authPath := "/auth"
|
authPath := "/auth"
|
||||||
server.router.GET(
|
server.router.GET(
|
||||||
|
@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -13,28 +14,38 @@ import (
|
|||||||
|
|
||||||
// Server serves HTTP requests for df service
|
// Server serves HTTP requests for df service
|
||||||
type Server struct {
|
type Server struct {
|
||||||
store db.Store
|
store db.Store
|
||||||
router *gin.Engine
|
router *gin.Engine
|
||||||
config util.Config
|
config util.Config
|
||||||
tokenMaker token.Maker
|
tokenMaker token.Maker
|
||||||
|
swaggerFiles http.FileSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServer creates a new HTTP server and sets up routing
|
// NewServer creates a new HTTP server and sets up routing
|
||||||
func NewServer(config util.Config, store db.Store) (*Server, error) {
|
func NewServer(config util.Config, store db.Store, swaggerFS http.FileSystem) (*Server, error) {
|
||||||
tokenMaker, err := token.NewPasetoMaker(config.TokenPrivateKeyHex)
|
tokenMaker, err := token.NewPasetoMaker(config.TokenPrivateKeyHex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot create token maker: %w", err)
|
return nil, fmt.Errorf("cannot create token maker: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
server := &Server{
|
server := &Server{
|
||||||
store: store,
|
store: store,
|
||||||
config: config,
|
config: config,
|
||||||
tokenMaker: tokenMaker,
|
tokenMaker: tokenMaker,
|
||||||
|
swaggerFiles: swaggerFS,
|
||||||
}
|
}
|
||||||
|
router := gin.New()
|
||||||
|
|
||||||
|
router.Use(gin.Recovery())
|
||||||
|
|
||||||
logLevel := slog.LevelError
|
logLevel := slog.LevelError
|
||||||
if config.Environment == "development" {
|
if config.Environment == "development" {
|
||||||
logLevel = slog.LevelDebug
|
logLevel = slog.LevelDebug
|
||||||
|
// router.Static("/swagger/", "./doc/swagger/")
|
||||||
|
}
|
||||||
|
|
||||||
|
if swaggerFS != nil {
|
||||||
|
router.StaticFS("/swagger/", swaggerFS)
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := slog.HandlerOptions{
|
opts := slog.HandlerOptions{
|
||||||
@ -48,10 +59,6 @@ func NewServer(config util.Config, store db.Store) (*Server, error) {
|
|||||||
|
|
||||||
slog.SetDefault(logger)
|
slog.SetDefault(logger)
|
||||||
|
|
||||||
router := gin.New()
|
|
||||||
|
|
||||||
router.Use(gin.Recovery())
|
|
||||||
|
|
||||||
router.Use(Logger())
|
router.Use(Logger())
|
||||||
|
|
||||||
router.POST("/login", server.loginAccount)
|
router.POST("/login", server.loginAccount)
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
type UpdateAccountPrivacyTxParams struct {
|
type UpdateAccountPrivacyTxParams struct {
|
||||||
ID int64 `json:"ID"`
|
ID int64 `json:"ID"`
|
||||||
Changer string `json:"changer"`
|
Changer string `json:"changer"`
|
||||||
PrivacyAccepted bool `json:"privacy_accepted"`
|
PrivacyAccepted *bool `json:"privacy_accepted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateAccountPrivacyTxResult struct {
|
type UpdateAccountPrivacyTxResult struct {
|
||||||
@ -17,19 +17,16 @@ type UpdateAccountPrivacyTxResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (store *SQLStore) UpdateAccountPrivacyTx(ctx context.Context, arg UpdateAccountPrivacyTxParams) (Account, error) {
|
func (store *SQLStore) UpdateAccountPrivacyTx(ctx context.Context, arg UpdateAccountPrivacyTxParams) (Account, error) {
|
||||||
var result UpdateAccountPrivacyTxResult
|
var date sql.NullTime
|
||||||
param := UpdateAccountPrivacyParams{
|
var account Account
|
||||||
ID: arg.ID,
|
|
||||||
Changer: arg.Changer,
|
|
||||||
}
|
|
||||||
|
|
||||||
if arg.PrivacyAccepted {
|
if *arg.PrivacyAccepted {
|
||||||
param.PrivacyAcceptedDate = sql.NullTime{
|
date = sql.NullTime{
|
||||||
Valid: true,
|
Valid: true,
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
param.PrivacyAcceptedDate = sql.NullTime{
|
date = sql.NullTime{
|
||||||
Valid: true,
|
Valid: true,
|
||||||
Time: time.Time{},
|
Time: time.Time{},
|
||||||
}
|
}
|
||||||
@ -38,9 +35,17 @@ func (store *SQLStore) UpdateAccountPrivacyTx(ctx context.Context, arg UpdateAcc
|
|||||||
|
|
||||||
err := store.execTx(ctx, func(q *Queries) error {
|
err := store.execTx(ctx, func(q *Queries) error {
|
||||||
var err error
|
var err error
|
||||||
result.Account, err = q.UpdateAccountPrivacy(ctx, param)
|
account, err = q.UpdateAccountPrivacy(ctx, UpdateAccountPrivacyParams{
|
||||||
|
PrivacyAccepted: sql.NullBool{
|
||||||
|
Bool: *arg.PrivacyAccepted,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
PrivacyAcceptedDate: date,
|
||||||
|
ID: arg.ID,
|
||||||
|
Changer: arg.Changer,
|
||||||
|
})
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
return result.Account, err
|
return account, err
|
||||||
}
|
}
|
||||||
|
561
bff/doc/swagger/df.swagger.json
Normal file
561
bff/doc/swagger/df.swagger.json
Normal file
@ -0,0 +1,561 @@
|
|||||||
|
{
|
||||||
|
"openapi": "3.1.0",
|
||||||
|
"info": {
|
||||||
|
"title": "df API",
|
||||||
|
"version": "1.0",
|
||||||
|
"contact": {
|
||||||
|
"name": "itsscb",
|
||||||
|
"url": "https://github.com/itsscb/df",
|
||||||
|
"email": "dev@itsscb.de"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"name": "df"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"/accounts/{id}": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": "Get account",
|
||||||
|
"description": "Use this API to get a new account",
|
||||||
|
"operationId": "df_GetAccount",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/GetAccountResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/GetAccountRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"df"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/accounts": {
|
||||||
|
"post": {
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/CreateAccountRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Create new account",
|
||||||
|
"description": "Use this API to create a new account",
|
||||||
|
"operationId": "df_CreateAccount",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/CreateAccountResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/CreateAccountRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"df"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/UpdateAccountRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": "Update account",
|
||||||
|
"description": "Use this API to update account",
|
||||||
|
"operationId": "df_UpdateAccount",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/UpdateAccountResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/UpdateAccountRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"df"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/accounts/privacy": {
|
||||||
|
"put": {
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/UpdateAccountPrivacyRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": "Update account privacy settings",
|
||||||
|
"description": "Use this API to update account privacy settings",
|
||||||
|
"operationId": "df_UpdateAccountPrivacy",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/UpdateAccountPrivacyRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"df"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/login": {
|
||||||
|
"post": {
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"$ref": "#/definitions/LoginAccountRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Login account",
|
||||||
|
"description": "Use this API to login account and get access token \u0026 refresh token",
|
||||||
|
"operationId": "df_LoginAccount",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "A successful response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/LoginAccountResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "An unexpected error response.",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/rpcStatus"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/LoginAccountRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"df"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"bearerAuth": []
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"securitySchemes": {
|
||||||
|
"bearerAuth": {
|
||||||
|
"type": "http",
|
||||||
|
"scheme": "bearer",
|
||||||
|
"bearerFormat": "paseto",
|
||||||
|
"in": "header"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemas": {
|
||||||
|
"Account": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"passwordhash": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "password"
|
||||||
|
},
|
||||||
|
"permission_level": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"privacy_accepted": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"Bool": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"Valid": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"privacy_accepted_date": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"Time": {
|
||||||
|
"type":"string",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"Valid": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"phone": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"String": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"Valid": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"firstname": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"lastname": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"birthday": {
|
||||||
|
"type":"string",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"street": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"city": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"zip": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"creator": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type":"string",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"changer": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"changed": {
|
||||||
|
"type":"string",
|
||||||
|
"format": "date-time"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"definitions": {
|
||||||
|
"CreateAccountRequest": {
|
||||||
|
"required": [
|
||||||
|
"firstname",
|
||||||
|
"lastname",
|
||||||
|
"city",
|
||||||
|
"zip",
|
||||||
|
"street",
|
||||||
|
"country",
|
||||||
|
"email",
|
||||||
|
"password",
|
||||||
|
"birthday"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"firstname": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"lastname": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"city": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"zip": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"street": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"birthday": {
|
||||||
|
"type":"string",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"phone": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "password"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"CreateAccountResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"account": {
|
||||||
|
"$ref": "#/components/schemas/Account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"GetAccountRequest": {
|
||||||
|
"required": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"GetAccountResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"account": {
|
||||||
|
"$ref": "#/components/schemas/Account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"LoginAccountRequest": {
|
||||||
|
"required": [
|
||||||
|
"email",
|
||||||
|
"password"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"email": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "email"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "password"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"UpdateAccountPrivacyRequest": {
|
||||||
|
"required": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"privacy_accepted": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"UpdateAccountPrivacyResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"account": {
|
||||||
|
"$ref": "#/components/schemas/Account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"UpdateAccountRequest": {
|
||||||
|
"required": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64"
|
||||||
|
},
|
||||||
|
"new_password": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "password"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "email"
|
||||||
|
},
|
||||||
|
"firstname": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"lastname": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"phone": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"city": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"zip": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"street": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"birthday": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"UpdateAccountResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"account": {
|
||||||
|
"$ref": "#/components/schemas/Account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"protobufAny": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"@type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": {}
|
||||||
|
},
|
||||||
|
"rpcStatus": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int32"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/protobufAny"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
bff/doc/swagger/favicon-16x16.png
Normal file
BIN
bff/doc/swagger/favicon-16x16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 665 B |
BIN
bff/doc/swagger/favicon-32x32.png
Normal file
BIN
bff/doc/swagger/favicon-32x32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 628 B |
16
bff/doc/swagger/index.css
Normal file
16
bff/doc/swagger/index.css
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
html {
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: -moz-scrollbars-vertical;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after {
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
19
bff/doc/swagger/index.html
Normal file
19
bff/doc/swagger/index.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<!-- HTML for static distribution bundle build -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Swagger UI</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="index.css" />
|
||||||
|
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||||
|
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
|
||||||
|
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
|
||||||
|
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
|
||||||
|
</body>
|
||||||
|
</html>
|
79
bff/doc/swagger/oauth2-redirect.html
Normal file
79
bff/doc/swagger/oauth2-redirect.html
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<title>Swagger UI: OAuth2 Redirect</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
function run () {
|
||||||
|
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||||
|
var sentState = oauth2.state;
|
||||||
|
var redirectUrl = oauth2.redirectUrl;
|
||||||
|
var isValid, qp, arr;
|
||||||
|
|
||||||
|
if (/code|token|error/.test(window.location.hash)) {
|
||||||
|
qp = window.location.hash.substring(1).replace('?', '&');
|
||||||
|
} else {
|
||||||
|
qp = location.search.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
arr = qp.split("&");
|
||||||
|
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
|
||||||
|
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
||||||
|
function (key, value) {
|
||||||
|
return key === "" ? value : decodeURIComponent(value);
|
||||||
|
}
|
||||||
|
) : {};
|
||||||
|
|
||||||
|
isValid = qp.state === sentState;
|
||||||
|
|
||||||
|
if ((
|
||||||
|
oauth2.auth.schema.get("flow") === "accessCode" ||
|
||||||
|
oauth2.auth.schema.get("flow") === "authorizationCode" ||
|
||||||
|
oauth2.auth.schema.get("flow") === "authorization_code"
|
||||||
|
) && !oauth2.auth.code) {
|
||||||
|
if (!isValid) {
|
||||||
|
oauth2.errCb({
|
||||||
|
authId: oauth2.auth.name,
|
||||||
|
source: "auth",
|
||||||
|
level: "warning",
|
||||||
|
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qp.code) {
|
||||||
|
delete oauth2.state;
|
||||||
|
oauth2.auth.code = qp.code;
|
||||||
|
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||||
|
} else {
|
||||||
|
let oauthErrorMsg;
|
||||||
|
if (qp.error) {
|
||||||
|
oauthErrorMsg = "["+qp.error+"]: " +
|
||||||
|
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
||||||
|
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
oauth2.errCb({
|
||||||
|
authId: oauth2.auth.name,
|
||||||
|
source: "auth",
|
||||||
|
level: "error",
|
||||||
|
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
||||||
|
}
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState !== 'loading') {
|
||||||
|
run();
|
||||||
|
} else {
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
run();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
20
bff/doc/swagger/swagger-initializer.js
Normal file
20
bff/doc/swagger/swagger-initializer.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
window.onload = function() {
|
||||||
|
//<editor-fold desc="Changeable Configuration Block">
|
||||||
|
|
||||||
|
// the following lines will be replaced by docker/configurator, when it runs in a docker-container
|
||||||
|
window.ui = SwaggerUIBundle({
|
||||||
|
url: "df.swagger.json",
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
deepLinking: true,
|
||||||
|
presets: [
|
||||||
|
SwaggerUIBundle.presets.apis,
|
||||||
|
SwaggerUIStandalonePreset
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
SwaggerUIBundle.plugins.DownloadUrl
|
||||||
|
],
|
||||||
|
layout: "StandaloneLayout"
|
||||||
|
});
|
||||||
|
|
||||||
|
//</editor-fold>
|
||||||
|
};
|
3
bff/doc/swagger/swagger-ui-bundle.js
Normal file
3
bff/doc/swagger/swagger-ui-bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
bff/doc/swagger/swagger-ui-bundle.js.map
Normal file
1
bff/doc/swagger/swagger-ui-bundle.js.map
Normal file
File diff suppressed because one or more lines are too long
3
bff/doc/swagger/swagger-ui-es-bundle-core.js
Normal file
3
bff/doc/swagger/swagger-ui-es-bundle-core.js
Normal file
File diff suppressed because one or more lines are too long
1
bff/doc/swagger/swagger-ui-es-bundle-core.js.map
Normal file
1
bff/doc/swagger/swagger-ui-es-bundle-core.js.map
Normal file
File diff suppressed because one or more lines are too long
3
bff/doc/swagger/swagger-ui-es-bundle.js
Normal file
3
bff/doc/swagger/swagger-ui-es-bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
bff/doc/swagger/swagger-ui-es-bundle.js.map
Normal file
1
bff/doc/swagger/swagger-ui-es-bundle.js.map
Normal file
File diff suppressed because one or more lines are too long
3
bff/doc/swagger/swagger-ui-standalone-preset.js
Normal file
3
bff/doc/swagger/swagger-ui-standalone-preset.js
Normal file
File diff suppressed because one or more lines are too long
1
bff/doc/swagger/swagger-ui-standalone-preset.js.map
Normal file
1
bff/doc/swagger/swagger-ui-standalone-preset.js.map
Normal file
File diff suppressed because one or more lines are too long
3
bff/doc/swagger/swagger-ui.css
Normal file
3
bff/doc/swagger/swagger-ui.css
Normal file
File diff suppressed because one or more lines are too long
1
bff/doc/swagger/swagger-ui.css.map
Normal file
1
bff/doc/swagger/swagger-ui.css.map
Normal file
File diff suppressed because one or more lines are too long
2
bff/doc/swagger/swagger-ui.js
Normal file
2
bff/doc/swagger/swagger-ui.js
Normal file
File diff suppressed because one or more lines are too long
1
bff/doc/swagger/swagger-ui.js.map
Normal file
1
bff/doc/swagger/swagger-ui.js.map
Normal file
File diff suppressed because one or more lines are too long
17
bff/main.go
17
bff/main.go
@ -2,7 +2,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"embed"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/itsscb/df/bff/api"
|
"github.com/itsscb/df/bff/api"
|
||||||
db "github.com/itsscb/df/bff/db/sqlc"
|
db "github.com/itsscb/df/bff/db/sqlc"
|
||||||
@ -10,7 +13,11 @@ import (
|
|||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:embed doc/swagger
|
||||||
|
var swaggerFiles embed.FS
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
var swaggerFS http.FileSystem
|
||||||
config, err := util.LoadConfig(".")
|
config, err := util.LoadConfig(".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("cannot load config:", err)
|
log.Fatal("cannot load config:", err)
|
||||||
@ -20,8 +27,16 @@ func main() {
|
|||||||
log.Fatalf("could not connect to DB: %s", err)
|
log.Fatalf("could not connect to DB: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.Environment == "development" {
|
||||||
|
subDir, err := fs.Sub(swaggerFiles, "doc/swagger")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("could not import swagger files")
|
||||||
|
}
|
||||||
|
swaggerFS = http.FS(subDir)
|
||||||
|
}
|
||||||
|
|
||||||
store := db.NewStore(conn)
|
store := db.NewStore(conn)
|
||||||
server, err := api.NewServer(config, store)
|
server, err := api.NewServer(config, store, swaggerFS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("could not start server: %s", err)
|
log.Fatalf("could not start server: %s", err)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user