It very much is by using interfaces.
Let‘s assume you create a web applications and you want to display users.
First, you‘d define an interface like
type Creator interface{
Create(u User)(User,error)
}
type Reader interface{
Read(k PrimaryKey)(User, error)
ListAll()([]User,error)
ListPaginated(page, offset int)([]User,error)
}
type Updater interface{
Update(u User)(User, error)
UpdateByKey(k PrimaryKey, u User)(User, error)
UpdateMany(...User)error
}
type Deleter interface{
Delete(u User)error
DeleteMany(u ...User)error
DeleteByKey(keys ...PrimaryKey)error
}
type CRUD interface {
Creator
Reader
Updater
Deleter
}
Next, implement the CRUD interface for each database type you want to support.
Now, you can create a handler:
// ListHandler uses an interface instead of a concrete type to
// retrieve the data from the databases.
// Not only does this approach make it possible to provide different
// implementations, but it makes unit testing way easier.
//
// "Thou Shalt Write Tests"
func ListHandler(rdr Reader) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Pagination ommited for brevity
// Note that the handler is agnostic of the underlying implementation.
u, err := rdr.ListAll()
if err != nil {
log.Printf("ListHandler: error retrieving user list: %s", err)
// Do not do this in production! It might give an attacker information
// Use a static error message instead!
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(u); err != nil {
log.Printf("ListHandler: error encoding user list to JSON: %s", err)
// See above
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
}
and set it up something like this:
func main() {
// Get your config
// Then simply use an implementation of CRUD
var dbConn CRUD
switch cfg.DbType {
case "myql":
// returns your implementation of CRUD using MySQL
dbConn = createMySQLConnector(cfg)
case "oracle":
// returns your implementation of CRUD using Oracle
dbConn = createOracleConnector(cfg)
}
http.Handle("/users/", ListHandler(dbConn))
log.Fatal(http.ListenAndServe("0.0.0.0:8080", nil))
}
hth