gocrud

package module
v0.0.0-...-4dc1058 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 8, 2025 License: MIT Imports: 24 Imported by: 0

README

gocrud

Template for go crud applications we use. Also some generic handler functions and helpers we use.

Installation

go get github.com/dargasht/gocrud

What we use

  • go-fiber for http server
  • pgx/v5 for database
  • pgxpool for database connection pool
  • sonic for json marshall/unmarshall
  • zap for logging
  • sqlc for database code generation
  • sqlc for some wierd queries that can't be done with sqlc
  • goose for database migrations

what we enjoy

  • excessive use of postgres json_agg function
  • simple architecture with no magic (maybe some magic, but not too much)
  • no ORM
  • writing raw sql queries
  • simplicity simplicity and simplicity

Folder structure

.
├── bin # for binaries (should be added in gitignore)
├── cfg # for configs
├── cmd
│   └── api
│       └── main.go # the main entry point
├── database
│   ├── migration # for database migrations
│   ├── query # for database queries
│   ├── repo # for sqlc generated queries and models 
│   └── store # for specific database implementations that uses sqlx
├── handler # for http handlers (data transformation and validation)
├── middleware # for http middlewares (if needed)
├── model # for service models and handler models (DTOs)
├── router # for instantiating handlers and injecting dependencies
├── service # for business logic (if needed)
└── utils # for utility functions 

Things to keep in mind:

  • services should be stateless and not depend on external services
  • use service layer if business logic is not simple otherwise use handler layer
  • go to each folder in the internal folder and read the README.md

Usefull stuff in this package are:

Documentation

Index

Constants

View Source
const (

	// ERROR MESSAGES
	InternalServerError      = "خطای داخلی سرور"
	InvalidJsonBody          = "بدنه ی درخواست معتبر نیست"
	InvalidRequest           = "درخواست شما معتبر نیست"
	CreateError              = "در ایجاد ایتم مورد نظر خطایی رخ داد"
	DeleteError              = "در حذف ایتم مورد نظر خطایی رخ داد"
	NoDataFound              = "داده ای یافت نشد"
	BadPerson                = "ای ناقلا 🤡🤡🤡 این کارا چیه؟"
	IncorrectOTP             = "کد احراز هویت اشتباه می باشد"
	InvalidToken             = "توکن نامعتبر است"
	PermissionNotAllowed     = "شما به این قسمت دسترسی ندارید"
	UploadError              = "خطا در آپلود فایل"
	UpdateError              = "خطایی در بروزرسانی داده رخ داد"
	UpdateDoneButImageFailed = "" /* 126-byte string literal not displayed */
	DataNotUnique            = "داده ای با این مشخصات وجود دارد"
	ImageNotFound            = "تصویری یافت نشد"

	//
	Success           = "عملیات موفقیت آمیز"
	SendingOTP        = "کد احراز هویت با موفقیت ارسال شد"
	Wait2Minutes      = "لطفا 2 دقیقه دیگر امتحان کنید"
	EmptyCart         = "سبد خرید خالی است"
	ProductOutOfStock = "محصول موجود نمی باشد"
	Friend            = "دوست"
)

Variables

View Source
var ErrNotFound error = errors.New("no data found")

Some Simple errors

View Source
var GoCRUDConfig = SetConfig()

GoCRUDConfig is the default config You should set this to your needs in your main file Look at the main file in the example

Functions

func Authenticate

func Authenticate(source string, h *HandlerConfig, c *fiber.Ctx) (repo.User, error)

This is Very usefull for authenticating the user Usefull for most crud applications

func CRUDErrorHandler

func CRUDErrorHandler(log *zap.Logger) fiber.ErrorHandler

This function for handling errors that are returned from the handlers Just use it

func DecodeJWT

func DecodeJWT(tokenString string) (jwt.MapClaims, error)

This is for decoding the jwt not much to explain

func EnsureAdmin

func EnsureAdmin(source string, h *HandlerConfig, c *fiber.Ctx) error

EnsureAdmin checks if the user is admin You can make this in a middleware This is just an example for a system who has admin role You can use it as a template for your system and roles

func GenerateToken

func GenerateToken(userID int32) (string, error)

This is for generating tokens not much to explain

func GetJWTFromHeader

func GetJWTFromHeader(c *fiber.Ctx, authScheme string) (string, error)

This is for getting the jwt from header not much to explain

func GetPagination

func GetPagination(c *fiber.Ctx) (page int, limit int, offset int)

GetPagination returns page, limit and offset

func GetPaginationNoLimit

func GetPaginationNoLimit(c *fiber.Ctx) (page int, limit int, offset int)

GetPaginationNoLimit returns page, limit and offset Use in rare cases that user wants to get alot of data

func GetUserIDFromJWT

func GetUserIDFromJWT(c *fiber.Ctx) int32

For cases that a request can contain or not contain a token Use this to get the user id

func NewCreateAdminJSONHandler

func NewCreateAdminJSONHandler[T CReq[U], U CRepo, R CRes](
	c *fiber.Ctx,
	h *HandlerConfig,
	source string,
	createFunc func(context.Context, U) (R, error),
) error

func NewDeleteAdminJSONHandler

func NewDeleteAdminJSONHandler(
	c *fiber.Ctx,
	h *HandlerConfig,
	source string,
	updateFunc func(context.Context, int32) (int64, error),
) error

func NewUpdateAdminJSONHandler

func NewUpdateAdminJSONHandler[T UReq[U], U URepo](
	c *fiber.Ctx,
	h *HandlerConfig,
	source string,
	updateFunc func(context.Context, U) (int64, error),
) error

func SendOTP

func SendOTP(mobile string, logger *zap.Logger) error

This is for sending otp

func SetupS3Client

func SetupS3Client(accessKey, secretKey, endpoint string) *s3.Client

This is for setting up the db call this in the main file and set it to gocrud.GoCRUDConfig Object

func UploadToS3

func UploadToS3(
	ctx context.Context,
	client *s3.Client,
	file multipart.File,
	fileName string,
	folderName string,
) error

UploadToS3 uploads a file to S3

func ValidateOTP

func ValidateOTP(mobile, otp string) bool

This is for validating otp

Types

type CRUDError

type CRUDError struct {
	Code            int      `json:"code"`
	Message         string   `json:"message"`
	Source          string   `json:"-"`
	InternalMessage string   `json:"-"`
	Args            []string `json:"-"`
}

func NewCRUDError

func NewCRUDError(code int, message string, source string, internalMessage string, args ...string) *CRUDError

Only use when there is no error and want to create a new error I barely use this one

func NewCreateError

func NewCreateError(source string, err error, args ...string) *CRUDError

func NewDBError

func NewDBError(source string, err error, args ...string) *CRUDError

------------------------------------------------------------------ ------------------- Database Errors ------------------------------ ------------------------------------------------------------------

func NewDeleteError

func NewDeleteError(source string, err error, args ...string) *CRUDError

func NewInvalidTokenError

func NewInvalidTokenError(source string, internalMessage string) *CRUDError

func NewJSONError

func NewJSONError(source string, err error, args ...string) *CRUDError

------------------------------------------------------------------ ---------------- JSON and Validation Errors ---------------------- ------------------------------------------------------------------

func NewNotFoundError

func NewNotFoundError(source string, err error, args ...string) *CRUDError

Used for 404

func NewPermissionError

func NewPermissionError(source string, internalMessage string, args ...string) *CRUDError

------------------------------------------------------------------ ------------------- Other Errors --------------------------------- ------------------------------------------------------------------

func NewUpdateError

func NewUpdateError(source string, err error, args ...string) *CRUDError

func NewValidationError

func NewValidationError(source string, err error, args ...string) *CRUDError

func (*CRUDError) Error

func (e *CRUDError) Error() string

This is what make this struct error

type CRepo

type CRepo interface {
}

type CReq

type CReq[T CRepo] interface {
	ToRepo() T
}

type CRes

type CRes interface {
}

type Config

type Config struct {
	// contains filtered or unexported fields
}

Config for GoCRUD

func SetConfig

func SetConfig(options ...ConfigOption) *Config

SetConfig sets the config Look at the main file in the example

type ConfigOption

type ConfigOption func(*Config)

func WithAppName

func WithAppName(appName string) ConfigOption

Options

func WithAuthSecret

func WithAuthSecret(authSecret string) ConfigOption

func WithLanguage

func WithLanguage(language string) ConfigOption

func WithOtpApiKey

func WithOtpApiKey(otpApiKey string) ConfigOption

func WithS3Client

func WithS3Client(s3Client *s3.Client, bucketName string) ConfigOption

type HandlerConfig

type HandlerConfig struct {
	DB     *repo.Queries
	Logger *zap.Logger
}

Example of what a handler config should look like It is not recommanded to use this just write your own

func NewHandlerConfig

func NewHandlerConfig(db *repo.Queries, logger *zap.Logger) *HandlerConfig

Creates a new handler config This is not recommanded to use this just write your own

type Meta

type Meta struct {
	CurrentPage int `json:"current_page"`
	LastPage    int `json:"last_page"`
	Total       int `json:"total"`
	FromIndex   int `json:"from_index"`
	ToIndex     int `json:"to_index"`
	PerPage     int `json:"per_page"`
}

func GetPaginationMeta

func GetPaginationMeta(page int, limit int, size int) Meta

GetPaginationMeta returns pagination meta For putting in the response

type OTP

type OTP struct {
	Code      string
	Timestamp time.Time
}

type OTPStore

type OTPStore struct {
	// contains filtered or unexported fields
}

type Res

type Res[T any] struct {
	Data    T      `json:"data"`
	Message string `json:"message"`
	Status  int    `json:"status"`
}

Standard response suitable for most handlers

func NewRes

func NewRes[T any](data T, message string, status int) Res[T]

type ResWithMeta

type ResWithMeta[T any] struct {
	Data    T      `json:"data"`
	Message string `json:"message"`
	Status  int    `json:"status"`
	Meta    Meta   `json:"meta,omitempty"`
}

Standard response suitable for handlers who do pagination In go 1.24 when the new omitzero json tag will be introduced we can merge the 2 responses probably

func NewResWithMeta

func NewResWithMeta[T any](data T, message string, status int, meta Meta) ResWithMeta[T]

type URepo

type URepo interface{}

type UReq

type UReq[T URepo] interface {
	SetID(id int32) any
	ToRepo() T
}

Directories

Path Synopsis
internal
cfg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL