github.com/alimy/mir/v4@v4.1.0/README.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      一个很酷的开发RESTful API的辅助工具
    14    </p>
    15  </div>
    16  
    17  Mir 是一套提供类似gRPC服务开发体验的快速开发RESTful API后端开发脚手架,适配多种HTTP框架,包括 [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   ## 使用说明
    26  * 生成样板项目
    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接口定义:
    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      `mir:"-"`
   105  	Group      `mir:"v1"`
   106  	Login  func(Post, LoginReq) LoginResp `mir:"/login/"`
   107  	Logout func(Post)                     `mir:"/logout/"`
   108  }
   109  ```
   110  
   111  * 代码生成:
   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  // RegisterUserServant register User servant to gin
   163  func RegisterUserServant(e *gin.Engine, s User) {
   164  	router := e.Group("v1")
   165  	// use chain for router
   166  	middlewares := s.Chain()
   167  	router.Use(middlewares...)
   168  
   169  	// register routes info to router
   170  	router.Handle("POST", "/login/", func(c *gin.Context) {
   171  		select {
   172  		case <-c.Request.Context().Done():
   173  			return
   174  		default:
   175  		}
   176  		req := new(LoginReq)
   177  		if err := s.Bind(c, req); err != nil {
   178  			s.Render(c, nil, err)
   179  			return
   180  		}
   181  		resp, err := s.Login(req)
   182  		s.Render(c, resp, err)
   183  	})
   184  	router.Handle("POST", "/logout/", func(c *gin.Context) {
   185  		select {
   186  		case <-c.Request.Context().Done():
   187  			return
   188  		default:
   189  		}
   190  		
   191  		s.Render(c, nil, s.Logout(c))
   192  	})
   193  }
   194  
   195  func (UnimplementedUserServant) Chain() gin.HandlersChain {
   196  	return nil
   197  }
   198  
   199  func (UnimplementedUserServant) Login(c *gin.Context, req *LoginReq) (*LoginResp, mir.Error) {
   200  	return nil, mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
   201  }
   202  
   203  func (UnimplementedUserServant) Logout(c *gin.Context) mir.Error {
   204  	return mir.Errorln(http.StatusNotImplemented, http.StatusText(http.StatusNotImplemented))
   205  }
   206  
   207  func (UnimplementedUserServant) mustEmbedUnimplementedUserServant() {}
   208  ```
   209  
   210  * 接口实现:   
   211  ```go
   212  // file: servants/user.go
   213  
   214  package servants
   215  
   216  import (
   217  	"github.com/alimy/mir-example/v4/mirc/auto/api"
   218  	"github.com/alimy/mir/v4"
   219  	"github.com/gin-gonic/gin"
   220  )
   221  
   222  type baseSrv struct{}
   223  
   224  func (baseSrv) Bind(c *gin.Context, obj any) mir.Error {
   225  	if err := c.ShouldBind(obj); err != nil {
   226  		mir.NewError(http.StatusBadRequest, err)
   227  	}
   228  	return nil
   229  }
   230  
   231  func (baseSrv) Render(c *gin.Context, data any, err mir.Error) {
   232  	if err == nil {
   233  		c.JSON(http.StatusOK, data)
   234  	} else {
   235  		c.JSON(err.StatusCode(), err.Error())
   236  	}
   237  }
   238  
   239  type userSrv struct {
   240  	baseSrv
   241  
   242  	api.UnimplementedUserServant
   243  }
   244  
   245  func newUserSrv() api.Site {
   246  	return &userSrv{}
   247  }
   248  ```
   249  
   250  * 服务注册:  
   251  ```go
   252  // file: servants/servants.go
   253  
   254  package servants
   255  
   256  import (
   257  	"github.com/alimy/mir-example/v4/mirc/auto/api"
   258  	"github.com/gin-gonic/gin"
   259  )
   260  
   261  // RegisterServants register all the servants to gin.Engine
   262  func RegisterServants(e *gin.Engine) {
   263  	api.RegisterUserServant(e, newUserSrv())
   264  	
   265  	// TODO: some other servant to register
   266  }
   267  ```
   268  
   269  * 程序启动:
   270  ```go
   271  // file: main.go
   272  
   273  package main
   274  
   275  import (
   276  	"log"
   277  
   278  	"github.com/alimy/mir-example/v4/servants"
   279  	"github.com/gin-gonic/gin"
   280  )
   281  
   282  func main() {
   283  	e := gin.Default()
   284  
   285  	// register servants to gin
   286  	servants.RegisterServants(e)
   287  
   288  	// start servant service
   289  	if err := e.Run(); err != nil {
   290  		log.Fatal(err)
   291  	}
   292  }
   293  ```
   294  
   295  ### 使用[go-mir](https://github.com/alimy/mir)的项目
   296   * [examples](examples) - 本项目自带的demo,主要演示了如何使用[Mir](https://github.com/alimy/mir)快速进行RESTful API的后端开发。   
   297  * [paopao-ce](https://github.com/rocboss/paopao-ce/tree/dev) - 一个清新文艺的微社区,提供类似Twiter/微博的推文分享服务。