Using internal packages to reduce an API surface
Not every piece of code is reusable. Having a smaller API surface makes it easier for others to adapt and use your code. So, you should not export APIs that are specific to your program.
How to do it...
Create internal
packages to hide implementation details from other packages. Anything under an internal
package can only be imported from the packages under the package containing that internal
package – that is, anything under myproject/internal
can only be imported from the packages under myproject
.
In our example, we placed the database access code into a package where it can be accessed by other programs. However, it does not make sense to expose the HTTP routes to others, as they are specific to this program. So, we will put them under the webform/internal
package.
This is the internal/routes/routes.go
file:
package routes import ( "database/sql" "github.com/gorilla/mux" "net/http" ) func Build(router *mux.Router, conn *sql.DB) { router.Path("/form"). Methods("GET").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, "web/static/form.html") }) router.Path("/form"). Methods("POST").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { handlePost(conn, w, r) }) } func handlePost(conn *sql.DB, w http.ResponseWriter, r *http.Request) { email := r.PostFormValue("email") comment := r.PostFormValue("comment") _, err := conn.ExecContext(r.Context(), "insert into comments (email,comment) values (?,?)", email, comment) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } http.Redirect(w, r, "/form", http.StatusFound) }
Then, we change the main.go
file to use the internal package:
package main import ( "database/sql" "net/http" "github.com/gorilla/mux" _ "modernc.org/sqlite" "github.com/PacktPublishing/Go-Recipes-for-Developers/src/chp1/ webform/internal/routes" "github.com/PacktPublishing/Go-Recipes-for-Developers/src/chp1/ webform/pkg/commentdb" ) func main() { db, err := sql.Open("sqlite", "webform.db") if err != nil { panic(err) } commentdb.InitDB(db) r := mux.NewRouter() routes.Build(r, db) server := http.Server{ Addr: ":8181", Handler: r, } server.ListenAndServe() }