Course page
Log in

You are watching a free preview. Enroll to open all 24 lessons, track progress and ask the course tutor.

Enroll for $59.99

Section 1: Go services from the ground up

Go refresher for service code

Article 14 min Lesson 2 of 24 Preview

If you already write Go, skim this lesson. If not, these are the features we use throughout the course.

Structs and methods

type Item struct {
	ID        int64     `json:"id"`
	Name      string    `json:"name"`
	OwnerID   int64     `json:"-"`
	CreatedAt time.Time `json:"created_at"`
}

func (i Item) IsNew(now time.Time) bool {
	return now.Sub(i.CreatedAt) < 24*time.Hour
}

Struct tags like json:"name" control how fields are encoded. A tag of json:"-" hides a field from JSON output. Only exported fields, starting with a capital letter, are visible to other packages and to the JSON encoder.

Errors are values

item, err := store.GetItem(ctx, id)
if err != nil {
	return fmt.Errorf("get item %d: %w", id, err)
}

Functions return an error as their last value. You check it immediately. Wrapping with %w adds context while keeping the original error inspectable. Callers can test for a specific error with errors.Is:

var ErrNotFound = errors.New("not found")

if errors.Is(err, ErrNotFound) {
	// respond with 404
}

Interfaces are small and implicit

type ItemStore interface {
	GetItem(ctx context.Context, id int64) (Item, error)
	CreateItem(ctx context.Context, in NewItem) (Item, error)
}

A type satisfies an interface automatically if it has the methods. No implements keyword. Define interfaces where they are used, not where they are implemented, and keep them small. Our handlers depend on an ItemStore interface, so tests can pass a fake.

Slices and maps

names := make([]string, 0, len(items))
for _, it := range items {
	names = append(names, it.Name)
}
counts := map[string]int{}
counts["overdue"]++

Goroutines and channels, briefly

go doWork() starts a goroutine. Channels pass values between goroutines. In a typical service, the HTTP server creates goroutines for you, and you write goroutines yourself mainly for background jobs. We will use them sparingly and always with a way to stop them.

Modules

go mod init github.com/you/lendr
go get github.com/jackc/pgx/v5

go.mod records the module path and dependencies, and go.sum stores checksums. Both are committed.

Run go vet ./... and gofmt -l . often. They catch common mistakes and formatting differences before review.

← → switch lessons