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.
Related
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?
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.
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())
I am trying to mock an HTTP client that's being used within an API function call in my Go code.
import (
"internal.repo/[...]/http"
"encoding/json"
"strings"
"github.com/stretchr/testify/require"
)
func CreateResource(t *testing.T, url string, bodyReq interface{}, username string, password string, resource string) []byte {
bodyReqJSON, err := json.Marshal(bodyReq)
if err != nil {
panic(err)
}
headers := make(map[string]string)
headers["Content-Type"] = "application/json"
logger.Logf(t, "*************************** CREATE a temporary test %s ***************************", resource)
// this func below should be mocked
statusCode, body := http.POST(t, url, bodyReqJSON, headers, username, password)
require.Equal(t, statusCode, 201, "******ERROR!! A problem occurred while creating %s. Body: %s******", resource, strings.TrimSpace(string(body)))
return body
}
I'd like to mock my http.POST function that it's part of an internal HTTP package so that I do not need to actually make the online call, and isolate the test offline.
Is there an alternative way to dependency-inject a mock structure that implements an hypothetical HTTP interface?
How would you do something like this?
Here's the solution, thanks to #Peter.
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestCreateResource(t *testing.T) {
t.Run("successful", func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(201)
}))
defer server.Close()
o := CreateResource(t, server.URL, nil, "admin", "password", "resource")
assert.Equal(t, []byte{}, o)
})
}
I have this code :
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.New()
r.GET("/user/:id", func(c *gin.Context) {
// How can I get the litteral string "/user/:id" here ?
c.JSON(http.StatusOK, gin.H{"message": "received request"})
})
}
Is there any way that I can retrieve inside the handler the litteral string /user/:id? If I use c.Request.Path it will give me the full output of the path like /user/10.
According to the documentation you can use FullPath().
router.GET("/user/:id", func(c *gin.Context) {
c.FullPath() == "/user/:id" // true
})