Why Fiber duplicate GET endpoint whith a HEAD endpoint - go

these is my api and i don't know what is the problem for that endpoints duplicated, i was trying if is something of config but there is not nothing about in their documentation
package main
import (
"aurora/routes"
"fmt"
"github.com/gofiber/fiber/v2"
)
func main() {
app := fiber.New(fiber.Config{
AppName: "Aurora Api V1",
})
routes.ServerRoutes(app)
app.Get("/AAAAAAAA", func(c *fiber.Ctx) error {
return c.JSON("hellow from login")
})
routesList := app.GetRoutes()
for i, route := range routesList {
fmt.Printf("%d - %d\n", i+1, route)
}
app.Listen(":3000")
}
package routes
import (
"aurora/routes/user"
"github.com/gofiber/fiber/v2"
)
func ServerRoutes(server *fiber.App) {
user.UserRoutes(server.Group("/user"))
}
package user
import "github.com/gofiber/fiber/v2"
func UserRoutes(router fiber.Router) {
router.Get("/login", func(c *fiber.Ctx) error {
return c.JSON("hellow from login")
})
router.Get("/logout", func(c *fiber.Ctx) error {
return c.JSON("hellow from logout")
})
router.Get("/signup", func(c *fiber.Ctx) error {
return c.JSON("hellow from signup")
})
}
i want that golang just map GET endpoints not HEAD endpoints, or there a reason for that?

I think HEAD method is used as default for GET routes in Fiber since it's nearly the same thing. Read more about HEAD method in MDN Docs.

Related

How to apply Chi middleware for subroutes?

Given the following sample API using Chi
package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func main() {
http.ListenAndServe(":3000", GetRouter())
}
func GetRouter() *chi.Mux {
apiRouter := chi.NewRouter()
apiRouter.Route("/foo-group", func(fooGroupRouter chi.Router) {
fooGroupRouter.Use(middleware.AllowContentType("application/json"))
fooGroupRouter.Post("/sub-route", HandleRoute( /* Params */))
})
// other routes
return apiRouter
}
func HandleRoute( /* Params */) http.HandlerFunc {
return func(responseWriter http.ResponseWriter, request *http.Request) {
responseWriter.WriteHeader(http.StatusCreated)
responseWriter.Write([]byte("done"))
}
}
When calling the API via
POST localhost:3000/foo-group/sub-route
I get a 201 with "done". But I want to ensure this endpoint only accepts the content type "application/json", otherwise send back a 415.
Unfortunately the middleware is not working yet. I also tried to test the behaviour with the testrunner
package main
import (
"net/http"
"net/http/httptest"
"strconv"
"testing"
)
func TestHandleRoute(suite *testing.T) {
server := httptest.NewServer(HandleRoute())
suite.Run("responds with status code "+strconv.Itoa(http.StatusUnsupportedMediaType)+" if content type is not application/json", func(testing *testing.T) {
response, _ := http.Post(server.URL, "text/xml", nil)
if response.StatusCode != http.StatusUnsupportedMediaType {
testing.Errorf("Expected statuscode %d but got %d", http.StatusUnsupportedMediaType, response.StatusCode)
}
})
}
Unfortunately the test fails with the message
main_test.go:17: Expected statuscode 415 but got 201
so it seems the middleware didn't run. How can I fix that?

How to set Routes Group in Go Fiber V2 from separated file?

I want to make seperate files for each sub main routes. I am using go 1.17
main.go
package main
import (
"rolling_glory_go/routes"
"github.com/gofiber/fiber/v2"
)
func main() {
app := fiber.New()
app.Get("/", func(c *fiber.Ctx) error {
err := c.SendString("Hello golang!")
return err
})
routes.R_login(app.Group("/login"))
routes.R_users(app.Group("/users"))
app.Listen(":3000")
}
I want to import routes from r_login.go and r_users.go so i could manage many routes from different files and not put many routes from single file in main.go. I got an error like this.
.\main.go:17:26: cannot use app.Group("/login") (type fiber.Router) as type *fiber.Group in argument to routes.R_login: need type assertion
.\main.go:18:26: cannot use app.Group("/users") (type fiber.Router) as type *fiber.Group in argument to routes.R_users: need type assertion
My Structure Folder
r_login.go
package routes
import "github.com/gofiber/fiber/v2"
func R_login(router *fiber.Group) {
router.Get("/", func(c *fiber.Ctx) error {
return c.SendString("respond with a resource")
})
}
r_users.go
package routes
import "github.com/gofiber/fiber/v2"
func R_users(router *fiber.Group) {
router.Get("/", func(c *fiber.Ctx) error {
return c.SendString("respond with a resource")
})
}
How to fix this ?
As you have app.Group("/login") which of type fiber.Router
, just modify R_login to have it accept this type.
package routes
import "github.com/gofiber/fiber/v2"
func R_login(router fiber.Router) {
router.Get("/", func(c *fiber.Ctx) error {
return c.SendString("respond with a resource")
})
}

Graphql Subscriptions not working with Gin

When I tried to setup a Go web server with GraphQL I used this as template. It is basically a combo of gin and 99designs/gqlgen.
When I create a basic gqlgen server based on net/http package, the declaration of GraphQL subscriptions work as expected.
package main
import (
"log"
"net/http"
"os"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/playground"
"github.com/jawil003/gqlgen/graph"
"github.com/jawil003/gqlgen/graph/generated"
)
const defaultPort = "8080"
func main() {
port := os.Getenv("PORT")
if port == "" {
port = defaultPort
}
srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{}}))
http.Handle("/", playground.Handler("GraphQL playground", "/query"))
http.Handle("/query", srv)
log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
But when I add gin, like this:
package main
import (
"github.com/gin-gonic/gin"
"github.com/jawil003/gqlgen-todos/graph"
"github.com/jawil003/gqlgen-todos/graph/generated"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/playground"
)
// Defining the Graphql handler
func graphqlHandler() gin.HandlerFunc {
// NewExecutableSchema and Config are in the generated.go file
// Resolver is in the resolver.go file
h := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{Resolvers: &graph.Resolver{}}))
return func(c *gin.Context) {
h.ServeHTTP(c.Writer, c.Request)
}
}
// Defining the Playground handler
func playgroundHandler() gin.HandlerFunc {
h := playground.Handler("GraphQL", "/query")
return func(c *gin.Context) {
h.ServeHTTP(c.Writer, c.Request)
}
}
func main() {
// Setting up Gin
r := gin.Default()
r.POST("/query", graphqlHandler())
r.GET("/", playgroundHandler())
r.Run()
}
I get this issue:
{ "error": "Could not connect to websocket endpoint ws://localhost:8080/query. Please check if the endpoint url is correct." }
Is there any known solution to make gin work with graphql subscriptions?
Hello to fix error Could not connect to websocket endpoint.. with Gin change r.POST("/query", graphqlHandler()) to r.Any("/query", graphqlHandler())

How do I get the body that was sent? Using gin gonic

How do I get the body that was sent?
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
fmt.Println("Hello, world!")
r := gin.Default()
r.POST("/", func(c *gin.Context) {
body := c.Request.Body
c.JSON(200,body);
})
r.Run(":8080");
}
I make a request via postman
{
"email": "test#gmail.com",
"password": "test"
}
and in response I get empty json {}
what to do?
You can bind the incoming request json as follows:
package main
import (
"github.com/gin-gonic/gin"
)
type LoginReq struct {
Email string
Password string
}
func main() {
r := gin.Default()
r.POST("/", func(c *gin.Context) {
var req LoginReq
c.BindJSON(&req)
c.JSON(200, req)
})
r.Run(":8080")
}
Remember this method gives 400 if there is a binding error. If you want to handle error yourself, try ShouldBindJSON which returns an error if any or nil.

How to group routes in gin?

I want to group my routes in different files, so the main file won't be very messy.
I want something like this in their own files:
v1 := router.Group("/v1")
{
v1.Group("users", usersRoutes)
v1.Group("pictures", picturesRoutes)
v1.Group("friends", friendsRoutes)
}
So each one of the *Routes would look something like this:
users := v1.Group("/users")
{
users.GET("/", getUsers)
users.POST("/", createUser)
}
Is this possible? Right now my code looks like this:
package app
import (
"net/http"
"github.com/gin-gonic/gin"
)
func getUrls() {
v1 := router.Group("/v1")
{
ping := v1.Group("/ping")
{
ping.GET("/", pongFunction)
}
users := v1.Group("/users")
{
users.GET("/", getUsersFunction)
}
}
}
But this is going to increase its size a lot.
You would need to store router variable in your struct or global variable. Then individual go files will add handlers to that variable. Here is an example:
routes.go
package app
import (
"github.com/gin-gonic/gin"
)
type routes struct {
router *gin.Engine
}
func NewRoutes() routes {
r := routes{
router: gin.Default(),
}
v1 := r.router.Group("/v1")
r.addPing(v1)
r.addUsers(v1)
return r
}
func (r routes) Run(addr ...string) error {
return r.router.Run()
}
ping.go
package app
import "github.com/gin-gonic/gin"
func (r routes) addPing(rg *gin.RouterGroup) {
ping := rg.Group("/ping")
ping.GET("/", pongFunction)
}
func pongFunction(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
}
users.go
package app
import "github.com/gin-gonic/gin"
func (r routes) addUsers(rg *gin.RouterGroup) {
users := rg.Group("/users")
users.GET("/", getUsersFunction)
}
func getUsersFunction(c *gin.Context) {
c.JSON(200, gin.H{
"users": "...",
})
}

Resources