gokit_realworld

package module
v0.0.0-...-c4bde49 Latest Latest
Warning

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

Go to latest
Published: Jul 20, 2020 License: MIT Imports: 7 Imported by: 0

README

RealWorld Example App

Golang/Gokit codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the RealWorld spec and API.
Demo    RealWorld

Build Status

This codebase was created to demonstrate a fully fledged fullstack application built with Golang/Gokit including CRUD operations, authentication, routing, pagination, and more.

Getting started

Install Golang (go1.11+)

Please check the official golang installation guide before you start. Official Documentation Also make sure you have installed a go1.11+ version.

Environment Config

make sure your ~/.*shrc have those variable:

➜  echo $GOPATH
/Users/xesina/go
➜  echo $GOROOT
/usr/local/go/
➜  echo $PATH
...:/usr/local/go/bin:/Users/xesina/test//bin:/usr/local/go/bin

For more info and detailed instructions please check this guide: Setting GOPATH

Clone the repository

Clone this repository:

➜ git clone https://github.com/xesina/gokit-realworld.git

Or simply use the following command which will handle cloning the repo:

➜ go get -u -v github.com/xesina/gokit-realworld

Switch to the repo folder

➜ cd $GOPATH/src/github.com/xesina/gokit-realworld
Install dependencies
➜ go mod download
Run
➜ go run main.go
Build
➜ go build
Tests
➜ go test ./...

Documentation

Index

Constants

View Source
const (
	// Action cannot be performed.
	EConflict = "conflict"
	// Internal error.
	EInternal = "internal"
	// Entity does not exist.
	ENotFound = "not_found"
	// Too many API requests.
	ERateLimit = "rate_limit"
	// User ID validation failed.
	EInvalidUserID = "invalid_user_id"
	// Username validation failed.
	EInvalidUsername   = "invalid_username"
	EIncorrectPassword = "incorrect_password"
)

Application error codes.

Variables

View Source
var (
	ErrArticleNotFound      = Error{ENotFound, errors.New("article not found")}
	ErrArticleAlreadyExists = Error{EConflict, errors.New("article already exists")}
)
View Source
var (
	ErrResourceNotFound       = Error{ENotFound, errors.New("resource not found")}
	ErrUserNotFound           = Error{ENotFound, errors.New("user not found")}
	ErrUserAlreadyExists      = Error{EConflict, errors.New("user already exists")}
	ErrIncorrectPasswordError = Error{EIncorrectPassword, errors.New("incorrect password")}
)

Functions

func ErrorCode

func ErrorCode(err error) string

ErrorCode returns the code of the error, if available.

func InternalError

func InternalError(err error) error

Types

type Article

type Article struct {
	ID          int64
	Slug        string
	Title       string
	Description string
	Body        string
	Author      User
	Comments    Comments
	Favorites   Favorites
	Tags        Tags
	CreatedAt   time.Time
	UpdatedAt   time.Time
}

func (Article) Favorited

func (a Article) Favorited(id int64) bool

func (Article) MakeSlug

func (a Article) MakeSlug() string

type ArticleRepo

type ArticleRepo interface {
	Get(slug string) (*Article, error)
	List(offset, limit int) ([]*Article, int, error)
	ListByTag(tag string, offset, limit int) ([]*Article, int, error)
	ListByAuthorID(id int64, offset, limit int) ([]*Article, int, error)
	ListByFavoriterID(id int64, offset, limit int) ([]*Article, int, error)
	Feed(req FeedRequest) ([]*Article, int, error)
	Create(u Article) (*Article, error)
	Update(slug string, u Article) (*Article, error)
	Delete(u Article) error
	AddFavorite(a Article, u User) (*Article, error)
	RemoveFavorite(a Article, u User) (*Article, error)
	AddComment(c Comment) (*Comment, error)
	DeleteComment(c Comment) error
	Comments(a Article) ([]*Comment, error)
	Tags() ([]*Tag, error)
}

type ArticleService

type ArticleService interface {
	Create(a Article) (*Article, error)
	Update(slug string, a Article) (*Article, error)
	Get(a Article) (*Article, error)
	List(r ListRequest) ([]*Article, int, error)
	Feed(r FeedRequest) ([]*Article, int, error)
	Delete(a Article) error
	Favorite(a Article, u User) (*Article, error)
	Unfavorite(a Article, u User) (*Article, error)
	AddComment(c Comment) (*Comment, error)
	DeleteComment(c Comment) error
	Comments(a Article) ([]*Comment, error)
	Tags() ([]*Tag, error)
}

type Bio

type Bio struct {
	Value string
	Valid bool
}

func (Bio) MarshalJSON

func (b Bio) MarshalJSON() ([]byte, error)

func (*Bio) UnmarshalJSON

func (b *Bio) UnmarshalJSON(bytes []byte) error

type Comment

type Comment struct {
	ID        int64
	Article   Article
	ArticleID int64
	UserID    int64
	Body      string
	CreatedAt time.Time
	UpdatedAt time.Time
}

type Comments

type Comments map[int64]Comment

type Error

type Error struct {
	Code string
	Err  error
}

func (Error) Error

func (e Error) Error() string

func (Error) Unwrap

func (e Error) Unwrap() error

type Favorites

type Favorites map[int64]struct{}

func (Favorites) FavoritedBy

func (ff Favorites) FavoritedBy(id int64) bool

type FeedRequest

type FeedRequest struct {
	UserID       int64
	FollowingIDs []int64
	Limit        int
	Offset       int
}

type FollowRequest

type FollowRequest struct {
	Followee string
	Follower int64
}

type Follows

type Follows map[int64]struct{}

func (Follows) List

func (ff Follows) List() (l []int64)

type Image

type Image struct {
	Value string
	Valid bool
}

func (Image) MarshalJSON

func (i Image) MarshalJSON() ([]byte, error)

func (*Image) UnmarshalJSON

func (i *Image) UnmarshalJSON(bytes []byte) error

TODO: check: if we can extract these methods to a generic methods/type and attach these to the type

type ListRequest

type ListRequest struct {
	Tag         string
	AuthorID    int64
	FavoriterID int64
	Offset      int
	Limit       int
}

type Tag

type Tag struct {
	ID       int64
	Tag      string
	Articles []Article
}

type Tags

type Tags map[string]Tag

func (Tags) HasTag

func (tt Tags) HasTag(t string) bool

func (Tags) TagsList

func (tt Tags) TagsList() (tagList []string)

type User

type User struct {
	ID         int64
	Username   string
	Email      string
	Password   string
	Bio        Bio
	Image      Image
	Followers  Follows
	Followings Follows
}

TODO: where should we put the validation? Should we have separate validation per domain model and transports?

func (*User) CheckPassword

func (u *User) CheckPassword(plain string) bool

func (*User) HashPassword

func (u *User) HashPassword(plain string) (string, error)

func (*User) IsFollower

func (u *User) IsFollower(follower *User) bool

type UserRepo

type UserRepo interface {
	// TODO: should this return user? What if we assume this should only be a **write** command
	Create(u User) (*User, error)
	Update(u User) (*User, error)
	Get(e string) (*User, error)
	GetByID(id int64) (*User, error)
	GetByUsername(u string) (*User, error)
	AddFollower(follower, followee int64) (*User, error)
	RemoveFollower(follower, followee int64) (*User, error)
}

type UserService

type UserService interface {
	Register(user User) (*User, error)
	Login(user User) (*User, error)
	Get(user User) (*User, error)
	Update(user User) (*User, error)
	GetProfile(user User) (*User, error)
	Follow(req FollowRequest) (*User, error)
	Unfollow(req FollowRequest) (*User, error)
}

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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