Golang vesion: 1.18.5

Configuration lib:

"github.com/spf13/viper" github repo

I'm writing a AWS Lambda using Go. It sits behind an AWS APIGateway as a REST API. It sends out POST requests to an external API. I want to config that external API's URL and a few other header params in a configuration file. Found that spf13/viper library can be used for that requirement.

Here's my source tree:

     api-root
        ├──config  
        ├   ├── application.yaml
        └──lambda
            ├── main.go
      

Here's my main.go,

package main

import (
    "fmt"
    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/spf13/viper"
    "my-api/pkg/handlers"
    "os"
)

func main() {
    lambda.Start(Handler)
}

func Handler(request events.APIGatewayProxyRequest) (*events.APIGatewayProxyResponse, error) {

    // Config
    v := viper.New()

    v.SetConfigName("application") // config file name without extension
    v.SetConfigType("yaml")
    v.AddConfigPath(".")
    v.AddConfigPath("../config/")
    v.AutomaticEnv() // read value ENV variable

    err := v.ReadInConfig()
    if err != nil {
        fmt.Println("fatal error config file: default \n", err)
        os.Exit(1)
    }

    env := v.GetString("app.env")
    fmt.Println("Environment : ", env)

    return handlers.Join(request)
}
      

Here's my go build command,

GOARCH=amd64 GOOS=linux go build -mod=vendor -o ./bin/<lambda-function-name> -ldflags="-s -w" ./lambda/main.go

And when I run it locally using sam

sam local start-api -t deployment/template.yml

And then hit the local endpoint using postman, it gives me the following error,

fatal error config file: default 
 Config File "application" Not Found in "[/var/task /var/config]"

However, when I create a normal go app and run it I get the expected params successfully. Here's my normal go app main.go,

package main

import (
    "fmt"
    "github.com/spf13/viper"
    "os"
)

func main() {
    v := viper.New()

    v.SetConfigName("application") // config file name without extension
    v.SetConfigType("yaml")
    v.AddConfigPath(".")
    v.AddConfigPath("./config/")
    v.AutomaticEnv() // read value ENV variable

    err := v.ReadInConfig()
    if err != nil {
        fmt.Println("fatal error config file: default \n", err)
        os.Exit(1)
    }

    en := v.GetString("app.env")
    fmt.Println("Environment : ", en)

}
      

when I run the app I see the expected print in the console,

➜ go run main.go
Environment :  dev

What should I do to get viper working in the lambda?

2

There are 2 best solutions below

0
Pickles Dog On

I had the same problem.

I solved it by creating a layer in Lambda (sam)

AWSTemplateFormatVersion: '2010-09-09'
  ...

Resources:
  Function:
    Type: AWS::Serverless::Function 
    Properties:
      ...
      Layers:
        - !Ref Files
  Files:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: config-files-layer
      ContentUri: <<YAML FILES DIR>>
      CompatibleRuntimes:
      - ...

And changing

v.AddConfigPath(".")

to

v.AddConfigPath("/opt")

More: Creating and sharing Lambda layers

0
Daniel Alvarenga On

The fast way for lambda:

viper.SetDefault("MY_ENV", os.Getenv("MY_ENV"))

The best way: don't use viper.