diff --git a/pkg/bindings/generator/generator.go b/pkg/bindings/generator/generator.go
new file mode 100644
index 0000000000..24c2310ff4
--- /dev/null
+++ b/pkg/bindings/generator/generator.go
@@ -0,0 +1,234 @@
+package main
+
+import (
+	"errors"
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/token"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"strings"
+	"text/template"
+	"time"
+)
+
+var bodyTmpl = `package {{.PackageName}}
+
+import (
+{{range $import := .Imports}}	{{$import}}
+{{end}}
+
+)
+
+/*
+This file is generated automatically by go generate.  Do not edit.
+
+Created {{.Date}}
+*/
+
+// Changed
+func (o *{{.StructName}}) Changed(fieldName string) bool {
+	r := reflect.ValueOf(o)
+	value := reflect.Indirect(r).FieldByName(fieldName)
+	return !value.IsNil()
+}
+
+// ToParams
+func (o *{{.StructName}}) ToParams() (url.Values, error) {
+	params := url.Values{}
+	if o == nil {
+		return params, nil
+	}
+	json := jsoniter.ConfigCompatibleWithStandardLibrary
+	s := reflect.ValueOf(o)
+	if reflect.Ptr == s.Kind() {
+		s = s.Elem()
+	}
+	sType := s.Type()
+	for i := 0; i < s.NumField(); i++ {
+		fieldName := sType.Field(i).Name
+		if !o.Changed(fieldName) {
+			continue
+		}
+		f := s.Field(i)
+		if reflect.Ptr == f.Kind() {
+			f = f.Elem()
+		}
+		switch f.Kind() {
+		case reflect.Bool:
+			params.Set(fieldName, strconv.FormatBool(f.Bool()))
+		case reflect.String:
+			params.Set(fieldName, f.String())
+		case reflect.Int, reflect.Int64:
+			// f.Int() is always an int64
+			params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+		case reflect.Slice:
+			typ := reflect.TypeOf(f.Interface()).Elem()
+			slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap())
+			switch typ.Kind() {
+			case reflect.String:
+				s, ok := slice.Interface().([]string)
+				if !ok {
+					return nil, errors.New("failed to convert to string slice")
+				}
+				for _, val := range s {
+					params.Add(fieldName, val)
+				}
+			default:
+				return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+			}
+		case reflect.Map:
+			lowerCaseKeys := make(map[string][]string)
+			// I dont know if this code is needed anymore, TBD
+			// for k, v := range filters {
+			// 	lowerCaseKeys[strings.ToLower(k)] = v
+			// }
+			s, err := json.MarshalToString(lowerCaseKeys)
+			if err != nil {
+				return nil, err
+			}
+
+			params.Set(fieldName, s)
+		default:
+			return nil, errors.Errorf("unknown type %s", f.Kind().String())
+		}
+	}
+	return params, nil
+}
+`
+
+var fieldTmpl = `
+// With{{.Name}}
+func(o *{{.StructName}}) With{{.Name}}(value {{.Type}}) *{{.StructName}} {
+	v := &value
+	o.{{.Name}} = v
+	return o
+}
+`
+
+type fieldStruct struct {
+	Name       string
+	StructName string
+	Type       string
+}
+
+func main() {
+	var (
+		closed       bool
+		fieldStructs []fieldStruct
+		structNode   ast.Node
+	)
+	srcFile := os.Getenv("GOFILE")
+	pkg := os.Getenv("GOPACKAGE")
+	inputStructName := os.Args[1]
+	b, err := ioutil.ReadFile(srcFile)
+	if err != nil {
+		panic(err)
+	}
+	fset := token.NewFileSet() // positions are relative to fset
+	f, err := parser.ParseFile(fset, "", b, parser.ParseComments)
+	if err != nil {
+		panic(err)
+	}
+
+	// always add reflect
+	imports := []string{"\"reflect\""}
+	for _, imp := range f.Imports {
+		imports = append(imports, imp.Path.Value)
+	}
+
+	out, err := os.Create(strings.ToLower(inputStructName) + "_" + srcFile)
+	if err != nil {
+		panic(err)
+	}
+	defer func() {
+		if !closed {
+			out.Close()
+		}
+	}()
+	bodyStruct := struct {
+		PackageName string
+		Imports     []string
+		Date        string
+		StructName  string
+	}{
+		PackageName: pkg,
+		Imports:     imports,
+		Date:        time.Now().String(),
+		StructName:  inputStructName,
+	}
+
+	body := template.Must(template.New("body").Parse(bodyTmpl))
+	fields := template.Must(template.New("fields").Parse(fieldTmpl))
+	ast.Inspect(f, func(n ast.Node) bool {
+		ref, refOK := n.(*ast.TypeSpec)
+		if refOK {
+			if ref.Name.Name == inputStructName {
+				structNode = n
+				x := ref.Type.(*ast.StructType)
+				for _, field := range x.Fields.List {
+					var (
+						name string
+					)
+					typeExpr := field.Type
+					start := typeExpr.Pos() - 1
+					end := typeExpr.End() - 1
+					fieldType := strings.Replace(string(b[start:end]), "*", "", 1)
+					if len(field.Names) > 0 {
+						name = field.Names[0].Name
+						if len(name) < 1 {
+							panic(errors.New("bad name"))
+						}
+					}
+					fStruct := fieldStruct{
+						Name:       name,
+						StructName: inputStructName,
+						Type:       fieldType,
+					}
+					fieldStructs = append(fieldStructs, fStruct)
+				} // for
+
+				// create the body
+				if err := body.Execute(out, bodyStruct); err != nil {
+					fmt.Println(err)
+					os.Exit(1)
+				}
+
+				// create with func from the struct fields
+				for _, fs := range fieldStructs {
+					if err := fields.Execute(out, fs); err != nil {
+						fmt.Println(err)
+						os.Exit(1)
+					}
+				}
+
+				// close out file
+				if err := out.Close(); err != nil {
+					fmt.Println(err)
+					os.Exit(1)
+				}
+				closed = true
+
+				// go fmt file
+				gofmt := exec.Command("gofmt", "-w", "-s", out.Name())
+				gofmt.Stderr = os.Stdout
+				if err := gofmt.Run(); err != nil {
+					fmt.Println(err)
+					os.Exit(1)
+				}
+
+				// go import file
+				goimport := exec.Command("goimports", "-w", out.Name())
+				goimport.Stderr = os.Stdout
+				if err := goimport.Run(); err != nil {
+					fmt.Println(err)
+					os.Exit(1)
+				}
+			}
+
+		}
+		return true
+	})
+}
diff --git a/pkg/bindings/images/removeoptions_types.go b/pkg/bindings/images/removeoptions_types.go
new file mode 100644
index 0000000000..5902bf9088
--- /dev/null
+++ b/pkg/bindings/images/removeoptions_types.go
@@ -0,0 +1,93 @@
+package images
+
+import (
+	"net/url"
+	"reflect"
+	"strconv"
+
+	jsoniter "github.com/json-iterator/go"
+	"github.com/pkg/errors"
+)
+
+/*
+This file is generated automatically by go generate.  Do not edit.
+
+Created 2020-12-10 12:51:06.090426622 -0600 CST m=+0.000133169
+*/
+
+// Changed
+func (o *RemoveOptions) Changed(fieldName string) bool {
+	r := reflect.ValueOf(o)
+	value := reflect.Indirect(r).FieldByName(fieldName)
+	return !value.IsNil()
+}
+
+// ToParams
+func (o *RemoveOptions) ToParams() (url.Values, error) {
+	params := url.Values{}
+	if o == nil {
+		return params, nil
+	}
+	json := jsoniter.ConfigCompatibleWithStandardLibrary
+	s := reflect.ValueOf(o)
+	if reflect.Ptr == s.Kind() {
+		s = s.Elem()
+	}
+	sType := s.Type()
+	for i := 0; i < s.NumField(); i++ {
+		fieldName := sType.Field(i).Name
+		if !o.Changed(fieldName) {
+			continue
+		}
+		f := s.Field(i)
+		if reflect.Ptr == f.Kind() {
+			f = f.Elem()
+		}
+		switch f.Kind() {
+		case reflect.Bool:
+			params.Set(fieldName, strconv.FormatBool(f.Bool()))
+		case reflect.String:
+			params.Set(fieldName, f.String())
+		case reflect.Int, reflect.Int64:
+			// f.Int() is always an int64
+			params.Set(fieldName, strconv.FormatInt(f.Int(), 10))
+		case reflect.Slice:
+			typ := reflect.TypeOf(f.Interface()).Elem()
+			slice := reflect.MakeSlice(reflect.SliceOf(typ), f.Len(), f.Cap())
+			switch typ.Kind() {
+			case reflect.String:
+				s, ok := slice.Interface().([]string)
+				if !ok {
+					return nil, errors.New("failed to convert to string slice")
+				}
+				for _, val := range s {
+					params.Add(fieldName, val)
+				}
+			default:
+				return nil, errors.Errorf("unknown slice type %s", f.Kind().String())
+			}
+		case reflect.Map:
+			lowerCaseKeys := make(map[string][]string)
+			// I dont know if this code is needed anymore, TBD
+			// for k, v := range filters {
+			// 	lowerCaseKeys[strings.ToLower(k)] = v
+			// }
+			s, err := json.MarshalToString(lowerCaseKeys)
+			if err != nil {
+				return nil, err
+			}
+
+			params.Set(fieldName, s)
+		default:
+			return nil, errors.Errorf("unknown type %s", f.Kind().String())
+		}
+	}
+	return params, nil
+}
+
+// WithForce
+func (o *RemoveOptions) WithForce(value bool) *RemoveOptions {
+	v := &value
+	o.Force = v
+	return o
+}
diff --git a/pkg/bindings/images/rm.go b/pkg/bindings/images/rm.go
index 9685b75e4f..0b3b881654 100644
--- a/pkg/bindings/images/rm.go
+++ b/pkg/bindings/images/rm.go
@@ -41,17 +41,19 @@ func BatchRemove(ctx context.Context, images []string, opts entities.ImageRemove
 	return &report.ImageRemoveReport, errorhandling.StringsToErrors(report.Errors)
 }
 
-// Remove removes an image from the local storage.  Use force to remove an
+// Remove removes an image from the local storage.  Use optional force option to remove an
 // image, even if it's used by containers.
-func Remove(ctx context.Context, nameOrID string, force bool) (*entities.ImageRemoveReport, error) {
+func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) (*entities.ImageRemoveReport, error) {
 	var report handlers.LibpodImagesRemoveReport
 	conn, err := bindings.GetClient(ctx)
 	if err != nil {
 		return nil, err
 	}
 
-	params := url.Values{}
-	params.Set("force", strconv.FormatBool(force))
+	params, err := options.ToParams()
+	if err != nil {
+		return nil, err
+	}
 	response, err := conn.DoRequest(nil, http.MethodDelete, "/images/%s", params, nil, nameOrID)
 	if err != nil {
 		return nil, err
diff --git a/pkg/bindings/images/types.go b/pkg/bindings/images/types.go
new file mode 100644
index 0000000000..340c7bdb90
--- /dev/null
+++ b/pkg/bindings/images/types.go
@@ -0,0 +1,8 @@
+package images
+
+//go:generate go run ../generator/generator.go RemoveOptions
+// RemoveOptions are optional options for image removal
+type RemoveOptions struct {
+	// Forces removes all containers based on the image
+	Force *bool
+}
diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go
index 7d9415f917..684f110e83 100644
--- a/pkg/bindings/test/images_test.go
+++ b/pkg/bindings/test/images_test.go
@@ -84,7 +84,7 @@ var _ = Describe("Podman images", func() {
 	// Test to validate the remove image api
 	It("remove image", func() {
 		// Remove invalid image should be a 404
-		response, err := images.Remove(bt.conn, "foobar5000", false)
+		response, err := images.Remove(bt.conn, "foobar5000", nil)
 		Expect(err).ToNot(BeNil())
 		Expect(response).To(BeNil())
 		code, _ := bindings.CheckResponseCode(err)
@@ -93,7 +93,7 @@ var _ = Describe("Podman images", func() {
 		// Remove an image by name, validate image is removed and error is nil
 		inspectData, err := images.GetImage(bt.conn, busybox.shortName, nil)
 		Expect(err).To(BeNil())
-		response, err = images.Remove(bt.conn, busybox.shortName, false)
+		response, err = images.Remove(bt.conn, busybox.shortName, nil)
 		Expect(err).To(BeNil())
 		code, _ = bindings.CheckResponseCode(err)
 
@@ -113,12 +113,13 @@ var _ = Describe("Podman images", func() {
 
 		// try to remove the image "alpine". This should fail since we are not force
 		// deleting hence image cannot be deleted until the container is deleted.
-		response, err = images.Remove(bt.conn, alpine.shortName, false)
+		response, err = images.Remove(bt.conn, alpine.shortName, nil)
 		code, _ = bindings.CheckResponseCode(err)
 		Expect(code).To(BeNumerically("==", http.StatusConflict))
 
 		// Removing the image "alpine" where force = true
-		response, err = images.Remove(bt.conn, alpine.shortName, true)
+		options := images.RemoveOptions{}
+		response, err = images.Remove(bt.conn, alpine.shortName, options.WithForce(true))
 		Expect(err).To(BeNil())
 		// To be extra sure, check if the previously created container
 		// is gone as well.
@@ -213,7 +214,7 @@ var _ = Describe("Podman images", func() {
 
 	It("Load|Import Image", func() {
 		// load an image
-		_, err := images.Remove(bt.conn, alpine.name, false)
+		_, err := images.Remove(bt.conn, alpine.name, nil)
 		Expect(err).To(BeNil())
 		exists, err := images.Exists(bt.conn, alpine.name)
 		Expect(err).To(BeNil())
@@ -231,7 +232,7 @@ var _ = Describe("Podman images", func() {
 		// load with a repo name
 		f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
 		Expect(err).To(BeNil())
-		_, err = images.Remove(bt.conn, alpine.name, false)
+		_, err = images.Remove(bt.conn, alpine.name, nil)
 		Expect(err).To(BeNil())
 		exists, err = images.Exists(bt.conn, alpine.name)
 		Expect(err).To(BeNil())
@@ -247,7 +248,7 @@ var _ = Describe("Podman images", func() {
 		// load with a bad repo name should trigger a 500
 		f, err = os.Open(filepath.Join(ImageCacheDir, alpine.tarballName))
 		Expect(err).To(BeNil())
-		_, err = images.Remove(bt.conn, alpine.name, false)
+		_, err = images.Remove(bt.conn, alpine.name, nil)
 		Expect(err).To(BeNil())
 		exists, err = images.Exists(bt.conn, alpine.name)
 		Expect(err).To(BeNil())
@@ -275,7 +276,7 @@ var _ = Describe("Podman images", func() {
 
 	It("Import Image", func() {
 		// load an image
-		_, err = images.Remove(bt.conn, alpine.name, false)
+		_, err = images.Remove(bt.conn, alpine.name, nil)
 		Expect(err).To(BeNil())
 		exists, err := images.Exists(bt.conn, alpine.name)
 		Expect(err).To(BeNil())
diff --git a/pkg/bindings/test/manifests_test.go b/pkg/bindings/test/manifests_test.go
index 55fc4cb0db..a4ecaa20ff 100644
--- a/pkg/bindings/test/manifests_test.go
+++ b/pkg/bindings/test/manifests_test.go
@@ -47,7 +47,7 @@ var _ = Describe("Podman containers ", func() {
 		code, _ := bindings.CheckResponseCode(err)
 		Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
 
-		_, err = images.Remove(bt.conn, id, false)
+		_, err = images.Remove(bt.conn, id, nil)
 		Expect(err).To(BeNil())
 
 		// create manifest list with images