DEV Community

Cover image for CRUD Operations with Goravel (Laravel for GO)
Adewale Charles
Adewale Charles

Posted on

CRUD Operations with Goravel (Laravel for GO)

About Goravel

Goravel is a web application framework with complete functions and excellent scalability, as a starting scaffolding to help Gopher quickly build their own applications.

Goravel is the perfect clone of Laravel for Go developers, which means a PHP developer like myself can easily relate to the framework and start writing with little learning to do.

Let's start with the installation, you can follow this article to install or visit Goravel official documentation website.

// Download framework
git clone https://github.com/goravel/goravel.git && rm -rf goravel/.git*

// Install dependencies
cd goravel && go mod tidy

// Create .env environment configuration file
cp .env.example .env

// Generate application key
go run . artisan key:generate

//start the application
go run .
Enter fullscreen mode Exit fullscreen mode

On opening the code in your favourite text editor, you will see that the project structure is exactly like Laravel, so Laravel developers won't feel so lost.

Model, Migration and Controller

To create a model, migration and controller, we can use the artisan command just like we do in Laravel.

// create model 
go run . artisan make:model Category

// create migration 
go run . artisan make:migration create_categories_table

// create controller 
go run . artisan make:controller --resource category_controller
Enter fullscreen mode Exit fullscreen mode

Now if we check the database/migration folder we will see that files have been created for us, the up and down file, open the up migration file and paste the code below inside:

CREATE TABLE categories (
  id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  name varchar(255) NOT NULL,
  created_at datetime(3) NOT NULL,
  updated_at datetime(3) NOT NULL,
  PRIMARY KEY (id),
  KEY idx_categories_created_at (created_at),
  KEY idx_categories_updated_at (updated_at)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;NGINE = InnoDB DEFAULT CHARSET = utf8mb4;
Enter fullscreen mode Exit fullscreen mode

If we check inside app/http/controllers folder, we will have a category_controller.go file, and the content inside should look like what we have below:

package controllers

import (
 "github.com/goravel/framework/contracts/http"
)

type CategoryController struct {
 //Dependent services
}

func NewCategoryController() *CategoryController {
 return &CategoryController{
  //Inject services
 }
}

func (r *CategoryController) Index(ctx http.Context) http.Response {
 return nil
} 

func (r *CategoryController) Show(ctx http.Context) http.Response {
 return nil
}

func (r *CategoryController) Store(ctx http.Context) http.Response {
 return nil
}

func (r *CategoryController) Update(ctx http.Context) http.Response {
 return nil
}

func (r *CategoryController) Destroy(ctx http.Context) http.Response {
 return nil
}
Enter fullscreen mode Exit fullscreen mode

Then, let's locate the category model file inside app/http/model , then paste the code below inside:

package models

import (
 "github.com/goravel/framework/database/orm"
)

type Category struct {
 orm.Model
 Name string
}
Enter fullscreen mode Exit fullscreen mode

There is nothing much going on here, we are just declaring our fillable with their data type.

Let’s locate our api.php file inside the route folder and update the code to look like the below:

package routes

import (
 "github.com/goravel/framework/facades"

 "goravel/app/http/controllers"
)

func Api() {
 userController := controllers.NewUserController()
 facades.Route().Get("/users/{id}", userController.Show)

 //Resource route
 categoryController := controllers.NewCategoryController()
 facades.Route().Resource("/category", categoryController)
}
Enter fullscreen mode Exit fullscreen mode

Now, let's update our imports inside the category_controller.go file and update it to below:

import (
 "goravel/app/models"
 "github.com/goravel/framework/contracts/http"
  "github.com/goravel/framework/facades"
)
Enter fullscreen mode Exit fullscreen mode

We just imported our models and facades, facades allow us to have access to a lot of cool useful things like Validation, orm, etc. orm is the ORM for GO.

Time to write some code!

Let's update our methods in our controller to the code below:

Index Method

// this is just to pull all categories in our database
func (r *CategoryController) Index(ctx http.Context) http.Response {
 var categories []models.Category

 if err := facades.Orm().Query().Find(&categories); err != nil {
  return ctx.Response().Json(http.StatusInternalServerError, http.Json{
   "error": err.Error(),
  })
 }

 return ctx.Response().Success().Json(http.Json{
  "success": true,
  "message": "Data fetch successfully",
  "data":    categories,
 })
} 
Enter fullscreen mode Exit fullscreen mode

Store Method

func (r *CategoryController) Store(ctx http.Context) http.Response {

// validate the input name that the user is passing
 validation, err := facades.Validation().Make(ctx.Request().All(), map[string]string{
        "name": "required|string",
    })

// check if an error occured, might not be validation error
    if err != nil {
        return ctx.Response().Json(http.StatusInternalServerError, http.Json{
            "success": false,
            "message": "Validation setup failed",
            "error":   err.Error(),
        })
    }

// check for validation errors
    if validation.Fails() {
        return ctx.Response().Json(http.StatusBadRequest, http.Json{
            "success": false,
            "message": "Validation failed",
            "errors":  validation.Errors().All(),
        })
    }

// Create the category
 category := &models.Category{
  Name: ctx.Request().Input("name"),
 }

// save the category and return error if there is any
 if err := facades.Orm().Query().Create(category); err != nil {
  return ctx.Response().Json(http.StatusInternalServerError, http.Json{
   "success": false,
   "errors": err.Error(),
  })
 }

// upon successfull creation return success response with the newly created category
 return ctx.Response().Success().Json(http.Json{
  "success": true,
  "message": "Category created successfully",
  "data":    category,
 })
}
Enter fullscreen mode Exit fullscreen mode

Update Method

func (r *CategoryController) Update(ctx http.Context) http.Response {

    validation, err := facades.Validation().Make(ctx.Request().All(), map[string]string{
        "id":   "required",
        "name": "required|string",
    })

    if err != nil {
        return ctx.Response().Json(http.StatusInternalServerError, http.Json{
            "success": false,
            "message": "Validation setup failed",
            "error":   err.Error(),
        })
    }

    if validation.Fails() {
        return ctx.Response().Json(http.StatusBadRequest, http.Json{
            "success": false,
            "message": "Validation failed",
            "errors":  validation.Errors().All(),
        })
    }

// find the category using the id
    var category models.Category
    if err := facades.Orm().Query().Where("id", ctx.Request().Input("id")).First(&category); err != nil {
        return ctx.Response().Json(http.StatusNotFound, http.Json{
            "success": false,
            "message": "Category not found",
        })
    }

// update or return error if there is any
    category.Name = ctx.Request().Input("name")
    if err := facades.Orm().Query().Save(&category); err != nil {
        return ctx.Response().Json(http.StatusInternalServerError, http.Json{
            "success": false,
            "message": "Failed to update category",
            "error":   err.Error(),
        })
    }

// return success if successfull
    return ctx.Response().Success().Json(http.Json{
        "success": true,
        "message": "Category updated successfully",
        "data":    category,
    })
}
Enter fullscreen mode Exit fullscreen mode

Destroy Method

func (r *CategoryController) Destroy(ctx http.Context) http.Response {

// find the category by id
 var category models.Category
 facades.Orm().Query().Find(&category, ctx.Request().Input("id"))
 res, err := facades.Orm().Query().Delete(&category)

// return error if there is any
 if err != nil {
  return ctx.Response().Json(http.StatusInternalServerError, http.Json{
  "error": err.Error(),
  })
 }

// return success if successfull
 return ctx.Response().Success().Json(http.Json{
  "success": true,
  "message": "Category deleted successfully",
  "data":    res,
 })
}
Enter fullscreen mode Exit fullscreen mode

Now we need to set up the database, I will be using MySQL, it is important to note the gravel ships with several database drivers. locate your .env file and edit this line below:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=DATABASE_NAME
DB_USERNAME=DATABASE_USERNAME
DB_PASSWORD=DATABASE_PASSWORD
Enter fullscreen mode Exit fullscreen mode

Then in your terminal type:

go run . artisan migrate
Enter fullscreen mode Exit fullscreen mode

This will automatically migrate our categories table in our DB.

Now we need to stop our server if you are running it before and restart it.

You can now test your endpoints from Postman you should note that by adding the resource to the category endpoint you now have access to GET, POST, PUT, or DELETE methods for your category endpoints. you can access your endpoints in this manner:

// GET category
http://localhost:3000/category

//POST catgory - with payload
http://localhost:3000/category
{
    "name": "goravel"
}

// PUT category - with payload
http://localhost:3000/category/{id}
{
    "id": 1,
    "name": "laravel"
}

//DELETE category
http://localhost:3000/category/{id}
Enter fullscreen mode Exit fullscreen mode

That's how you make simple CRUD operations using Goravel.

Top comments (0)