Adding user
Tags: go, gin
Published: 2021-06-24 17:01:24

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`:

```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`:

```go
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:

```go
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 route](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aincommull9rpoxkzmql.png)

![SignIn route](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cra5no3dclgs90b214an.png)