github.com/alimy/mir/v4@v4.1.0/README-en.md (about)

     1  [![Go](https://github.com/alimy/mir/actions/workflows/go.yml/badge.svg)](https://github.com/alimy/mir/actions/workflows/go.yml)
     2  [![GoDoc](https://godoc.org/github.com/alimy/mir?status.svg)](https://pkg.go.dev/github.com/alimy/mir/v4)
     3  [![Sourcegraph](https://img.shields.io/badge/view%20on-Sourcegraph-brightgreen.svg?logo=sourcegraph)](https://sourcegraph.com/github.com/alimy/mir)
     4  
     5  <div align="center">
     6    <a href="https://github.com/alimy/mir">
     7      <img src="https://alimy.me/mir/images/mir-logo.png" alt="Logo" width="240" height="240">
     8    </a>
     9  
    10    <h3 align="center">Mir</h3>
    11  
    12    <p align="center">
    13      A cool help tool to develop RESTful API.
    14    </p>
    15  </div>
    16  
    17  Mir is a toolkit to develop RESTful API backend service like develop service of gRPC. It adapt some HTTP framework sush as [Gin](https://github.com/gin-gonic/gin), [Chi](https://github.com/go-chi/chi), [Hertz](https://github.com/cloudwego/hertz), [Echo](https://github.com/labstack/echo), [Iris](https://github.com/kataras/iris), [Fiber](https://github.com/gofiber/fiber), [Macaron](https://github.com/go-macaron/macaron), [Mux](https://github.com/gorilla/mux), [httprouter](https://github.com/julienschmidt/httprouter)。  
    18  
    19  <div align="center">
    20    <a href="https://github.com/alimy/mir">
    21      <img src="https://alimy.me/mir/images/mir-arc.png">
    22    </a>
    23  </div>
    24   
    25   ### Tutorials
    26  * Generate a simple template project
    27  ```bash
    28  % go install github.com/alimy/mir/mirc/v4@latest
    29  % mirc new -h
    30  create template project
    31  
    32  Usage:
    33    mirc new [flags]
    34  
    35  Flags:
    36    -d, --dst string     genereted destination target directory (default ".")
    37    -h, --help           help for new
    38        --mir string     mir replace package name or place
    39    -p, --pkg string     project's package name (default "github.com/alimy/mir-example")
    40    -s, --style string   generated engine style eg: gin,chi,mux,hertz,echo,iris,fiber,fiber-v2,macaron,httprouter (default "gin")
    41  
    42  % mirc new -d example 
    43  % tree example
    44  example
    45  .
    46  |-- Makefile
    47  |-- README.md
    48  |-- go.mod
    49  |-- go.sum
    50  |-- main.go
    51  |-- mirc
    52  |   |-- auto
    53  |   |   `-- api
    54  |   |       |-- site.go
    55  |   |       |-- v1
    56  |   |       |   `-- site.go
    57  |   |       `-- v2
    58  |   |           `-- site.go
    59  |   |-- gen.go
    60  |   `-- routes
    61  |       |-- site.go
    62  |       |-- v1
    63  |       |   `-- site.go
    64  |       `-- v2
    65  |           `-- site.go
    66  `-- servants
    67      |-- core.go
    68      |-- servants.go
    69      |-- site.go
    70      |-- site_v1.go
    71      `-- site_v2.go
    72  
    73  % cd example
    74  % make generate
    75  % make run
    76  ```
    77   
    78  * RESTful API define:
    79  ```go
    80  // file: mirc/routes.go
    81  
    82  package routes
    83  
    84  import (
    85  	. "github.com/alimy/mir/v4"
    86  	. "github.com/alimy/mir/v4/engine"
    87  )
    88  
    89  func init() {
    90  	AddEntry(new(User))
    91  }
    92  
    93  type LoginReq struct {
    94  	Name   string `json:"name"`
    95  	Passwd string `json:"passwd"`
    96  }
    97  
    98  type LoginResp struct {
    99  	JwtToken string `json:"jwt_token"`
   100  }
   101  
   102  // User user interface info
   103  type User struct {
   104  	Chain  Chain                          `mir:"-"`
   105  	Group  Group                          `mir:"v1"`
   106  	Login  func(Post, LoginReq) LoginResp `mir:"/login/"`
   107  	Logout func(Post)                     `mir:"/logout/"`
   108  }
   109  ```
   110  
   111  * Stub source code generatee automatic:
   112  ```go
   113  // file: mirc/auto/api/routes.go
   114  
   115  // Code generated by go-mir. DO NOT EDIT.
   116  // versions:
   117  // - mir v4.0.0
   118  
   119  package routes
   120  
   121  import (
   122  	"net/http"
   123  
   124  	"github.com/alimy/mir/v4"
   125  	"github.com/gin-gonic/gin"
   126  )
   127  
   128  type _binding_ interface {
   129  	Bind(*gin.Context) mir.Error
   130  }
   131  
   132  type _render_ interface {
   133  	Render(*gin.Context)
   134  }
   135  
   136  type _default_ interface {
   137  	Bind(*gin.Context, any) mir.Error
   138  	Render(*gin.Context, any, mir.Error)
   139  }
   140  
   141  type LoginReq struct {
   142  	Name   string `json:"name"`
   143  	Passwd string `json:"passwd"`
   144  }
   145  
   146  type LoginResp struct {
   147  	JwtToken string `json:"jwt_token"`
   148  }
   149  
   150  type User interface {
   151  	_default_
   152  
   153  	// Chain provide handlers chain for gin
   154  	Chain() gin.HandlersChain
   155  
   156  	Login(*gin.Context, *LoginReq) (*LoginResp, mir.Error)
   157  	Logout(*gin.Context) mir.Error
   158  
   159  	mustEmbedUnimplementedUserServant()
   160  }
   161  
   162  // UnimplementedUserServant can be embedded to have forward compatible implementations.
   163  type UnimplementedUserServant struct {
   164  }
   165  
   166  // RegisterUserServant register User servant to gin
   167  func RegisterUserServant(e *gin.Engine, s User) {
   168  	router := e.Group("v1")
   169  	// use chain for router
   170  	middlewares := s.Chain()
   171  	router.Use(middlewares...)
   172  
   173  	// register routes info to router
   174  	router.Handle("POST", "/login/", func(c *gin.Context) {
   175  		select {
   176  		case <-c.Request.Context().Done():
   177  			return
   178  		default:
   179  		}
   180  		req := new(LoginReq)
   181  		if err := s.Bind(c, req); err != nil {
   182  			s.Render(c, nil, err)
   183  			return
   184  		}
   185  		resp, err := s.Login(req)
   186  		s.Render(c, resp, err)
   187  	})
   188  	router.Handle("POST", "/logout/", func(c *gin.Context) {
   189  		select {
   190  		case <-c.Request.Context().Done():
   191  			return
   192  		default:
   193  		}
   194  		
   195  		r.Render(c, nil, s.Logout(c))
   196  	})
   197  }
   198  
   199  func (UnimplementedUserServant) Chain() gin.HandlersChain {
   200  	return nil
   201  }
   202  
   203  func (UnimplementedUserServant) Login(c *gin.Context, req *LoginReq) (*LoginResp, mir.Error) {
   204  	return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
   205  }
   206  
   207  func (UnimplementedUserServant) Logout(c *gin.Context) mir.Error {
   208  	return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
   209  }
   210  
   211  func (UnimplementedUserServant) mustEmbedUnimplementedUserServant() {}
   212  ```
   213  
   214  * API interface implement:   
   215  ```go
   216  // file: servants/user.go
   217  
   218  package servants
   219  
   220  import (
   221  	"github.com/alimy/mir-example/v4/mirc/auto/api"
   222  	"github.com/alimy/mir/v4"
   223  	"github.com/gin-gonic/gin"
   224  )
   225  
   226  type baseSrv struct{}
   227  
   228  func (baseSrv) Bind(c *gin.Context, obj any) mir.Error {
   229  	if err := c.ShouldBind(obj); err != nil {
   230  		mir.NewError(http.StatusBadRequest, err)
   231  	}
   232  	return nil
   233  }
   234  
   235  func (baseSrv) Render(c *gin.Context, data any, err mir.Error) {
   236  	if err == nil {
   237  		c.JSON(http.StatusOK, data)
   238  	} else {
   239  		c.JSON(err.StatusCode(), err.Error())
   240  	}
   241  }
   242  
   243  type userSrv struct {
   244  	baseSrv
   245  
   246  	api.UnimplementedUserServant
   247  }
   248  
   249  func newUserSrv() api.Site {
   250  	return &userSrv{}
   251  }
   252  ```
   253  
   254  * Service register:  
   255  ```go
   256  // file: servants/servants.go
   257  
   258  package servants
   259  
   260  import (
   261  	"github.com/alimy/mir-example/v4/mirc/auto/api"
   262  	"github.com/gin-gonic/gin"
   263  )
   264  
   265  // RegisterServants register all the servants to gin.Engine
   266  func RegisterServants(e *gin.Engine) {
   267  	api.RegisterUserServant(e, newUserSrv())
   268  	
   269  	// TODO: some other servant to register
   270  }
   271  ```
   272  
   273  * App start:
   274  ```go
   275  // file: main.go
   276  
   277  package main
   278  
   279  import (
   280  	"log"
   281  
   282  	"github.com/alimy/mir-example/v4/servants"
   283  	"github.com/gin-gonic/gin"
   284  )
   285  
   286  func main() {
   287  	e := gin.Default()
   288  
   289  	// register servants to gin
   290  	servants.RegisterServants(e)
   291  
   292  	// start servant service
   293  	if err := e.Run(); err != nil {
   294  		log.Fatal(err)
   295  	}
   296  }
   297  ```
   298  
   299  ### Projects that used [go-mir](https://github.com/alimy/mir) 
   300   * [examples](examples) - a demo example to describe how to use [Mir](https://github.com/alimy/mir) to develop RESTful API backend service quickly.
   301  * [paopao-ce](https://github.com/rocboss/paopao-ce/tree/dev) - A artistic "twitter like" community built on gin+zinc+vue+ts.