Database Integration with GraphQL, Fiber, and SQLx in Go


This article will guide you through building a GraphQL API that connects to a PostgreSQL database using Fiber, SQLx, and gqlgen. We'll cover everything from setting up the database to handling queries via resolvers.
Code Explanation and Execution Flow
1. Database Connection (db.go
)
Code:
package main
import (
"log"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
)
var db *sqlx.DB
func initDB() {
var err error
db, err = sqlx.Connect("postgres", "user=postgres password=yourpassword dbname=graphql_db sslmode=disable")
if err != nil {
log.Fatalf("Failed to connect to database: %v", err)
}
log.Println("Database connected successfully")
}
Explanation:
Purpose: Initializes the connection to the PostgreSQL database.
sqlx.Connect
: Connects to the database using the PostgreSQL driver.Error Handling: If the connection fails, the application logs the error and stops.
Global Variable (
db
): Used across the app for executing queries.
Execution Flow:
initDB
is called inmain.go
to establish a connection with the database before the server starts.Queries in resolvers use this connection to fetch or modify data.
2. Resolvers (resolvers.go
)
Code:
package main
type queryResolver struct{}
func (r *queryResolver) Users() ([]*User, error) {
var users []*User
err := db.Select(&users, "SELECT * FROM users")
if err != nil {
return nil, err
}
return users, nil
}
func (r *queryResolver) User(id string) (*User, error) {
var user User
err := db.Get(&user, "SELECT * FROM users WHERE id = $1", id)
if err != nil {
return nil, err
}
return &user, nil
}
Explanation:
Resolvers: Functions that handle GraphQL queries by interacting with the database.
Users
Resolver:Fetches all users from the
users
table.Uses
db.Select
to map query results into a slice ofUser
objects.
User
Resolver:Fetches a single user by ID using a parameterized query.
Uses
db.Get
to fetch and map the result to aUser
object.
Error Handling:
- Returns
nil
and an error if the database query fails or no data is found.
- Returns
Execution Flow:
GraphQL server invokes the resolver based on the query type (
users
oruser
).The resolver executes a SQL query to fetch data from the database.
The results are returned as GraphQL responses.
3. GraphQL Types (models.go
)
Code:
package main
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
}
Explanation:
Defines the
User
type to represent the database structure.JSON tags: Ensure that fields are serialized with these names in GraphQL responses.
4. GraphQL Handler (graphql_handler.go
)
Code:
package main
import (
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/playground"
"github.com/gofiber/fiber/v2"
)
func GraphQLHandler(app *fiber.App, srv *handler.Server) {
app.All("/query", func(c *fiber.Ctx) error {
srv.ServeHTTP(c.Context())
return nil
})
app.Get("/", func(c *fiber.Ctx) error {
c.Redirect("/playground")
return nil
})
app.Get("/playground", func(c *fiber.Ctx) error {
playground.Handler("GraphQL Playground", "/query").ServeHTTP(c.Context())
return nil
})
}
Explanation:
Purpose: Routes requests to the GraphQL server.
/query
Route:- Handles GraphQL requests (queries, mutations) by invoking the server handler.
/playground
Route:- Serves the GraphQL Playground for testing queries interactively.
Fiber Middleware: Uses Fiber's routing and HTTP handling for simplicity and speed.
Execution Flow:
Users access
/playground
in a browser to open the testing UI.Queries and mutations are sent to
/query
, where the GraphQL server processes them.
5. Fiber Server (main.go
)
Code:
package main
import (
"log"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/gofiber/fiber/v2"
)
func main() {
initDB() // Initialize database
// Create Fiber app
app := fiber.New()
// Create GraphQL server
srv := handler.NewDefaultServer(generated.NewExecutableSchema(generated.Config{
Resolvers: &Resolver{},
}))
// Register GraphQL routes
GraphQLHandler(app, srv)
// Start server
log.Println("Server running on http://localhost:8080/")
log.Fatal(app.Listen(":8080"))
}
Explanation:
Initialize Database: Calls
initDB
to establish a database connection.Fiber App: Creates an HTTP server using Fiber.
GraphQL Server:
Sets up the gqlgen executable schema and resolvers.
Links the Fiber app to the GraphQL server and playground routes.
Start Server: Starts the Fiber app on port 8080.
Execution Flow:
Initializes the database connection with
initDB
.Sets up routes for GraphQL and starts the server.
Logs the server URL, which can be accessed via a browser or GraphQL client.
6. Test GraphQL Queries
Query All Users:
query {
users {
id
name
age
}
}
Execution Flow:
The request hits the
/query
endpoint.The
users
resolver executes a SQL query (SELECT * FROM users
).Results are returned as a list of
User
objects.
Sample Response:
{
"data": {
"users": [
{
"id": "1",
"name": "Alice",
"age": 25
},
{
"id": "2",
"name": "Bob",
"age": 30
}
]
}
}
Query a User by ID:
query {
user(id: "1") {
name
age
}
}
Execution Flow:
The request hits the
/query
endpoint.The
user
resolver executes a parameterized query (SELECT * FROM users WHERE id = $1
).The result is returned as a single
User
object.
Sample Response:
{
"data": {
"user": {
"name": "Alice",
"age": 25
}
}
}
Conclusion
In this tutorial, you:
Learned how to connect a PostgreSQL database to a GraphQL API.
Built a server using Fiber, SQLx, and gqlgen.
Queried and fetched data using GraphQL.
This setup can be extended with mutations, authentication, and more advanced features like subscriptions for real-time updates.
Subscribe to my newsletter
Read articles from Shivam Dubey directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
