React Gin Blog (5/19): Adding user

We are making simple blog, so first thing we have to do is to implement some way for users to create account and log in. For now, we will just make simple struct User that will be stored in memory. Latter we will connect our application with a database so we can store our data there.

First let’s create new directory inside of internal/ which we will name store/. This package will implement logic for storing all our data. Until we connect our app to database, we will use simple slice for storing users. In internal/store/ directory, let’s create new file users.go:

package store

type User struct {
  Username string
  Password string
}

var Users []*User

Remove /hello test route from router.go file and add new routes /signup and /signin:

package server

import (
  "github.com/gin-gonic/gin"
)

func setRouter() *gin.Engine {
  // Creates default gin router with Logger and Recovery middleware already attached
  router := gin.Default()

  // Enables automatic redirection if the current route can't be matched but a
  // handler for the path with (without) the trailing slash exists.
  router.RedirectTrailingSlash = true

  // Create API route group
  api := router.Group("/api")
  {
    api.POST("/signup", signUp)
    api.POST("/signin", signIn)
  }

  router.NoRoute(func(ctx *gin.Context) { ctx.JSON(http.StatusNotFound, gin.H{}) })

  return router
}

Handlers signUp and signIn that we are passing to router will be implemented in internal/server/user.go file:

package server

import (
  "net/http"
  "rgb/internal/store"

  "github.com/gin-gonic/gin"
)

func signUp(ctx *gin.Context) {
  user := new(store.User)
  if err := ctx.Bind(user); err != nil {
    ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"err": err.Error()})
    return
  }
  store.Users = append(store.Users, user)
  ctx.JSON(http.StatusOK, gin.H{
    "msg": "Signed up successfully.",
    "jwt": "123456789",
  })
}

func signIn(ctx *gin.Context) {
  user := new(store.User)
  if err := ctx.Bind(user); err != nil {
    ctx.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"err": err.Error()})
    return
  }
  for _, u := range store.Users {
    if u.Username == user.Username && u.Password == user.Password {
      ctx.JSON(http.StatusOK, gin.H{
        "msg": "Signed in successfully.",
        "jwt": "123456789",
      })
      return
    }
  }
  ctx.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"err": "Sign in failed."})
}

Let’s analyze what this code does. We create new variable of type User where we will store data user provided through our frontend. After that we are calling method Bind() which will bind this form data to our User type variable. If this binding fails we immediately set error code and error message, and return from current function. If there were no errors, we will set response code to status OK and return JWT for authentication. For now we are returning only some dummy JWT so our frontend will work correctly, but latter we will change that with real JWT implementation. Now you can try to create new account, logout and login again. As you can see on pictures below, both routes are working.

SignUp API.
SignIn API.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: