I'm trying to run some example code that stores some random data using a cloud function in the Firestore server, however, Cloud functions deploy command refuses to build the command:
// Package p contains an HTTP Cloud Function.
package p
import (
//...
firebase "firebase.google.com/go"
"log"
"net/http"
"os"
)
// Store1 Stores data on FireBase
func Store1(w http.ResponseWriter, r *http.Request) {
// Use the application default credentials
ctx := context.Background()
conf := &firebase.Config{ProjectID: "firefirefire"}
app, err := firebase.NewApp(ctx, conf)
if err != nil {
log.Fatalln(err)
}
client, err := app.Firestore(ctx)
if err != nil {
log.Fatalln(err)
}
defer client.Close()
_, _, err = client.Collection("users").Add(ctx, map[string]interface{}{
"first": "Ada",
"last": "Lovelace",
"born": 1815,
})
if err != nil {
log.Fatalf("Failed adding alovelace: %v", err)
}
fmt.Println("ENV:" + os.Getenv("VAR1"))
fmt.Fprint(w, html.EscapeString(d.Message))
}
This is what I get as an error:
localhost:store1 b$ ./deploy.sh
Updated property [functions/region].
Deploying function (may take a while - up to 2 minutes)...failed.
ERROR: (gcloud.functions.deploy) OperationError: code=3, message=Build failed: /tmp/sgb/gopath/src/serverlessapp/vendor/p/store1.go:6:2: cannot find package "firebase.google.com/go" in any of:
/tmp/sgb/gopath/src/serverlessapp/vendor/firebase.google.com/go (vendor tree)
/go/src/firebase.google.com/go (from $GOROOT)
/tmp/sgb/gopath/src/firebase.google.com/go (from $GOPATH)
As you can see, the problem seems to be that Google doesn't have firebase.google.com/go on Cloud functions engine and as a result I can't have my serverless configuration do the firebase thing.
Should I move to CloudSQL and just pay the $11 fee ?
Should I continue to try to get Firebase to work?
Should I try a Firebase Function instead?
Please advise.
According to your description and codes,if I understand your issue clearly, you are trying to trigger an HTTP Cloud Function to write data into Cloud Firestore.
While you deploy the Cloud Function, package "firebase.google.com/go" cloud not be found.”. Becasue ”firebase.google.com/go” which is the entry point to the Firebase Admin SDK. However, Cloud Function, the Google Cloud Client Library for Go is installed. Based on your requirement, It seems Cloud Functions for Firebase may provide the solution you need.
Related
Are there any options for logging request times in grpc-node? I've been able to log response times using opentelemetry & jaegar (to display response times). I couldn't find any npm packages for this either, but just wanted to ask you guys if you did find any options for grpc-node.
You don't need a package to do it, you can do it using a simple gRPC client interceptor.
This is how you would do it in Golang. Just check how you can create a gRPC interceptor in Node. Sorry for not having a JS example, hope it helps some how.
func UnaryRequestTImeInterceptor() grpc.UnaryClientInterceptor {
return func(
ctx context.Context,
method string,
req interface{},
reply interface{},
cc *grpc.ClientConn,
invoker grpc.UnaryInvoker,
opts ...grpc.CallOption,
) error {
start := time.Now()
err := invoker(ctx, method, req, reply, cc, opts...)
reqTime := time.Since(start)
return err
}
}
I am trying to create a firebase project with a firestore instance programatically. I've been using the firebase-tools cli and have managed to create a new project, a web app and get the app config, but I still need to manually enter the console and click the "Create database" button. Is it possible to automate this process?
Given that Firestore depends on an implementation of Google App Engine, I was able to programatically create a Firestore database using the Google App Engine api:
package main
import (
"context"
"google.golang.org/api/appengine/v1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"log"
)
// CreateFirestoreDatabase uses the Google App Engine API
// to create a Firestore database
func CreateFirestoreDatabase(ctx context.Context) error {
// instantiate service
service, err := appengine.NewService(context.Background())
if err != nil {
log.Fatalf("appengine.NewService: %v", err)
}
// create application
op, err := service.Apps.
Create(&appengine.Application{
DatabaseType: "CLOUD_FIRESTORE",
Id: "your-google-project-id",
LocationId: "europe-west",
}).
Context(ctx).Do()
if err != nil {
return status.Errorf(
codes.Internal,
"service.Apps.Create: %s", err,
)
}
// check the status of the longrunning operations
// TODO: loop until op.Done == true
_ = op
return nil
}
The same process is used by the gcloud SDK:
gcloud firestore databases create [--region=REGION]
It is useful to have a look a the underlying python code backing the gcloud bin folder. Here is a screenshot of the gcloud firestore create command confirming this:
The process can be automated using terraform and the work around to configure an app engine application resource.
resource "google_app_engine_application" "app" {
project = "your-project-id"
location_id = "us-central"
database_type = "CLOUD_FIRESTORE"
}
As stated in the answers before firestore seems to rely on app engine even in the gcloud SDK.
Ugly but works.
Over here the Firebase docs explain how you can retrieve a token required to make requests to the Remote Config Rest API.
It provides example code for Python, Java and Node.js. Because there is no code for Go, it sends me to the Google Client Library (for Go). You might be able to understand why I am getting lost there...
The examples use GoogleCredential in Java, ServiceAccountCredentials in Python and google.auth.JWT in Node.js. I was not able to find any of those here. I do not know why there are no clear naming conventions.
I have found
firebaseremoteconfig-gen.go: The code looks like it already implements what the Firebase documentation page tries to achieve "manually". Comparison: doc, package.
Help
Because the "Usage example" of the package ends strangely abrupt and is the opposite of extensive, I do not understand how to make use of it.
I would be helped if someone could tell me how I can use this:
firebaseremoteconfigService, err := firebaseremoteconfig.New(oauthHttpClient)
I could not figure out where I would get oauthHttpClient from. There is an oauth2 package in the repository, but there I face the same problem:
oauth2Service, err := oauth2.New(oauthHttpClient)
I need oauthHttpClient again, so this cannot be a solution.
http.Client could be anything, but I need to authenticate with a service-account.json file, like shown in the three example snippets here.
Tags explanation
I hope that someone has either had experience with integrating Firebase Remote Config with Go, someone knows how Google Client API authentication works or someone is good enough with Go to get how the usage works.
There are a couple of main ways of authenticating with the google APIs, they are documented here:
Link to docs
The ways documented are "3-legged OAuth", "Using API Keys" and finally "Service Accounts".
From the links that you've included in the question; you are looking at the Python / Java / Node examples of "Service Accounts".
Using Service Accounts in go
The oauthHttpClient that you are referring to, is an http client that will attach the authentication information to the requests automatically.
You can create one using this package:
https://godoc.org/golang.org/x/oauth2/google
The examples linked in other languages use a "service account json key file".
Using the method linked below, you can read that keyfile and create a jwt.Config struct that will give you access to the client that you need.
https://godoc.org/golang.org/x/oauth2/google#JWTConfigFromJSON
The go equivalent of the other language examples linked is;
data, err := ioutil.ReadFile("/path/to/your-project-key.json")
if err != nil {
log.Fatal(err)
}
conf, err := google.JWTConfigFromJSON(data, "https://www.googleapis.com/auth/firebase.remoteconfig")
if err != nil {
log.Fatal(err)
}
// Initiate an http.Client. The following GET request will be
// authorized and authenticated on the behalf of
// your service account.
client := conf.Client(oauth2.NoContext)
client.Get("...")
I just started using the same library (from an AppEngine Standard project). This is how I am creating the service client:
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"golang.org/x/oauth2/google"
fb "google.golang.org/api/firebaseremoteconfig/v1"
"google.golang.org/appengine"
"google.golang.org/appengine/log"
)
const (
// Name of our service account file
saFileName = "my-firebase-sa.json"
// OAuth scopes used for remote config API
scopeRemoteConfig = "https://www.googleapis.com/auth/firebase.remoteconfig"
)
func createFirebaseService(ctx context.Context) (*fb.Service, error) {
data, err := ioutil.ReadFile(saFileName)
if err != nil {
return nil, err
}
conf, err := google.JWTConfigFromJSON(data, scopeRemoteConfig)
if err != nil {
return nil, err
}
return fb.New(conf.Client(ctx))
}
And I call it as such:
func fetchConfig(ctx context.Context) (*fb.RemoteConfig, error) {
s, err := createFirebaseService(ctx)
if err != nil {
log.Errorf(ctx, "Failed to create firebase service: %v", err)
return nil, fmt.Errorf("Failed to initialize Firebase service")
}
projectID := "projects/" + appengine.AppID(ctx)
cfg, err := s.Projects.GetRemoteConfig(projectID).Do()
if err != nil {
log.Errorf(ctx, "Failed to call Firebase remote config API: %v", err)
return nil, err
}
return cfg, nil
}
The code is using the Project ID to form its path; after reading through the lib code I noticed it was missing /projects/ from that path; so I just prepended that to my project ID and it works ;-) At least until they fix that and my code stops working..
Hopefully this helps someone.
I am using firebase go sdk (https://github.com/acoshift/go-firebase-admin) and have followed the docs to set up my app.
But when I try to initialize the app with firebase.NewApp I get an error saying
google: could not find default credentials.
Can someone please help
Here is the code snippet
opt = option.WithCredentialsFile(viper.GetString("firebase"))
app, err = firebase.NewApp(context.Background(), nil, opt)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
The problem in opt = option.WithCredentialsFile(viper.GetString("firebase"))
It couldn't find the path to your config file. Try to use path to file and then find how to add it via viper
I'm using gin framework. And I'm opening the sqlite database in the main function like this
func main() {
...
db, err := sql.Open("sqlite3", "./libreread.db")
CheckError(err)
defer db.Close()
...
}
And I have these router handlers in the main function.
...
r.GET("/", GetHomePage)
r.GET("/signin", GetSignIn)
r.POST("/signin", PostSignIn)
...
How to pass that db value through the router handler func PostSignin(c *gin.Context) ?
So that I could avoid opening and closing the database each time in the functions.
UPDATE: I'm using go-sqlite3 package.
Thanks!
Let's say you have your sql client initialized in db, then, you can pass it to different routes with
r.GET("/", GetHomePageHandler(&db))
And in your GetHomePageHandler:
func GetHomePageHandler(sqldb *SQLiteConn) func (*gin.Context) {
return func (*gin.Context) {
. . .
}
}
Where *SQLiteConn is the type of your sql db instance. I don't know which package you are currently using so this is just an example.
You can find also a more elegant way of solving it in this answer,