github.com/iron-io/functions@v0.0.0-20180820112432-d59d7d1c40b2/fn/commands/routes.go (about)

     1  package commands
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"net/http"
    10  	"net/url"
    11  	"os"
    12  	"path"
    13  	"strconv"
    14  	"strings"
    15  	"text/tabwriter"
    16  
    17  	f_common "github.com/iron-io/functions/common"
    18  	image_commands "github.com/iron-io/functions/fn/commands/images"
    19  	"github.com/iron-io/functions/fn/common"
    20  	fnclient "github.com/iron-io/functions_go/client"
    21  	apiroutes "github.com/iron-io/functions_go/client/routes"
    22  	"github.com/iron-io/functions_go/models"
    23  	fnmodels "github.com/iron-io/functions_go/models"
    24  	"github.com/jmoiron/jsonq"
    25  	"github.com/urfave/cli"
    26  )
    27  
    28  type routesCmd struct {
    29  	client *fnclient.Functions
    30  }
    31  
    32  var routeFlags = []cli.Flag{
    33  	cli.StringFlag{
    34  		Name:  "image,i",
    35  		Usage: "image name",
    36  	},
    37  	cli.Int64Flag{
    38  		Name:  "memory,m",
    39  		Usage: "memory in MiB",
    40  	},
    41  	cli.StringFlag{
    42  		Name:  "type,t",
    43  		Usage: "route type - sync or async",
    44  	},
    45  	cli.StringSliceFlag{
    46  		Name:  "config,c",
    47  		Usage: "route configuration",
    48  	},
    49  	cli.StringSliceFlag{
    50  		Name:  "headers",
    51  		Usage: "route response headers",
    52  	},
    53  	cli.StringFlag{
    54  		Name:  "format,f",
    55  		Usage: "hot container IO format - json or http",
    56  	},
    57  	cli.IntFlag{
    58  		Name:  "max-concurrency,mc",
    59  		Usage: "maximum concurrency for hot container",
    60  	},
    61  	cli.StringFlag{
    62  		Name:  "jwt-key,j",
    63  		Usage: "Signing key for JWT",
    64  	},
    65  	cli.DurationFlag{
    66  		Name:  "timeout",
    67  		Usage: "route timeout (eg. 30s)",
    68  	},
    69  	cli.DurationFlag{
    70  		Name:  "idle-timeout",
    71  		Usage: "hot func timeout (eg. 30s)",
    72  	},
    73  }
    74  
    75  func Routes() cli.Command {
    76  
    77  	r := routesCmd{client: common.ApiClient()}
    78  
    79  	return cli.Command{
    80  		Name:  "routes",
    81  		Usage: "manage routes",
    82  		Subcommands: []cli.Command{
    83  			{
    84  				Name:      "call",
    85  				Usage:     "call a route",
    86  				ArgsUsage: "<app> </path> [image]",
    87  				Action:    r.call,
    88  				Flags:     image_commands.Runflags(),
    89  			},
    90  			{
    91  				Name:      "list",
    92  				Aliases:   []string{"l"},
    93  				Usage:     "list routes for `app`",
    94  				ArgsUsage: "<app>",
    95  				Action:    r.list,
    96  			},
    97  			{
    98  				Name:      "create",
    99  				Aliases:   []string{"c"},
   100  				Usage:     "create a route in an `app`",
   101  				ArgsUsage: "<app> </path>",
   102  				Action:    r.create,
   103  				Flags:     routeFlags,
   104  			},
   105  			{
   106  				Name:      "update",
   107  				Aliases:   []string{"u"},
   108  				Usage:     "update a route in an `app`",
   109  				ArgsUsage: "<app> </path>",
   110  				Action:    r.update,
   111  				Flags:     routeFlags,
   112  			},
   113  			{
   114  				Name:  "config",
   115  				Usage: "operate a route configuration set",
   116  				Subcommands: []cli.Command{
   117  					{
   118  						Name:      "set",
   119  						Aliases:   []string{"s"},
   120  						Usage:     "store a configuration key for this route",
   121  						ArgsUsage: "<app> </path> <key> <value>",
   122  						Action:    r.configSet,
   123  					},
   124  					{
   125  						Name:      "unset",
   126  						Aliases:   []string{"u"},
   127  						Usage:     "remove a configuration key for this route",
   128  						ArgsUsage: "<app> </path> <key>",
   129  						Action:    r.configUnset,
   130  					},
   131  				},
   132  			},
   133  			{
   134  				Name:      "delete",
   135  				Aliases:   []string{"d"},
   136  				Usage:     "delete a route from `app`",
   137  				ArgsUsage: "<app> </path>",
   138  				Action:    r.delete,
   139  			},
   140  			{
   141  				Name:      "inspect",
   142  				Aliases:   []string{"i"},
   143  				Usage:     "retrieve one or all routes properties",
   144  				ArgsUsage: "<app> </path> [property.[key]]",
   145  				Action:    r.inspect,
   146  			},
   147  			{
   148  				Name:      "token",
   149  				Aliases:   []string{"t"},
   150  				Usage:     "retrieve jwt for authentication",
   151  				ArgsUsage: "<app> </path> [expiration(sec)]",
   152  				Action:    r.token,
   153  			},
   154  		},
   155  	}
   156  }
   157  
   158  func Call() cli.Command {
   159  	r := routesCmd{client: common.ApiClient()}
   160  
   161  	return cli.Command{
   162  		Name:      "call",
   163  		Usage:     "call a remote function",
   164  		ArgsUsage: "<app> </path>",
   165  		Flags:     image_commands.Runflags(),
   166  		Action:    r.call,
   167  	}
   168  }
   169  
   170  func cleanRoutePath(p string) string {
   171  	p = path.Clean(p)
   172  	if !path.IsAbs(p) {
   173  		p = "/" + p
   174  	}
   175  	return p
   176  }
   177  
   178  func (a *routesCmd) list(c *cli.Context) error {
   179  	appName := c.Args().Get(0)
   180  
   181  	resp, err := a.client.Routes.GetAppsAppRoutes(&apiroutes.GetAppsAppRoutesParams{
   182  		Context: context.Background(),
   183  		App:     appName,
   184  	})
   185  
   186  	if err != nil {
   187  		switch err.(type) {
   188  		case *apiroutes.GetAppsAppRoutesNotFound:
   189  			return fmt.Errorf("error: %s", err.(*apiroutes.GetAppsAppRoutesNotFound).Payload.Error.Message)
   190  		case *apiroutes.GetAppsAppRoutesDefault:
   191  			return fmt.Errorf("unexpected error: %s", err.(*apiroutes.GetAppsAppRoutesDefault).Payload.Error.Message)
   192  		}
   193  		return fmt.Errorf("unexpected error: %s", err)
   194  	}
   195  
   196  	w := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0)
   197  	fmt.Fprint(w, "path", "\t", "image", "\t", "endpoint", "\n")
   198  	for _, route := range resp.Payload.Routes {
   199  		u, err := url.Parse("../")
   200  		u.Path = path.Join(u.Path, "r", appName, route.Path)
   201  		if err != nil {
   202  			return fmt.Errorf("error parsing functions route path: %s", err)
   203  		}
   204  
   205  		fmt.Fprint(w, route.Path, "\t", route.Image, "\n")
   206  	}
   207  	w.Flush()
   208  
   209  	return nil
   210  }
   211  
   212  func (a *routesCmd) call(c *cli.Context) error {
   213  	appName := c.Args().Get(0)
   214  	route := cleanRoutePath(c.Args().Get(1))
   215  
   216  	u := url.URL{
   217  		Scheme: common.SCHEME,
   218  		Host:   common.HOST,
   219  	}
   220  	u.Path = path.Join(u.Path, "r", appName, route)
   221  	content := image_commands.Stdin()
   222  
   223  	resp, err := a.client.Routes.GetAppsAppRoutesRoute(&apiroutes.GetAppsAppRoutesRouteParams{
   224  		Context: context.Background(),
   225  		App:     appName,
   226  		Route:   route,
   227  	})
   228  
   229  	if err != nil {
   230  		switch err.(type) {
   231  		case *apiroutes.GetAppsAppRoutesRouteNotFound:
   232  			return fmt.Errorf("error: %s", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message)
   233  		case *apiroutes.GetAppsAppRoutesRouteDefault:
   234  			return fmt.Errorf("unexpected error: %s", err.(*apiroutes.GetAppsAppRoutesRouteDefault).Payload.Error.Message)
   235  		}
   236  		return fmt.Errorf("unexpected error: %s", err)
   237  	}
   238  
   239  	rt := resp.Payload.Route
   240  
   241  	return callfn(u.String(), rt, content, os.Stdout, c.String("method"), c.StringSlice("e"))
   242  }
   243  
   244  func callfn(u string, rt *models.Route, content io.Reader, output io.Writer, method string, env []string) error {
   245  	if method == "" {
   246  		if content == nil {
   247  			method = "GET"
   248  		} else {
   249  			method = "POST"
   250  		}
   251  	}
   252  
   253  	req, err := http.NewRequest(method, u, content)
   254  	if err != nil {
   255  		return fmt.Errorf("error running route: %s", err)
   256  	}
   257  
   258  	req.Header.Set("Content-Type", "application/json")
   259  
   260  	if len(env) > 0 {
   261  		envAsHeader(req, env)
   262  	}
   263  
   264  	if rt.JwtKey != "" {
   265  		ss, err := f_common.GetJwt(rt.JwtKey, 60*60)
   266  		if err != nil {
   267  			return fmt.Errorf("unexpected error: %s", err)
   268  		}
   269  		req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", ss))
   270  	}
   271  
   272  	resp, err := http.DefaultClient.Do(req)
   273  	if err != nil {
   274  		return fmt.Errorf("error running route: %s", err)
   275  	}
   276  
   277  	io.Copy(output, resp.Body)
   278  
   279  	return nil
   280  }
   281  
   282  func envAsHeader(req *http.Request, selectedEnv []string) {
   283  	detectedEnv := os.Environ()
   284  	if len(selectedEnv) > 0 {
   285  		detectedEnv = selectedEnv
   286  	}
   287  
   288  	for _, e := range detectedEnv {
   289  		kv := strings.Split(e, "=")
   290  		name := kv[0]
   291  		req.Header.Set(name, os.Getenv(name))
   292  	}
   293  }
   294  
   295  func routeWithFlags(c *cli.Context, rt *models.Route) {
   296  	if i := c.String("image"); i != "" {
   297  		rt.Image = i
   298  	}
   299  
   300  	if f := c.String("format"); f != "" {
   301  		rt.Format = f
   302  	}
   303  
   304  	if t := c.String("type"); t != "" {
   305  		rt.Type = t
   306  	}
   307  
   308  	if m := c.Int("max-concurrency"); m > 0 {
   309  		rt.MaxConcurrency = int32(m)
   310  	}
   311  
   312  	if m := c.Int64("memory"); m > 0 {
   313  		rt.Memory = m
   314  	}
   315  
   316  	if t := c.Duration("timeout"); t > 0 {
   317  		to := int64(t.Seconds())
   318  		rt.Timeout = &to
   319  	}
   320  
   321  	if t := c.Duration("idle-timeout"); t > 0 {
   322  		to := int64(t.Seconds())
   323  		rt.IDLETimeout = &to
   324  	}
   325  
   326  	if j := c.String("jwt-key"); j != "" {
   327  		rt.JwtKey = j
   328  	}
   329  
   330  	if len(c.StringSlice("headers")) > 0 {
   331  		headers := map[string][]string{}
   332  		for _, header := range c.StringSlice("headers") {
   333  			parts := strings.Split(header, "=")
   334  			headers[parts[0]] = strings.Split(parts[1], ";")
   335  		}
   336  		rt.Headers = headers
   337  	}
   338  
   339  	if len(c.StringSlice("config")) > 0 {
   340  		rt.Config = common.ExtractEnvConfig(c.StringSlice("config"))
   341  	}
   342  }
   343  
   344  func routeWithFuncFile(c *cli.Context, rt *models.Route) {
   345  	ff, err := common.LoadFuncfile()
   346  	if err == nil {
   347  		if ff.FullName() != "" { // args take precedence
   348  			rt.Image = ff.FullName()
   349  		}
   350  		if ff.Format != nil {
   351  			rt.Format = *ff.Format
   352  		}
   353  		if ff.MaxConcurrency != nil {
   354  			rt.MaxConcurrency = int32(*ff.MaxConcurrency)
   355  		}
   356  		if ff.Timeout != nil {
   357  			to := int64(ff.Timeout.Seconds())
   358  			rt.Timeout = &to
   359  		}
   360  		if ff.IDLETimeout != nil {
   361  			to := int64(ff.IDLETimeout.Seconds())
   362  			rt.IDLETimeout = &to
   363  		}
   364  		if ff.JwtKey != nil && *ff.JwtKey != "" {
   365  			rt.JwtKey = *ff.JwtKey
   366  		}
   367  
   368  		if rt.Path == "" && ff.Path != nil {
   369  			rt.Path = *ff.Path
   370  		}
   371  	}
   372  }
   373  
   374  func (a *routesCmd) create(c *cli.Context) error {
   375  	appName := c.Args().Get(0)
   376  	route := cleanRoutePath(c.Args().Get(1))
   377  
   378  	rt := &models.Route{}
   379  	rt.Path = route
   380  	rt.Image = c.Args().Get(2)
   381  
   382  	routeWithFuncFile(c, rt)
   383  	routeWithFlags(c, rt)
   384  
   385  	if rt.Path == "" {
   386  		return errors.New("error: route path is missing")
   387  	}
   388  	if rt.Image == "" {
   389  		fmt.Println("No image specified, using `iron/hello`")
   390  		rt.Image = "iron/hello"
   391  	}
   392  
   393  	body := &models.RouteWrapper{
   394  		Route: rt,
   395  	}
   396  
   397  	resp, err := a.client.Routes.PostAppsAppRoutes(&apiroutes.PostAppsAppRoutesParams{
   398  		Context: context.Background(),
   399  		App:     appName,
   400  		Body:    body,
   401  	})
   402  
   403  	if err != nil {
   404  		switch err.(type) {
   405  		case *apiroutes.PostAppsAppRoutesBadRequest:
   406  			return fmt.Errorf("error: %s", err.(*apiroutes.PostAppsAppRoutesBadRequest).Payload.Error.Message)
   407  		case *apiroutes.PostAppsAppRoutesConflict:
   408  			return fmt.Errorf("error: %s", err.(*apiroutes.PostAppsAppRoutesConflict).Payload.Error.Message)
   409  		case *apiroutes.PostAppsAppRoutesDefault:
   410  			return fmt.Errorf("unexpected error: %s", err.(*apiroutes.PostAppsAppRoutesDefault).Payload.Error.Message)
   411  		}
   412  		return fmt.Errorf("unexpected error: %s", err)
   413  	}
   414  
   415  	fmt.Println(resp.Payload.Route.Path, "created with", resp.Payload.Route.Image)
   416  	return nil
   417  }
   418  
   419  func (a *routesCmd) patchRoute(appName, routePath string, r *fnmodels.Route) error {
   420  	resp, err := a.client.Routes.GetAppsAppRoutesRoute(&apiroutes.GetAppsAppRoutesRouteParams{
   421  		Context: context.Background(),
   422  		App:     appName,
   423  		Route:   routePath,
   424  	})
   425  
   426  	if err != nil {
   427  		switch err.(type) {
   428  		case *apiroutes.GetAppsAppRoutesRouteNotFound:
   429  			return fmt.Errorf("error: %s", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message)
   430  		case *apiroutes.GetAppsAppRoutesDefault:
   431  			return fmt.Errorf("unexpected error: %s", err.(*apiroutes.GetAppsAppRoutesDefault).Payload.Error.Message)
   432  		}
   433  		return fmt.Errorf("unexpected error: %s", err)
   434  	}
   435  
   436  	if resp.Payload.Route.Config == nil {
   437  		resp.Payload.Route.Config = map[string]string{}
   438  	}
   439  
   440  	if resp.Payload.Route.Headers == nil {
   441  		resp.Payload.Route.Headers = map[string][]string{}
   442  	}
   443  
   444  	resp.Payload.Route.Path = ""
   445  	if r != nil {
   446  		if r.Config != nil {
   447  			for k, v := range r.Config {
   448  				if string(k[0]) == "-" {
   449  					delete(resp.Payload.Route.Config, string(k[1:]))
   450  					continue
   451  				}
   452  				resp.Payload.Route.Config[k] = v
   453  			}
   454  		}
   455  		if r.Headers != nil {
   456  			for k, v := range r.Headers {
   457  				if string(k[0]) == "-" {
   458  					delete(resp.Payload.Route.Headers, k)
   459  					continue
   460  				}
   461  				resp.Payload.Route.Headers[k] = v
   462  			}
   463  		}
   464  		if r.Image != "" {
   465  			resp.Payload.Route.Image = r.Image
   466  		}
   467  		if r.Format != "" {
   468  			resp.Payload.Route.Format = r.Format
   469  		}
   470  		if r.Type != "" {
   471  			resp.Payload.Route.Type = r.Type
   472  		}
   473  		if r.MaxConcurrency > 0 {
   474  			resp.Payload.Route.MaxConcurrency = r.MaxConcurrency
   475  		}
   476  		if r.Memory > 0 {
   477  			resp.Payload.Route.Memory = r.Memory
   478  		}
   479  		if r.Timeout != nil {
   480  			resp.Payload.Route.Timeout = r.Timeout
   481  		}
   482  		if r.IDLETimeout != nil {
   483  			resp.Payload.Route.IDLETimeout = r.IDLETimeout
   484  		}
   485  		if r.JwtKey != "" {
   486  			resp.Payload.Route.JwtKey = r.JwtKey
   487  		}
   488  
   489  	}
   490  
   491  	_, err = a.client.Routes.PatchAppsAppRoutesRoute(&apiroutes.PatchAppsAppRoutesRouteParams{
   492  		Context: context.Background(),
   493  		App:     appName,
   494  		Route:   routePath,
   495  		Body:    resp.Payload,
   496  	})
   497  
   498  	if err != nil {
   499  		switch err.(type) {
   500  		case *apiroutes.PatchAppsAppRoutesRouteBadRequest:
   501  			return fmt.Errorf("error: %s", err.(*apiroutes.PatchAppsAppRoutesRouteBadRequest).Payload.Error.Message)
   502  		case *apiroutes.PatchAppsAppRoutesRouteNotFound:
   503  			return fmt.Errorf("error: %s", err.(*apiroutes.PatchAppsAppRoutesRouteNotFound).Payload.Error.Message)
   504  		case *apiroutes.PatchAppsAppRoutesRouteDefault:
   505  			return fmt.Errorf("unexpected error: %s", err.(*apiroutes.PatchAppsAppRoutesRouteDefault).Payload.Error.Message)
   506  		}
   507  		return fmt.Errorf("unexpected error: %s", err)
   508  	}
   509  
   510  	return nil
   511  }
   512  
   513  func (a *routesCmd) update(c *cli.Context) error {
   514  	appName := c.Args().Get(0)
   515  	route := cleanRoutePath(c.Args().Get(1))
   516  
   517  	rt := &models.Route{}
   518  	routeWithFuncFile(c, rt)
   519  	routeWithFlags(c, rt)
   520  
   521  	err := a.patchRoute(appName, route, rt)
   522  	if err != nil {
   523  		return err
   524  	}
   525  
   526  	fmt.Println(appName, route, "updated")
   527  	return nil
   528  }
   529  
   530  func (a *routesCmd) configSet(c *cli.Context) error {
   531  	appName := c.Args().Get(0)
   532  	route := cleanRoutePath(c.Args().Get(1))
   533  	key := c.Args().Get(2)
   534  	value := c.Args().Get(3)
   535  
   536  	patchRoute := fnmodels.Route{
   537  		Config: make(map[string]string),
   538  	}
   539  
   540  	patchRoute.Config[key] = value
   541  
   542  	err := a.patchRoute(appName, route, &patchRoute)
   543  	if err != nil {
   544  		return err
   545  	}
   546  
   547  	fmt.Println(appName, route, "updated", key, "with", value)
   548  	return nil
   549  }
   550  
   551  func (a *routesCmd) configUnset(c *cli.Context) error {
   552  	appName := c.Args().Get(0)
   553  	route := cleanRoutePath(c.Args().Get(1))
   554  	key := c.Args().Get(2)
   555  
   556  	patchRoute := fnmodels.Route{
   557  		Config: make(map[string]string),
   558  	}
   559  
   560  	patchRoute.Config["-"+key] = ""
   561  
   562  	err := a.patchRoute(appName, route, &patchRoute)
   563  	if err != nil {
   564  		return err
   565  	}
   566  
   567  	fmt.Printf("removed key '%s' from the route '%s%s'", key, appName, key)
   568  	return nil
   569  }
   570  
   571  func (a *routesCmd) inspect(c *cli.Context) error {
   572  	appName := c.Args().Get(0)
   573  	route := cleanRoutePath(c.Args().Get(1))
   574  	prop := c.Args().Get(2)
   575  
   576  	resp, err := a.client.Routes.GetAppsAppRoutesRoute(&apiroutes.GetAppsAppRoutesRouteParams{
   577  		Context: context.Background(),
   578  		App:     appName,
   579  		Route:   route,
   580  	})
   581  
   582  	if err != nil {
   583  		switch err.(type) {
   584  		case *apiroutes.GetAppsAppRoutesRouteNotFound:
   585  			return fmt.Errorf("error: %s", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message)
   586  		case *apiroutes.GetAppsAppRoutesRouteDefault:
   587  			return fmt.Errorf("unexpected error: %s", err.(*apiroutes.GetAppsAppRoutesRouteDefault).Payload.Error.Message)
   588  		}
   589  		return fmt.Errorf("unexpected error: %s", err)
   590  	}
   591  
   592  	enc := json.NewEncoder(os.Stdout)
   593  	enc.SetIndent("", "\t")
   594  
   595  	if prop == "" {
   596  		enc.Encode(resp.Payload.Route)
   597  		return nil
   598  	}
   599  
   600  	data, err := json.Marshal(resp.Payload.Route)
   601  	if err != nil {
   602  		return fmt.Errorf("failed to inspect route: %s", err)
   603  	}
   604  	var inspect map[string]interface{}
   605  	err = json.Unmarshal(data, &inspect)
   606  	if err != nil {
   607  		return fmt.Errorf("failed to inspect route: %s", err)
   608  	}
   609  
   610  	jq := jsonq.NewQuery(inspect)
   611  	field, err := jq.Interface(strings.Split(prop, ".")...)
   612  	if err != nil {
   613  		return errors.New("failed to inspect that route's field")
   614  	}
   615  	enc.Encode(field)
   616  
   617  	return nil
   618  }
   619  
   620  func (a *routesCmd) delete(c *cli.Context) error {
   621  	appName := c.Args().Get(0)
   622  	route := cleanRoutePath(c.Args().Get(1))
   623  
   624  	_, err := a.client.Routes.DeleteAppsAppRoutesRoute(&apiroutes.DeleteAppsAppRoutesRouteParams{
   625  		Context: context.Background(),
   626  		App:     appName,
   627  		Route:   route,
   628  	})
   629  	if err != nil {
   630  		switch err.(type) {
   631  		case *apiroutes.DeleteAppsAppRoutesRouteNotFound:
   632  			return fmt.Errorf("error: %s", err.(*apiroutes.DeleteAppsAppRoutesRouteNotFound).Payload.Error.Message)
   633  		case *apiroutes.DeleteAppsAppRoutesRouteDefault:
   634  			return fmt.Errorf("unexpected error: %s", err.(*apiroutes.DeleteAppsAppRoutesRouteDefault).Payload.Error.Message)
   635  		}
   636  		return fmt.Errorf("unexpected error: %s", err)
   637  	}
   638  
   639  	fmt.Println(appName, route, "deleted")
   640  	return nil
   641  }
   642  
   643  func (a *routesCmd) token(c *cli.Context) error {
   644  	appName := c.Args().Get(0)
   645  	route := cleanRoutePath(c.Args().Get(1))
   646  	e := c.Args().Get(2)
   647  	expiration := 60 * 60
   648  	if e != "" {
   649  		var err error
   650  		expiration, err = strconv.Atoi(e)
   651  		if err != nil {
   652  			return fmt.Errorf("invalid expiration: %s", err)
   653  		}
   654  	}
   655  
   656  	resp, err := a.client.Routes.GetAppsAppRoutesRoute(&apiroutes.GetAppsAppRoutesRouteParams{
   657  		Context: context.Background(),
   658  		App:     appName,
   659  		Route:   route,
   660  	})
   661  
   662  	if err != nil {
   663  		switch err.(type) {
   664  		case *apiroutes.GetAppsAppRoutesRouteNotFound:
   665  			return fmt.Errorf("error: %s", err.(*apiroutes.GetAppsAppRoutesRouteNotFound).Payload.Error.Message)
   666  		case *apiroutes.GetAppsAppRoutesRouteDefault:
   667  			return fmt.Errorf("unexpected error: %s", err.(*apiroutes.GetAppsAppRoutesRouteDefault).Payload.Error.Message)
   668  		}
   669  		return fmt.Errorf("unexpected error: %s", err)
   670  	}
   671  
   672  	enc := json.NewEncoder(os.Stdout)
   673  	enc.SetIndent("", "\t")
   674  	jwtKey := resp.Payload.Route.JwtKey
   675  	if jwtKey == "" {
   676  		return errors.New("Empty JWT Key")
   677  	}
   678  
   679  	// Create the Claims
   680  	ss, err := f_common.GetJwt(jwtKey, expiration)
   681  	if err != nil {
   682  		return fmt.Errorf("unexpected error: %s", err)
   683  	}
   684  	t := struct {
   685  		Token string `json:"token"`
   686  	}{Token: ss}
   687  	enc.Encode(t)
   688  
   689  	return nil
   690  }