8 Structuring packages and services

 

This chapter covers

  • Effectively organizing and structuring packages to avoid import cycles.
  • Simplifying the usage of types by making their zero value useful.
  • Protecting against unsafe concurrent use of shared state with mutexes.
  • Implementing and testing HTTP servers with the http and httptest packages.
  • Recording HTTP responses with custom test helpers to streamline testing.

Bite is a fictional startup that aims to disrupt online link management services. Their first service is a REST API that shortens long URLs to short keys for easy sharing and redirects clients to the original URLs from short keys. Let's sneak peek before the chapter goals.

NOTE

REST (Representational State Transfer) is an API design approach that enables programs to communicate, typically over HTTP, using methods like GET and POST.

We first start serving our REST API over HTTP:

$ ./linkd  #A
. . .app=linkd addr=localhost:8080  #A

Sending a POST request shortens the link and returns a key:

$ curl link/shorten -d'url=https://x.com/inancgumus' #A
OQzXIiL4  #B

Sending a GET request with the key redirects us to the original URL:

$ curl link/r/OQzXIiL4  #A
Location: https://x.com/inancgumus

This chapter and the next three explain how to structure maintainable packages and avoid import cycles, showcasing a microservice that serves clients over HTTP as a showcase. Our project will touch on many Go philosophies and patterns for writing maintainable code.

8.1 Organizing and structuring packages

8.1.1 Avoiding import cycles

8.1.2 Structuring packages in practice

8.2 Core

8.2.1 Errors

8.2.2 Core

8.2.3 Service

8.2.4 Mutex

8.3 HTTP

8.3.1 Health check

8.3.2 Serving HTTP

8.3.3 HTTP server

8.4 HTTP handlers

8.4.1 Handler closures

8.4.2 Redirecting

8.4.3 HTTP status codes

8.5 Routing

8.5.1 ServeMux

8.5.2 Routes

8.5.3 Demonstration

8.6 Timeouts

8.7 Testing

8.7.1 Response recording

8.7.2 Testing a handler