Admin CLI Interface
Part of the Object Oriented Programming section of Coddy's GO journey — lesson 103 of 107.
Challenge
EasyLet's build a command-line interface for our Library Management System using the Command Pattern! You'll create a CLI that processes admin commands like adding books, registering users, and managing borrowing operations—all through a clean, extensible architecture.
You'll organize your code across six files:
book.go: YourBookstruct with JSON tags forID,Title,Author,ISBN, andAvailable. Include theNewBookconstructor.user.go: YourUserstruct with JSON tags forID,Name,Email, andBorrowedBooks. Include theNewUserconstructor.library.go: YourLibrarystruct with maps for books and users, along withAddBook,AddUser,Borrow, andReturnmethods from previous lessons.commands.go: This is where the Command Pattern comes to life! Define aCommandinterface with anExecutemethod that takes a*Libraryand[]stringargs, returning a string result. Then implement these command structs:AddBookCommand— expects 4 args: id, title, author, isbn. Adds the book and returnsBook added: [title]AddUserCommand— expects 3 args: id, name, email. Adds the user and returnsUser added: [name]BorrowCommand— expects 2 args: userID, bookID. ReturnsBorrowed: [bookID]on success, orError: [message]on failureReturnCommand— expects 2 args: userID, bookID. ReturnsReturned: [bookID]on success, orError: [message]on failureListBooksCommand— takes no args. Returns each book's ID and title on separate lines in format[id]: [title], orNo booksif empty (list books sorted by ID)
If a command receives insufficient arguments, return
Error: insufficient argumentscli.go: Create aCLIstruct that holds a pointer to aLibraryand a map of command names toCommandimplementations. Build:NewCLIconstructor that initializes the CLI with a library and registers all commands:addbook,adduser,borrow,return,listbooksRunmethod that takes an input string, parses it usingstrings.Fields, looks up the command, and executes it. ReturnNo command providedfor empty input, orUnknown command: [name]for unrecognized commands
main.go: Create a library and CLI, then process commands from input. Read the number of commands, then read each command string on a separate line. For each command, callRunand print the result.
The following inputs will be provided:
- Number of commands
- Each command as a complete string on its own line
For example, given:
6
addbook B001 Go-Programming Alan-Donovan 978-0134190440
addbook B002 Clean-Code Robert-Martin 978-0132350884
adduser U001 Alice alice@test.com
borrow U001 B001
listbooks
borrow U001 B001Your output should be:
Book added: Go-Programming
Book added: Clean-Code
User added: Alice
Borrowed: B001
B001: Go-Programming
B002: Clean-Code
Error: book not availableAnd given:
4
listbooks
addbook B100 Design-Patterns Gang-of-Four 978-0201633610
listbooks
invalidcmd testYour output should be:
No books
Book added: Design-Patterns
B100: Design-Patterns
Unknown command: invalidcmdAnd given:
5
adduser U001 Bob bob@email.com
borrow U001 B001
addbook B001 Golang-Guide John-Smith 123-456
borrow U001 B001
return U001 B001Your output should be:
User added: Bob
Error: book not found
Book added: Golang-Guide
Borrowed: B001
Returned: B001Notice how the CLI doesn't need to know the details of each operation—it simply looks up the command and delegates execution. This makes adding new commands as simple as creating a new struct that implements the Command interface and registering it in the CLI!
Try it yourself
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
// Read the number of commands
var n int
fmt.Scanln(&n)
// Create a scanner to read full lines
scanner := bufio.NewScanner(os.Stdin)
// TODO: Create a new Library
// TODO: Create a new CLI with the library
// TODO: Process each command
// For each of the n commands:
// - Read the command line using scanner.Scan() and scanner.Text()
// - Run the command through the CLI
// - Print the result
_ = scanner // Remove this line when you use scanner
}
All lessons in Object Oriented Programming
1Fundamentals of Go OOP
External FilesGo Workspace & ModulesPackages & ImportsExported vs Unexported NamesIntroduction to OOP in GoStructs as ClassesDefining Methods on StructsPointer vs Value ReceiversStruct InitializationConstructor FunctionsRecap - Simple Calculator4Interfaces
Introduction to InterfacesImplicit ImplementationInterface as ContractEmpty Interface (any)Type AssertionType SwitchInterface CompositionStringer & Error InterfacesRecap - Shape Calculator7Encapsulation
Exported vs Unexported FieldsPackage-Level EncapsulationGetter & Setter MethodsInformation Hiding in GoRecap - Student Records10Generics (Go 1.18+)
Introduction to GenericsType ParametersType ConstraintsGeneric StructsGeneric Methods WorkaroundRecap - Generic Collection2Types & Structs Deep Dive
Basic & Composite TypesCustom Type DefinitionsStruct TagsAnonymous StructsNested StructsZero Values & DefaultsRecap - Contact Book5Composition Over Inheritance
Why Go Has No InheritanceStruct Embedding BasicsMethod PromotionEmbedding Multiple StructsEmbedding vs AggregationShadowing Embedded MethodsRecap - Employee Hierarchy8Error Handling & OOP
The error InterfaceCustom Error TypesError Wrapping (fmt.Errorf)Sentinel Errorserrors.Is() and errors.As()Panic, Defer, and RecoverRecap - File Parser3Pointers & Memory
Pointer Basics in GoPointers to StructsPass by Value vs ReferenceThe new() FunctionGarbage Collection in GoRecap - Linked List Builder6Polymorphism in Go
Polymorphism via InterfacesDuck Typing in GoInterface Satisfaction RulesPolymorphic CollectionsDependency InjectionRecap - Payment Processor9Concurrency & OOP
Goroutines BasicsChannels & CommunicationBuffered vs Unbuffered ChanSelect Statementsync.Mutex & sync.RWMutexsync.WaitGroupThread-Safe Struct DesignRecap - Worker Pool12Advanced OOP Concepts
Functional Options PatternBuilder Pattern in GoMethod ChainingType Aliases vs DefinitionsReflection BasicsCode Generation Overview15Project: Library Management
Project Overview & StructureBook and User Structs