Use swagger specification in GoLang for Azure functions - azure

Curently i'm building an Azure serverless Function in GoLang. I must have a swagger specification inside the function.
I'm using gin as http framework and swaggo as the swagger specification generator.
Main function:
func main() {
port, exists := os.LookupEnv("FUNCTIONS_CUSTOMHANDLER_PORT")
if !exists {
port = "8080"
}
r := gin.Default()
v1 := r.Group("/api")
v1.GET("/ping", function.Ping)
v1.GET("/docs", function.Swagger)
url := ginSwagger.URL("http://localhost:7071/api/docs")
v1.GET("/swagger", ginSwagger.WrapHandler(swaggerFiles.Handler, url))
r.Run(":" + port)
}
The function that will return the swagger.json:
func Swagger(c *gin.Context) {
c.File("docs/swagger.json")
}
When we build the application and run it local the response is 404.

Related

gocql: unable to create session: unable to discover protocol version: tls: first record does not look like a TLS handshake

Help, I am quite new to AstraDB, and while connecting it via goCQL, I got an error that says
"Error creating cassandra session: gocql: unable to create session: unable to discover protocol version: dial tcp 34.93.79.117:34567: i/o timeout"
I want to connect my code with server using GoCQL, and I was following this tutorial :- https://community.datastax.com/questions/3753/has-anyone-managed-to-connect-to-astra-from-gocql.html
I did not make much changes in my code, just a few different things from this tutorial.
In my code, Cassandra is a struct
type Cassandra struct {
Host string `yaml:"host"`
Port string `yaml:"port"`
Username string `yaml:"username"`
Password string `yaml:"password"`
Keyspace string `yaml:"keyspace"`
}
type cassandra struct {
Session *gocqlx.Session
}
func NewCassandraConfig() *Cassandra {
return &Cassandra{
Host: "", //databaseid-db_region.db.astra.datastax.com
Port: "34567", //port
Username: "", //token id
Password: "", //token password
Keyspace: "test", //keyspace created at
}
}
func New(conf *Cassandra) (*cassandra, error) {
cluster := gocql.NewCluster(conf.Host)
cluster.Keyspace = conf.Keyspace
cluster.Consistency = gocql.Quorum
cluster.Authenticator = gocql.PasswordAuthenticator{
Username: conf.Username,
Password: conf.Password,
}
cluster.Hosts = []string{conf.Host + ":" + conf.Port}
certPath, _ := filepath.Abs("absolute path to //cert") //gotten from bundle
keyPath, _ := filepath.Abs("absolute path to //key")
caPath, _ := filepath.Abs("absolute path to //ca.crt")
cert, _ := tls.LoadX509KeyPair(certPath, keyPath)
caCert, _ := ioutil.ReadFile(caPath)
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
}
cluster.SslOpts = &gocql.SslOptions{
Config: tlsConfig,
EnableHostVerification: false,
}
session, err := gocqlx.WrapSession(cluster.CreateSession())
if err != nil {
// log via logrus
log.Errorf("Error creating cassandra session: %v", err)
return nil, err
}
return &cassandra{
Session: &session,
}, nil
}
func main() {
CassandraConfig := NewCassandraConfig()
CassandraSession, err := New(CassandraConfig)
if err != nil {
log.Println("Error")
}
query := "SELECT id, name from test.testdata"
result := &testdata{}
iter := CassandraSession.Session.Query(query, nil).Iter()
for iter.Scan(&result.id, &result.name) {
log.Println(result.id, " ", result.name)
}
}
Can anyone help me find out what mistakes I made, cause I am unable to find that.
The error you posted indicates that you have configured something incorrectly so the driver is unable to connect to your database. It could be the wrong password, wrong CQL port, or incorrect certificate credentials.
I wrote those instructions all the way back to 2020 and they are a bit obsolete.
My suggestion is that you have a look at Nathan Bak's https://github.com/NathanBak/easy-cass-go package which makes it very easy to connect to your Astra DB. Cheers!

Unknown gRPC error with no error message - gRPC-web and goproxy

I'm trying to build a web application with the following stack:
Flutter/Dart
Go/goproxy
gRPC
MongoDB
I was able to successfully define and compile a protobuf into Dart and Go, however now that I'm trying to integrate the UI with the backend, I am running into the following issue:
Error: gRPC Error (code: 2, codeName: UNKNOWN, message:
null, details: [], rawResponse: null, trailers: {})
Here is my client code:
import 'package:grpc/grpc_web.dart';
import 'package:proj/protos/cards.pb.dart';
import 'package:proj/protos/cards.pbgrpc.dart';
class FiltersService {
static ResponseFuture<Filters> getFilters() {
GrpcWebClientChannel channel =
GrpcWebClientChannel.xhr(Uri.parse('http://localhost:9000'));
FiltersServiceClient clientStub = FiltersServiceClient(
channel,
);
return clientStub.getFilters(Void());
}
}
The server controller code:
const (
port = 9000
)
var (
grpcServer *grpc.Server
)
func StartServer() {
log.Println("Starting server")
listener, err := net.Listen("tcp", fmt.Sprintf(":%v", port))
if err != nil {
log.Fatalf("Unable to listen to port %v\n%v\n", port, err)
}
repositories.ConnectToMongoDB()
grpcServer = grpc.NewServer()
registerServices()
grpcWebServer := grpcweb.WrapServer(grpcServer)
httpServer := &http.Server{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.ProtoMajor == 2 {
grpcWebServer.ServeHTTP(w, r)
} else {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, X-User-Agent, X-Grpc-Web")
w.Header().Set("grpc-status", "")
w.Header().Set("grpc-message", "")
if grpcWebServer.IsGrpcWebRequest(r) {
grpcWebServer.ServeHTTP(w, r)
}
}
}),
}
httpServer.Serve(listener)
}
// Register services defined in protobufs to call from UI
func registerServices() {
cardsService := &services.CardsService{}
protos.RegisterCardsServiceServer(grpcServer, cardsService)
filtersService := &services.FiltersService{}
protos.RegisterFiltersServiceServer(grpcServer, filtersService)
}
I can tell that the server is receiving the request properly, and when I output the response of the service, I am getting the expected response.
Here is the service I am calling:
func (service *FiltersService) GetFilters(ctx context.Context, void *protos.Void) (*protos.Filters, error) {
filters := repositories.GetFilters()
return converters.FiltersStructToFiltersProtoConverter(filters), nil
}
When I output the response of converters.FiltersStructToFiltersProtoConverter(filters), I get the correct output, so it looks like there's still an issue with the way my server is set up.
I know this isn't a lot of info to go on, however I'm not sure what other information you may need, but can add as needed.

How to connect google-cloud-firestore to swift?

I was unable to connect Firestore-cloud to xcode using Firestore-CLI, but was unable to do so.
So, Now, I am trying to connect Firestore to serverless - https://firebase.google.com/docs/firestore/extend-with-functions , which in console is -
https://console.cloud.google.com .
I have the following functions -
1). the function in the given example is - "helloWorld" , the code is -
exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};
-- It gets deployed as - https://myregion-testpro-92351.cloudfunctions.net/function-1
2). I have also tested another function "helloHttp", the code is -
exports.helloHttp = (req, res) => {
res.send(`Hello ${escapeHtml(req.query.name || req.body.name || 'World')}!`);
};
-- It gets deployed as - https://myregion-testpro-92351.cloudfunctions.net/function-5
The above functions gets deployed successfully.
Also, my swift Viewcontroller code is -
import UIKit
import Firebase
class TestViewController:
UIViewController {
#IBAction func Test(_ sender: Any) { } }
The package.json for both the above functions is -
{
"name": "sample-http",
"version": "0.0.1"
}
I have the following question -
What should I put inside the button - "#IBAction func Test(_ sender: Any) { } }" in "TestViewController" above to make both functions, 1). "function-1", i.e. "helloWorld" and 2). "function-5", i.e. "helloHttp" print "HelloWorld" in xcode console.
I did something like this not too long ago, to deploy functions for your app's functionality, deploy them from terminal.
To execute a function and/or pass in parameters, from within your app, you can use AlamoFire. Each function has it's own URL which AlamoFire can retrieve and from there on you may wish to pass through whatever data is needed.

How to restart itself in Go daemon process?

I use go-daemon library to fork process and run it in background. And I need to restart the daemon process after update performed from within http handler.
The handler code is
func httpUpdate(w http.ResponseWriter, req *http.Request) {
if !isPost(req.Method) {
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
return
}
if checkAuth(req) != 200 {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
}
log.Println("INFO: Update request, checking for update...")
var err = doUpdate(UPDATE_URL, nil, false)
if !isError(err) {
log.Println("INFO: Update successful, exit")
var system = RealSystem{}
system.Run(fmt.Sprintf("(sleep 0.3s && %s start &> /test/extra.log)&disown", appFilename()))
system.Exit(0)
return
}
w.WriteHeader(http.StatusNoContent)
}
doUpdate() returns nil if successfully replaced the executable file. RealSystem is just wrapper for exec.Command and os.Exit(). appFilename() is the executable file name. The command to start app is /path/to/app start.
I see that new process starts, but executing Context::Reborn() fails with EOF error. Looks like some intrinsic pipes used as implementation details fail with EOF (may be...).
What would be the reason? Or may be there is a better way of doing that?
For now everything happens inside docker container in the "context" of e2e test if it matters. I spent hours trying to make it work but with no success.
I assume you mean restarting the currently running Go binary. You can use a syscall for unix-based systems, and use an exec.Command for Windows.
func RestartSelf() error {
self, err := osext.Executable()
if err != nil {
return err
}
args := os.Args
env := os.Environ()
// Windows does not support exec syscall.
if runtime.GOOS == "windows" {
cmd := exec.Command(self, args[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
cmd.Env = env
err := cmd.Run()
if err == nil {
os.Exit(0)
}
return err
}
return syscall.Exec(self, args, env)
}
The issue is specific to the library. Spawn new self instance from within child process is not a problem for the system, but for that library.
To achieve this it's necessary to execute something like that.
Note the _GO_DAEMON=0 variable set to zero. This makes library follow parent control flow.
var cmd = exec.Command("bash", "-c", fmt.Sprintf("sleep 0.5s; _GO_DAEMON=0 %s start", appFilename()))
var err = cmd.Start()
Also it was necessary to make small changes to the original library. Here is the fork.

Golang route not working

I just started to get into golang and as I plan to host at least two websites, I chose to use Mux to display different routes by "filtering" domains. Whenever I try to access my main route, it just gives me an 404 error. (Also, the fact that the "www" part is absent is perfectly normal. I don't type that to access the site).
But if I launch the server as a file server, I can access my files, so the server in itself is working I guess
func redirect(w http.ResponseWriter, req *http.Request) {
target := "https://" + req.Host + req.URL.Path
http.Redirect(w, req, target,
http.StatusTemporaryRedirect)
}
func main() {
go http.ListenAndServe(":80", http.HandlerFunc(redirect)) // Redirection
// Serveur sécurisé
r := mux.NewRouter()
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("/root/go/src/web/static/"))))
s := r.Host("echecderi.me").Subrouter()
s.HandleFunc("/", indexEchec)
http.ListenAndServeTLS(":443", "domain-crt.pem", "domain-key.pem", nil)
}
func indexEchec(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "<h1>Echec de rime</h1> </br> <img src=\"/static/echecderime/echec.gif\">")
}
I think you need to give r as the last parameter to http.ListenAndServeTLS.
you can also use a http.server instance
//create server instance
server := http.Server{
Addr: ":443",
TLSConfig: tlsConfig(cert),
}
rtr := mux.NewRouter()
rtr.HandleFunc("/profile", HandlerProfile).Methods("GET")
//rtr.HandleFunc( other routes...
//pass mux handler to server
server.Handler = rtr
server.ListenAndServeTLS("", "")

Resources