Custom Request Validation with ozzo-validation in Go

Custom validation in Echo using ozzo-validation makes input handling much cleaner and more structured. Instead of manually checking each field, you can define validation rules declaratively. Let’s say we need to validate a form submission where each field has attributes like label, type, and is_required. package form_requests import ( "fmt" "regexp" validation "github.com/go-ozzo/ozzo-validation/v4" "github.com/labstack/echo/v4" ) // FieldRequest defines a single form field type FieldRequest struct { Label string `json:"label"` Type string `json:"type"` IsRequired bool `json:"is_required"` } // CreateFormFieldsRequest wraps multiple fields type CreateFormFieldsRequest struct { Fields []FieldRequest `json:"fields"` } // BindAndValidate binds JSON data and runs validation func (r *CreateFormFieldsRequest) BindAndValidate(c echo.Context) []string { if err := c.Bind(r); err != nil { return []string{"Invalid request payload"} } err := validation.ValidateStruct(r, validation.Field(&r.Fields, validation.Required.Error("Fields array is required"), validation.Each( validation.By(validateField), )), ) return extractValidationErrors(err) } // validateField ensures each field meets the required rules func validateField(value interface{}) error { field, ok := value.(FieldRequest) if !ok { return fmt.Errorf("invalid field format") } return validation.ValidateStruct(&field, validation.Field(&field.Label, validation.Required.Error("Label is required"), validation.Length(3, 50).Error("Label must be between 3 and 50 characters"), validation.Match(regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)).Error("Label can only contain letters, numbers, underscores, and dashes"), ), validation.Field(&field.Type, validation.Required.Error("Type is required"), validation.In("text", "number", "email", "date", "checkbox").Error("Invalid field type"), ), validation.Field(&field.IsRequired, validation.Required.Error("IsRequired is required")), ) } // extractValidationErrors formats errors into a slice of strings func extractValidationErrors(err error) []string { if err == nil { return nil } var errors []string if ve, ok := err.(validation.Errors); ok { for _, e := range ve { errors = append(errors, e.Error()) } } return errors } Declarative Validation: Instead of manually checking fields, ozzo-validation provides a clean way to define rules. Custom Validation Function: validateField() ensures each field meets the required format and constraints. Consistent Error Handling: extractValidationErrors() collects and formats validation errors into a slice for easier debugging and response handling.

April 6, 2025 · 2 min · 295 words · Saqib Razzaq

Group Similar Routes in Go Echo

Using Echo groups is a great way to organize routes, especially when dealing with versioning, middleware, or related endpoints. Instead of cluttering the main file with multiple routes, you can logically group them. package main import ( "net/http" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" ) func main() { e := echo.New() // Global middleware e.Use(middleware.Logger()) e.Use(middleware.Recover()) // API versioning v1 := e.Group("/api/v1") // Group for user-related routes users := v1.Group("/users") users.GET("", getUsers) // GET /api/v1/users users.POST("", createUser) // POST /api/v1/users users.GET("/:id", getUserByID) // GET /api/v1/users/:id // Group for admin routes with middleware admin := v1.Group("/admin", adminMiddleware) admin.GET("/dashboard", adminDashboard) // GET /api/v1/admin/dashboard e.Logger.Fatal(e.Start(":8080")) } // Handlers func getUsers(c echo.Context) error { return c.JSON(http.StatusOK, map[string]string{"message": "List of users"}) } func createUser(c echo.Context) error { return c.JSON(http.StatusCreated, map[string]string{"message": "User created"}) } func getUserByID(c echo.Context) error { id := c.Param("id") return c.JSON(http.StatusOK, map[string]string{"message": "User ID: " + id}) } func adminDashboard(c echo.Context) error { return c.JSON(http.StatusOK, map[string]string{"message": "Admin dashboard"}) } // Middleware for admin routes func adminMiddleware(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { // Simulate an auth check if c.Request().Header.Get("Authorization") != "Bearer admin_token" { return c.JSON(http.StatusUnauthorized, map[string]string{"error": "Unauthorized"}) } return next(c) } }

April 6, 2025 · 1 min · 187 words · Saqib Razzaq

Parse JSON to Struct in Go

Parsing JSON into a struct using json.Unmarshal is a fundamental task in Go when working with APIs or reading JSON files. The encoding/json package makes this process straightforward. Let’s say we receive the following JSON payload: { "name": "John Doe", "age": 30, "email": "johndoe@example.com" } We can parse this JSON into a struct like this: package main import ( "encoding/json" "fmt" ) type User struct { Name string `json:"name"` Age int `json:"age"` Email string `json:"email"` } func main() { jsonData := `{"name": "John Doe", "age": 30, "email": "johndoe@example.com"}` var user User err := json.Unmarshal([]byte(jsonData), &user) if err != nil { fmt.Println("Error parsing JSON:", err) return } fmt.Println("Parsed User Struct:", user) }

April 6, 2025 · 1 min · 111 words · Saqib Razzaq

Request Logger Middleware in Go Echo

Middleware in Echo allows us to intercept requests before they reach handlers, making it a great place to add logging. Echo provides a built-in logging middleware (middleware.Logger()) but for more control, we can create a custom middleware: package main import ( "log" "time" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" ) // Custom logging middleware func requestLogger(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { start := time.Now() req := c.Request() log.Printf("Request: method=%s, path=%s, remote=%s", req.Method, req.URL.Path, req.RemoteAddr) err := next(c) res := c.Response() log.Printf("Response: status=%d, duration=%s", res.Status, time.Since(start)) return err } } func main() { e := echo.New() // Use Echo's default logger middleware e.Use(middleware.Logger()) // Use custom logging middleware e.Use(requestLogger) e.GET("/", func(c echo.Context) error { return c.String(200, "Hello, Echo!") }) e.Start(":8080") }

April 6, 2025 · 1 min · 119 words · Saqib Razzaq

How to download all files from an S3 bucket

April 4, 2025 · 1 min · 65 words · Saqib Razzaq

How to upload files to S3 using PHP SDK

April 4, 2025 · 1 min · 133 words · Saqib Razzaq

How to activate a virtual environment via Bash

Create a file named anything.sh and make it executable Paste following code in file Run ./path-to-file.sh cd path/to/env/dir && source bin/activate

November 11, 2021 · 1 min · 21 words · Saqib Razzaq

How to Import All CSV Files in Directory in MySQL via Bash

Create a file import.sh and make it executable Paste following code in file mysqluser='root' mysqlpass='password' mysqldb='database_name' tablename='mysql_table_name' DIRECTORY='input_directory' for csv in $DIRECTORY/*.csv; do echo "Loading $csv" mysql -u $mysqluser --password=$mysqlpass -D $mysqldb -e "LOAD DATA INFILE '$csv' IGNORE INTO TABLE $tablename FIELDS TERMINATED BY '\t' ENCLOSED BY '\"' LINES TERMINATED BY '\n' IGNORE 1 LINES;" done

November 11, 2021 · 1 min · 56 words · Saqib Razzaq

How to quickly login to MySQL using Bash

I know this method isn’t the most secure way. But when I’m working on personal projects, it gets annoying having to enter credentials every time. Hence, I put together this little script to quickly log me in. I create file mysql.sh with following contents mysql -u username --password='password_here'

November 11, 2021 · 1 min · 48 words · Saqib Razzaq

How to run a script if it is not already running in Linux

Let’s say you have a script called crawl.py and you never want two instances of it running at the same time. The following script can do the job RUNNING="$(ps aux|grep crawl|grep -v grep|wc -l)" if [ $RUNNING -eq 0 ] then python crawl.py else echo "Already running : skipping"; fi

November 11, 2021 · 1 min · 50 words · Saqib Razzaq

How to ZIP all files in directory and send to another server

First install zip if not already install Ubuntu apt-get install zip Centos yum install zip Then create a file.sh and paste following code OUTFILE=outputfile.zip INPUTDIR=inputdir zip -R $OUTFILE $INPUTDIR scp $OUTFILE usrename@outserver:/path/of/ $OUTFILE -i key.pem

November 11, 2021 · 1 min · 35 words · Saqib Razzaq

How to setup token API auth with Sanctum in Laravel

Read about Laravel Sanctum Create your laravel project composer create-project --prefer-dist laravel/laravel my-laravel-blog-api Move into project directory and then install Sanctum composer require laravel/sanctum Now let’s publish migrations and configuration files php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider" Run database migrations php artisan migrate Make sure your User model looks like this use Laravel\Sanctum\HasApiTokens; class User extends Authenticatable { use HasApiTokens, HasFactory, Notifiable; } Make an authentication / user controller. Let’s use AuthenticationController for this php artisan make:controller AuthenticationController Then add following code in this controller se Illuminate\Support\Facades\Hash; public function register(Request $request) { $validatedData = $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|min:8', ]); $user = User::create([ 'name' => $validatedData['name'], 'email' => $validatedData['email'], 'password' => Hash::make($validatedData['password']), ]); $token = $user->createToken('auth_token')->plainTextToken; return response()->json([ 'access_token' => $token, 'token_type' => 'Bearer', ]); } First, we validate the incoming request to make sure all required variables are present. Then we persist the supplied details into the database. Once a user has been created, we create a new personal access token for them using the createToken() method and give the token a name of auth_token. Because createToken() will return an instance of Laravel\Sanctum\NewAccessToken, we call the plainTextTokenproperty on the instance to access the plain-text value of the token. Finally, we return a JSON response containing the generated token as well as the type of the token. Then add login method to your controller. It should look like this use App\Models\User; use Illuminate\Support\Facades\Auth; public function login(Request $request) { if (!Auth::attempt($request->only('email', 'password'))) { return response()->json([ 'message' => 'Invalid login details' ], 401); } $user = User::where('email', $request['email'])->firstOrFail(); $token = $user->createToken('auth_token')->plainTextToken; return response()->json([ 'access_token' => $token, 'token_type' => 'Bearer', ]); } Add following two routes to allow registrations and login Route::post('/register', [AuthController::class, 'register']); Route::post('/login', [AuthController::class, 'login']);

November 3, 2021 · 2 min · 287 words · Saqib Razzaq

How to test Registration and Login in Laravel

I often work with Laravel APIs that require user registration and authentication. Of course, there is no stability in building applications without unit tests. Hence, I create following tests to ensure registration and login functions are working as expected. TestRegister.php Run php artisan make:test TestRegister Go to tests\Feature and open TestRegister.php Use following test to make sure user registrations are working. Of course, this is a minimal example. But this should give you a good idea of how you can get started. public function testsRegistration() { $payload = [ 'name' => 'Jenny', 'email' => 'jenny@test.com', 'password' => 'password', 'level' => '5', ]; $this->json('post', '/api/register', $payload) ->assertStatus(201) ->assertJsonStructure([ 'data' => [ 'access_token', 'token_type', ], ]);; } You’ll need to ajdust $payload variables according to what your API’s register endpoint expects. You’ll also need to adjust assertJsonStructure values based on what you are sending back as response. ...

November 2, 2021 · 2 min · 292 words · Saqib Razzaq

Laravel - manually handle HTTP exceptions

Laravel automatically handles HTTP exceptions and throws errors / redirects as it sees fit. Sometimes, this isn’t an ideal behaviour. I was building an API and wanted to display custom messages for missing routes, forbidden and other errors. This can be done like this Open app\Exceptions\Handler.php If you want to handle missing models, paste following snippet in render method if ($exception instanceof ModelNotFoundException) { return response()->json([ 'error' => 'Model not found' ], 404); } If you’d like to handle other HTTP exceptions, paste the following snippet instead if ($this->isHttpException($exception)) { switch ($exception->getStatusCode()) { // not authorized case '403': return \Response::json([ 'error' => 'You are not allowed to access this' ], 403); break; // not found case '404': return \Response::json([ 'error' => 'Resource not found' ], 404); break; // internal error case '500': return \Response::json([ 'error' => 'Something went terribly wrong' ], 500); break; default: return $this->renderHttpException($exception); break; } }

November 2, 2021 · 1 min · 149 words · Saqib Razzaq

How to create a user by default in Laravel

Sure, we can user Laravel’s database seeding and $faker to create any number of fake users. Personally, I don’t like to waste time fetching a new random user and their email address to continue my testing. I like have the same user created each time database is seeded. I do it like this. Run below command to create a new seeder in database/seeds directory. php artisan make:seeder UserSeeder In run method of UserSeeder.php paste following code $user = User::create([ 'name' => 'Saqib', 'email' => 'saqib@saqib.com', 'password' => Hash::make('password'), 'level' => 1 ]); Finally, add below line in run method in seeds\DatabaseSeeder.php $this->call(UserSeeder::class); ...

October 21, 2021 · 1 min · 125 words · Saqib Razzaq

Ubtunu 20 Post Installation Checklist

Run an update first apt-get update Install necessary dev tools apt-get install -y zip unzip wget curl youtube-dl git subversion dconf-editor build-essential Install Sublime Text apt-get update sudo apt install -y dirmngr gnupg apt-transport-https ca-certificates software-properties-common curl -fsSL https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key add - sudo add-apt-repository "deb https://download.sublimetext.com/ apt/stable/" sudo apt install -y sublime-text Install Google chrome apt-get update wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb sudo dpkg -i google-chrome-stable_current_amd64.deb Install Apache, MySQL, PHP, PHPMyAdmin Apache and MySQL apt-get update sudo apt install -y apache2 mysql-server sudo mysql_secure_installation PHP, PHPMyAdmin and some extensions ...

October 18, 2021 · 1 min · 192 words · Saqib Razzaq

How to create and use Seeders in Laravel

Create a seeder php artisan make:seeder seederName This creates a file seederName in database/seeds You can use a model or default database class. I’ll show you both examples To use an existing model, try this approach // assumes you've already added "use App\User" and "use Illuminate\Support\Facades\Hash;" at top of your file $user = User::create([ 'name' => 'Saqib', 'email' => 'saqib@saqib.com', 'password' => Hash::make('password'), 'level' => 1 ]); If you don’t have a model and want to run database inserts, try something like this DB::table('users')->insert([ 'name' => 'Jon Snow', 'email' => 'saqib@test.com', 'password' => Hash::make('password') ]); Run php artisan db:seed or php artisan migrate:fresh --seed to run seeders

October 17, 2021 · 1 min · 107 words · Saqib Razzaq

The common Laravel template structure

First, create a file that defines the structure of your page layout.blade.php @include('includes.header') @yield('content') @include('includes.footer') Then create files that yield content index.blade.php @extends('common_template') @section('content') {{$data['title']}} @endsection

October 17, 2021 · 1 min · 26 words · Saqib Razzaq

How to change windows wallpaper using Python3

Following code can be used for changing windows wallpaper import ctypes ctypes.windll.user32.SystemParametersInfoW(20, 0, image , 0)

October 11, 2021 · 1 min · 16 words · Saqib Razzaq

Python - search questions using wolframalpha

import json, requests def search(keyword): keyword = keyword.replace(' ', '+') data = requests.get('https://api.wolframalpha.com/v2/query?input=' + keyword + '&format=plaintext&output=json&appid=api_id_here') readable = data.json() results = readable['queryresult'] if results['success'] == True: for pod in results['pods']: if pod['title'] == 'Result': try: value = pod['subpods'][0]['plaintext'] return value except Exception as e: value = '' raise e else: print('Something went wrong. Below is full data') print(readable)

October 11, 2021 · 1 min · 59 words · Saqib Razzaq

Python + Scrapy: find element with text

response.xpath("//*[contains(text(), 'txt goes here')]").getall()

September 29, 2021 · 1 min · 4 words · Saqib Razzaq

How to update a request URL in Scrapy

Often times you might want to be able to manipulate every outgoing request. You don’t have to modify all points in your scrapper where you’re making requests. You can modify your middleware. Open middlewares.py in your project and paste following code in process_request method original_url = request.url new_url = 'modified_url_here' request = request.replace(url=new_url)

September 27, 2021 · 1 min · 53 words · Saqib Razzaq

Sublime Cheatsheet

Go to file Ctrl + P Toggle Sidebar Ctrl + K B Select line Ctrl + L Select word Ctrl + D Select content into brackets Ctrl + Shift + M Insert line before Ctrl + Shift + Enter Insert line after Ctrl + Enter Delete line Ctrl + Shift + K Duplicate lines Ctrl + Shift + D Join lines Ctrl + Shift + J Jump to matching bracket Ctrl + M ...

September 21, 2021 · 1 min · 73 words · Saqib Razzaq

Laravel - create a user by default

Sure, we can user Laravel’s database seeding and $faker to create any number of fake users. Personally, I don’t like to waste time fetching a new random user and their email address to continue my testing. I like have the same user created each time database is seeded. I do it like this. Run below command to create a new seeder in database/seeds directory. php artisan make:seeder UserSeeder In run method of UserSeeder.php paste following code $user = User::create([ 'name' => 'Saqib', 'email' => 'saqib@saqib.com', 'password' => Hash::make('password'), 'level' => 1 ]); Finally, add below line in run method in seeds\DatabaseSeeder.php $this->call(UserSeeder::class); ...

September 17, 2021 · 1 min · 125 words · Saqib Razzaq

Git Cheatsheet

Git Cheatsheet Get remote URL git remote -v Set remote URL git remote set-url origin git@bitbucket.org:user/repo.git Update remote branches list git remote update origin --prune Delete local branch git branch -d branchname Delete branch locally and remote git push origin --delete fix/authentication Create branch from another git checkout -b newbranch sourcebranch Soft reset (remove last commit) git reset --soft HEAD~1 Remove all local branches already merged into master (including dev) git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d

September 15, 2021 · 1 min · 84 words · Saqib Razzaq

Python - read txt file separated by line as list

In a web crawling project of mine I had to read proxies from a txt file. Each proxy was on a new line. I used following code to read them as list. proxies = [line.rstrip('\n') for line in open(directory + '/proxies_v2.txt')] Additionally, I shuffle them to make sure their order is random. random.shuffle(proxies)

September 11, 2021 · 1 min · 53 words · Saqib Razzaq

MySQL Cheatsheet

copy a table with schema, indexes and data First, copy the table with indexes CREATE TABLE new_name LIKE table_to_copy; Then copy the data by running INSERT INTO new_name SELECT * FROM table_to_copy; create BTREE Indexes CREATE INDEX index_name ON table_name (column1, column2, ...); create FULLTEXT indexes ALTER TABLE `TableName` ADD FULLTEXT INDEX `IndexName` (`ColumnName`); create new user and give all privilages CREATE USER 'user'@'localhost' IDENTIFIED BY 'password'; GRANT ALL PRIVILEGES ON * . * TO 'user'@'localhost'; create or drop multiple indexes in same query Create multiple indexes ...

September 1, 2021 · 2 min · 261 words · Saqib Razzaq

How to modify Laravel 'HOME' redirection path

When a user logs in, Laravel redirects it to path stored in HOME constant by default. If you want to modify this constant or add constants of your own, you can do it like this. Open app\Providers\RouteServiceProvider.php Search public const HOME to update HOME constant You can add your own just like that

August 19, 2021 · 1 min · 53 words · Saqib Razzaq

Laravel - common template structure

First, create a file that defines the structure of your page layout.blade.php @include('includes.header') @yield('content') @include('includes.footer') Then create files that yield content index.blade.php @extends('common_template') @section('content') {{$data['title']}} @endsection

August 19, 2021 · 1 min · 26 words · Saqib Razzaq

How to use proxies with Requests in Python

import requests proxy = 'proxy:goes:here' proxyDict = {"http" : proxy, "https" : proxy} response = requests.get('https://www.url.com', proxies=proxyDict) You can send the POST requests using a similar format. Headers can be added to the request using headers={}

July 29, 2021 · 1 min · 36 words · Saqib Razzaq