# Adding Command Line Arguments to the Swagger Server The first two parts of my swagger tutorial were dedicated to the straightforward art of getting swagger up and running. While I hope they're helpful, the whole point of those was to get you to the point where you had the Timezone project, so I could teach how to extend the Command Line Arguments of a swagger project. Nobody else, so far as I know, knows how to do this. One thing that I emphasized in [Go Swagger Part 2](TK:) was that `configure_timeofday.go` is the *only* file you should be touching, it's the interface between the server and your business logic. Every example of adding new flags to the command line, even the ones provided by the GoSwagger authors, starts by modifying the file `cmd/\-server/main.go`, one of those files clearly marked `// DO NOT EDIT`. We're not going to edit files marked `// DO NOT EDIT`. To understand the issue, though, we have to understand the tool swagger uses for handling command line arguments, `go-flags`. ## Go-Flags `go-flags` is the tool Swagger uses by default for handling command line arguments. It's a clever tool that uses Go's [tags and retrospection](TK:) features to encade the details of the CLI directly into a structure that will hold the options passed in on the command line. ## The implementation We're going to add a single feature: the default timezone. In Part 2, we hard-coded the default timezone into the handler, but what if we want to change the default timezone more readily than recompiling the binary every time? The Go, Docker, and Kubernetes crowd argue that that's acceptable, but I still want more flexibility. To start, we're going to open a new file it the folder with our handlers and add a new file, `timezone.go`. We're going to put a single tagged structure with a single field to hold our timezone CLI argument, and we're going to use `go-flags` protocol to describe our new command line flag. Here's the whole file: ``` <>= package timeofday type Timezone struct { Timezone string `long:"timezone" short:"t" description:"The default time zone" env:"GOTIME_DEFAULT_TIMEZONE" default:"UTC"` } @ ``` If you want to know what you can do with `go-flags`, open the file `./restapi/server.go` and examine the Server struct there, and compare its contents to what you see when you type `timeofday-server --help`. You can learn a lot by reading even the generated source code. As always, `// DO NOT EDIT THIS FILE`. Next, go into `configure_timeofday.go`, and find the function `configureFlags`. This, unsurprisingly, is where this feature is *supposed* to go. We've already imported the `timeofday` package, so we have access to our new Timezone type. Right above `configureFlags`, let's create an instance of this struct and populate it with defaults: ``` <>= var Timezone = timeofday.Timezone{ Timezone: "UTC", } @ ``` See the comment in configureFlags? Note that `swag` package? You'll have to add it to the imports. It should be already present, as it came with the rest of the swagger installation. Just add: ``` <>= swag "github.com/go-openapi/swag" @ ``` And now modify `configureFlags()`: ``` <>= func configureFlags(api *operations.TimeofdayAPI) { api.CommandLineOptionsGroups = []swag.CommandLineOptionsGroup{ swag.CommandLineOptionsGroup{ ShortDescription: "Time Of Day Service Options", Options: &Timezone, }, } } @ ``` See that `ShortDescription` there? When you run the `--help` option for the server, you'll see a section labeled "Application Options", and another labeled "Help Options". We're adding a new section, "Service Options", which will include our customizations. This conceptually allows us to distinguish between routine options of a microservice, and the *specific* options of *this* microservice. Always distinguish between your framework and your business logic. (I've often seen this written as "always distinguish between execution exceptions and business exceptions," and it's great advice is similarly here.) You can now build your server (`go build ./cmd/timeofday-server/`), and run it (`./timeofday-server --help`), and you'll see your new options. Of course, they don't do anything, we haven't modified your business logic! ## The Context Problem This is where most people have a problem. How do the values that now populate the Timezone struct make their way down to the handlers? There are a number of ways to do this. The "edit `main.go`" people just make it a global variable available to the whole server, but I'm here to tell you doing so is sad and you should feel sad if you do it. What we have here, in our structure that holds our CLI options, is a *context*. How do we set the context? The *correct* way is to modify the handlers so they have the context when they're called upon. The way we do that is via the oldest object-oriented technique of all time, one that dates all the way back to 1959 and the invention of Lisp: *closures*. Remember these lines in `configure_timeofday.go`, from way back? ``` api.TestGetHandler = operations.TestGetHandlerFunc(func(params operations.TestGetParams) middleware.Responder { return middleware.NotImplemented("operation .TestGet has not yet been implemented") }) ``` See that function that actually gets passed to TestHandlerGetFunc()? It's anonymous. We broke it out and gave it a name and stuff and filled it out with business logic and made it work. We're going to go back and replace those lines, *again*, so they look like this: ``` api.TimeGetHandler = operations.TimeGetHandlerFunc(timeofday.GetTime(&Timezone)) api.TimePostHandler = operations.TimePostHandlerFunc(timeofday.PostTime(&Timezone)) ``` Those are no longer references to functions. They're *function calls*! What do those functions return? Well, we know TimeGetHandlerFunc() is expecting a function, so so that function call had better return a function. And indeed it does. ``` func GetTime(timezone *Timezone) func(operations.TimeGetParams) middleware.Responder{ defaultTZ := timezone.Timezone return func(params operations.TimeGetParams) middleware.Responder { // Everything else is the same... except we need *two* levels of // closing } at the end! ``` Now, instead of returning a function defined at compile time, we returned a function that is finalized when GetTime() is called, and it now holds a permanent reference to our Timezone object. Do the same thing for `PostTime`. There's one more thing we have to do. We've moved our default timezone to the `configure_timeofday.go` file, so we don't need it here anymore: ``` func getTimeOfDay(tz *string) (*string, error) { t := time.Now() utc, err := time.LoadLocation(*tz) if err != nil { return nil, errors.New(fmt.Sprintf("Time zone not found: %s", *tz)) } thetime := t.In(utc).String() return &thetime, nil } ``` And that's it. That's everything. You can add all the command line arguments you want, and only preserve the fields that are relevant to the particular handler you're going to invoke. And *that's* how you add command line arguments to Swagger servers correctly.