github.com/clubpay/ronykit/kit@v0.14.4-0.20240515065620-d0dace45cbc7/README.MD (about) 1 [//]: # (<a href="https://github.com/clubpay/ronykit/actions/workflows/build-and-test.yml?query=branch%3Amain">) 2 3 [//]: # ( <img alt="Build Status" src="https://img.shields.io/github/workflow/status/clubpay/ronykit/build-and-test/main?style=for-the-badge">) 4 5 [//]: # (</a>) 6 <a href="https://goreportcard.com/report/github.com/clubpay/ronykit"> 7 <img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/clubpay/ronykit?style=for-the-badge"> 8 </a> 9 <a href="https://github.com/clubpay/ronykit/releases"> 10 <img alt="GitHub release (latest by date including pre-releases)" src="https://img.shields.io/github/v/release/clubpay/ronykit?include_prereleases&style=for-the-badge"> 11 </a> 12 <a href="https://codecov.io/gh/clubpay/ronykit/branch/main/"> 13 <img alt="Codecov Status" src="https://img.shields.io/codecov/c/github/clubpay/ronykit?style=for-the-badge"> 14 </a> 15 16 # Kit 17 18 RonyKit is a library written in Go (Golang), provides the abstraction layer for creating an API server. By defining separate 19 components for each task, you are almost free to develop your API server using RPC (Proto/JSON/...), REST, GraphQL or even with your 20 in-house defined protocol. However, some components are implemented in the 'std' which make it easy to use RonyKit out of the box. 21 In RonyKIT, I wanted to make it more flexible but still very performant. I will maintain two bundles one based on 22 [fasthttp](https://github.com/valyala/fasthttp) and the other provides only rpc over websocket based on two very fast 23 libraries [gobwas](https://github.com/gobwas/ws) and [gnet](https://github.com/panjf2000/gnet), however you are not limited to use those, 24 and 25 can build your own Bundles. To have a better understanding of how it is going to work please check examples folder. 26 in [simple-rest-server](../example/ex-02-rest) it shows a very simple hello world app. 27 in [mixed-jsonrpc-rest](../example/ex-01-rpc) it shows how you can write your services once but use them with multiple formats like 28 REST or RPC. 29 30 - [Installation](#installation) 31 - [Quick start](#quick-start) 32 - [Kit Components](#kit-components) 33 - [1. Handler](#1-handler) 34 - [2. Contract](#2-contract) 35 - [3. Service](#3-service) 36 - [4. Gateway](#4-gateway) 37 - [5. Cluster](#5-cluster) 38 - [6. EdgeServer](#6-edgeserver) 39 - [KIT Storage layers](#kit-storage-layers) 40 41 42 ## Installation 43 44 To install RonyKIT package, you need to install Go and set your Go workspace first. 45 46 First need to install[Go](https://golang.org/) (**version 1.17+ is required**), then you can use the below Go command to install 47 RonyKIT. 48 49 ```sh 50 $ go get -u github.com/clubpay/ronykit/kit/... 51 ``` 52 53 ## Quick start 54 55 You can find some sample codes in the [Examples](../example) folder. 56 57 ## Define Services and Contracts 58 59 In RonyKIT(Kit) you better to define the description of your services and their contracts using `desc` package, 60 and it provides you many helper methods. Although you can create your concrete implementations of kit.Service 61 and kit.Contract, but we strongly recommend you to use `desc` package. 62 63 When you develop a handler with Kit package you need to think about the input and output of your API, and define 64 these DTOs by defining appropriate structs. 65 66 For example, if you want to implement an `Echo` handler you can write your handler like this: 67 68 ```go 69 package main 70 71 import "github.com/clubpay/ronykit/kit" 72 73 type EchoRequest struct { 74 ID string `json:"Id"` 75 Timestamp int64 `json:"timestamp"` 76 } 77 78 type EchoResponse struct { 79 ID string `json:"Id"` 80 } 81 82 func echoHandler(ctx *kit.Context) { 83 req := ctx.In().GetMsg().(*EchoRequest) 84 85 ctx.In(). 86 Reply(). 87 SetMsg(&EchoResponse{ID: req.ID}). 88 Send() 89 } 90 ``` 91 92 Then you can write the service descriptor to define how your handler is going to be accessed from the Gateway of 93 your server. For example if you have an HTTP Gateway and you need your handler to be accessible using REST API, 94 you can define your service descriptor like this: 95 96 ```go 97 package main 98 99 import ( 100 "github.com/clubpay/ronykit/kit" 101 "github.com/clubpay/ronykit/kit/desc" 102 "github.com/clubpay/ronykit/std/gateways/fasthttp" 103 ) 104 105 106 func MyServiceDesc() *desc.Service { 107 return desc.NewService("MyServiceName"). 108 SetEncoding(kit.JSON). 109 AddContract( 110 desc.NewContract(). 111 SetInput(&EchoRequest{}). // This tells that we expect the incoming request resolves to EchoRequest struct 112 SetOutput(&EchoResponse{}). // This tells that we expect the outgoing response resolves to EchoResponse struct 113 AddSelector(fasthttp.GET("/echo/:Id")). // This tells that we want to use echoHandler for GET requests with /echo/:Id path 114 AddSelector(fasthttp.POST("/echo")). // This tells that we want to use echoHandler for POST requests with /echo path 115 SetHandler(echoHandler), // This tells that we want to use echoHandler as the handler of this contract 116 ) 117 } 118 ``` 119 120 In the ServiceDescriptor we defined two REST endpoints which our Handler would be served. 121 RonyKIT's EdgeServer tries its best to fill the input struct (i.e., EchoRequest) from the parameters: urlParam, queryParam or request's 122 body. 123 If you have a more complex case, you can also add your own custom decoder when you add your selector to the contract. 124 125 The last step is to set up our EdgeServer and bind our desired Gateway bundle and the `MyServiceDesc`. 126 The following code shows how we can do that: 127 128 ```go 129 package main 130 131 import ( 132 "github.com/clubpay/ronykit/kit" 133 "github.com/clubpay/ronykit/kit/desc" 134 "github.com/clubpay/ronykit/std/gateways/fasthttp" 135 ) 136 137 type EchoRequest struct { 138 ID string `json:"Id"` 139 Timestamp int64 `json:"timestamp"` 140 } 141 142 type EchoResponse struct { 143 ID string `json:"Id"` 144 } 145 146 func echoHandler(ctx *kit.Context) { 147 req := ctx.In().GetMsg().(*EchoRequest) 148 149 ctx.In(). 150 Reply(). 151 SetMsg(&EchoResponse{ID: req.ID}). 152 Send() 153 } 154 155 156 var MyServiceDesc desc.ServiceDescFunc = func() *desc.Service { 157 return desc.NewService("MyServiceName"). 158 SetEncoding(kit.JSON). 159 AddContract( 160 desc.NewContract(). 161 SetInput(&EchoRequest{}). 162 SetOutput(&EchoResponse{}). 163 AddSelector(fasthttp.GET("/echo/:Id")). 164 AddSelector(fasthttp.POST("/echo")). 165 SetHandler(echoHandler), 166 ) 167 } 168 169 func main() { 170 defer kit.NewServer( 171 kit.WithGateway( 172 fasthttp.MustNew( 173 fasthttp.Listen(":80"), 174 ), 175 ), 176 kit.WithServiceDesc(MyServiceDesc()), 177 ). 178 Start(context.TODO()). 179 PrintRoutes(os.Stdout). 180 Shutdown(context.TODO(), os.Kill, os.Interrupt) 181 } 182 ``` 183 184 --- 185 186 # KIT Components 187 188 ## 1. Handler 189 190 Handler is the function/method that accepts `kit.Context` as argument, and it will be called based on the 191 selector that is defined in the `desc.Service`. 192 193 ## 2. Contract 194 195 Contract defines a business use-case that is very similar to what a function does, just it will be triggered 196 based on the selectors that we define the ServiceDescriptor. 197 198 ## 3. Service 199 200 One or more Contracts that are doing some operations in a similar domain could be grouped in one Service. Each 201 EdgeServer can have one or more service attached. 202 203 ## 4. Gateway 204 205 Gateways handle the endpoints of the service. For example, if you need to provide REST apis you can use one of the 206 standard gateway bundles : fasthttp or silverhttp 207 For advanced cases you can develop your own Gateway, but it is not necessary for most cases. 208 209 ## 5. Cluster 210 211 Cluster defines the relation between different instances of the EdgeServer. This bundle is optional but if attached 212 to EdgeServer then in multi instance cases it can help and provides some facilities to share data between different 213 instances of your EdgeServer. 214 215 ## 6. EdgeServer 216 217 EdgeServer is the main component of the RonyKIT which glues different components together to make it a working 218 server. 219 220 --- 221 222 --- 223 224 --- 225 226 # KIT Storage layers 227 228 When we develop API server usually we need to store data with different lifecycles. Sometimes we need to store data 229 that lives between different handlers, in some cases, we need to keep the data between different requests of a connection. 230 (i.e. for websocket connection we want to keep some data for next request from this connection). 231 Basically in RonyKIT we provide 4 layers of storage: 232 233 | Layer | Lifecycle | 234 |------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 235 | Context | in the request, but available in all the handlers | 236 | Connection | in the connection, for REST apis usually the lifecycle of Connection storage and Context are same, but for websocket data will be available until websocket connection is active | 237 | Local | this is shared between different contracts, services and is in the local memory of the server | 238 | Cluster | this is shared between different instances of the EdgeServer. This is enabled ONLY if a Cluster bundle is attached | 239 240 --- 241 242