mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 10:41:03 +01:00
update some contents for the upcoming release (ebook too)
parent
388df26430
commit
6ad0e5ab5b
|
@ -54,7 +54,7 @@ myMiddleware := func(ctx iris.Context) {
|
|||
}
|
||||
|
||||
myCustomNotVersionFound := func(ctx iris.Context) {
|
||||
ctx.StatusCode(404)
|
||||
ctx.StatusCode(iris.StatusNotFound)
|
||||
ctx.Writef("%s version not found", versioning.GetVersion(ctx))
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ Follow the steps below to, temporarily, convert your local Iris web server to a
|
|||
2. Simply pass the `WithTunneling` configurator in your `app.Run`,
|
||||
3. You are ready to [GO](https://www.facebook.com/iris.framework/photos/a.2420499271295384/3261189020559734/?type=3&theater)!
|
||||
|
||||
[![tunneling_screenshot](https://user-images.githubusercontent.com/22900943/61413905-50596300-a8f5-11e9-8be0-7e806846d52f.png)](https://www.facebook.com/iris.framework/photos/a.2420499271295384/3261189020559734/?type=3&theater)
|
||||
![tunneling_screenshot](https://user-images.githubusercontent.com/22900943/81442996-42731800-917d-11ea-90da-7d6475a6b365.png)
|
||||
|
||||
- `ctx.Application().ConfigurationReadOnly().GetVHost()` returns the public domain value. Rarely useful but it's there for you. Most of the times you use relative url paths instead of absolute(or you should to).
|
||||
- It doesn't matter if ngrok is already running or not, Iris framework is smart enough to use ngrok's [web API](https://ngrok.com/docs) to create a tunnel.
|
||||
|
|
2
Cache.md
2
Cache.md
|
@ -84,4 +84,4 @@ similar to the `HandleDir`(which sends status OK(200) and browser disk caching i
|
|||
func Cache304(expiresEvery time.Duration) Handler
|
||||
```
|
||||
|
||||
Examples can be found at: <https://github.com/kataras/iris/tree/master/_examples/cache>.
|
||||
Examples can be found at: <https://github.com/kataras/iris/tree/master/_examples/response-writer/cache>.
|
||||
|
|
200
Configuration.md
200
Configuration.md
|
@ -2,17 +2,15 @@ At the [[previous|Host]] section we've learnt about the first input argument of
|
|||
|
||||
Let's start from basics. The `iris.New` function returns an `iris.Application`. This Application value can be configured through its `Configure(...iris.Configurator)` and `Run` methods.
|
||||
|
||||
The second optional, varadiac argument of `app.Run` method accepts one or more `iris.Configurator`. An `iris.Configurator` is just a type of: `func(app *iris.Application)`. Custom `iris.Configurator` can be passed to modify yours `*iris.Application` as well.
|
||||
The second optional, varadiac argument of `app.Run/Listen` method accepts one or more `iris.Configurator`. An `iris.Configurator` is just a type of: `func(app *iris.Application)`. Custom `iris.Configurator` can be passed to modify yours `*iris.Application` as well.
|
||||
|
||||
There are built-in`iris.Configurator`s for each of the core [Configuration](https://godoc.org/github.com/kataras/iris#Configuration)'s fields, such as `iris.WithoutStartupLog`, `iris.WithCharset("UTF-8")`, `iris.WithOptimizations` and `iris.WithConfiguration(iris.Configuration{...})` functions.
|
||||
|
||||
Each “module” like the iris view engine, websockets, sessions and each middleware has its own configurations and options, most of them, separately from the core configuration.
|
||||
Each "module" like the iris view engine, websockets, sessions and each middleware has its own configurations and options.
|
||||
|
||||
## Using the [Configuration](https://godoc.org/github.com/kataras/iris#Configuration)
|
||||
|
||||
The only one configuration structure is the `iris.Configuration`. Let's start by that one which can be passed on the `iris.WithConfiguration` function to make it an `iris.Configurator`.
|
||||
|
||||
All of the `iris.Configuration` fields are defaulted to the most common use cases. Iris doesn’t need any configuration before its `app.Run` but if you want to make use of a custom `iris.Configurator` before the server runs then you can use the `app.Configure` method to pass the configurator(s) there.
|
||||
All of the `iris.Configuration` fields are defaulted to the most common use cases. If you want to make use of a custom `iris.Configurator` at any point call the `app.Configure(accepts iris.Configurator)` method to pass your configurator(s) there.
|
||||
|
||||
```go
|
||||
config := iris.WithConfiguration(iris.Configuration {
|
||||
|
@ -70,13 +68,14 @@ app.Listen(":8080", config)
|
|||
|
||||
## Using the functional way
|
||||
|
||||
As we already mention, you can pass any number of `iris.Configurator` in the `app.Run`’s second argument. Iris provides an option for each of its `iris.Configuration`’s fields.
|
||||
As we already mention, you can pass any number of `iris.Configurator` in the `app.Run/Listen`’s second argument. Iris provides an option for each of its `iris.Configuration`’s fields.
|
||||
|
||||
```go
|
||||
app.Listen(":8080", iris.WithoutInterruptHandler,
|
||||
iris.WithoutServerError(iris.ErrServerClosed),
|
||||
iris.WithoutBodyConsumptionOnUnmarshal,
|
||||
iris.WithoutAutoFireStatusCode,
|
||||
iris.WithLowercaseRouting,
|
||||
iris.WithPathIntelligence,
|
||||
iris.WithOptimizations,
|
||||
iris.WithTimeFormat("Mon, 01 Jan 2006 15:04:05 GMT"),
|
||||
)
|
||||
|
@ -86,9 +85,181 @@ Good when you want to change some of the configuration's field.
|
|||
Prefix: "With" or "Without", code editors will help you navigate through all
|
||||
configuration options without even a glitch to the documentation.
|
||||
|
||||
List of functional options:
|
||||
|
||||
```go
|
||||
// WithGlobalConfiguration will load the global yaml configuration file
|
||||
// from the home directory and it will set/override the whole app's configuration
|
||||
// to that file's contents. The global configuration file can be modified by user
|
||||
// and be used by multiple iris instances.
|
||||
//
|
||||
// This is useful when we run multiple iris servers that share the same
|
||||
// configuration, even with custom values at its "Other" field.
|
||||
//
|
||||
// Usage: `app.Configure(iris.WithGlobalConfiguration)` or `app.Run([iris.Runner], iris.WithGlobalConfiguration)`.
|
||||
var WithGlobalConfiguration Configurator
|
||||
|
||||
// WithLogLevel sets the `Configuration.LogLevel` field.
|
||||
func WithLogLevel(level string) Configurator
|
||||
|
||||
// WithoutServerError will cause to ignore the matched "errors"
|
||||
// from the main application's `Run/Listen` function.
|
||||
//
|
||||
// Usage:
|
||||
// err := app.Listen(":8080", iris.WithoutServerError(iris.ErrServerClosed))
|
||||
// will return `nil` if the server's error was `http/iris#ErrServerClosed`.
|
||||
//
|
||||
// See `Configuration#IgnoreServerErrors []string` too.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/tree/master/_examples/http-server/listen-addr/omit-server-errors
|
||||
func WithoutServerError(errors ...error)Configurator
|
||||
|
||||
// WithoutStartupLog turns off the information send, once, to the terminal when the main server is open.
|
||||
var WithoutStartupLog Configurator
|
||||
|
||||
// WithoutBanner is a conversion for the `WithoutStartupLog` option.
|
||||
//
|
||||
// Turns off the information send, once, to the terminal when the main server is open.
|
||||
var WithoutBanner = WithoutStartupLog
|
||||
|
||||
// WithoutInterruptHandler disables the automatic graceful server shutdown
|
||||
// when control/cmd+C pressed.
|
||||
var WithoutInterruptHandler Configurator
|
||||
|
||||
// WithoutPathCorrection disables the PathCorrection setting.
|
||||
//
|
||||
// See `Configuration`.
|
||||
var WithoutPathCorrection Configurator
|
||||
|
||||
// WithPathIntelligence enables the EnablePathIntelligence setting.
|
||||
//
|
||||
// See `Configuration`.
|
||||
var WithPathIntelligence Configurator
|
||||
|
||||
// WithoutPathCorrectionRedirection disables the PathCorrectionRedirection setting.
|
||||
//
|
||||
// See `Configuration`.
|
||||
var WithoutPathCorrectionRedirection Configurator
|
||||
|
||||
// WithoutBodyConsumptionOnUnmarshal disables BodyConsumptionOnUnmarshal setting.
|
||||
//
|
||||
// See `Configuration`.
|
||||
var WithoutBodyConsumptionOnUnmarshal Configurator
|
||||
|
||||
// WithEmptyFormError enables the setting `FireEmptyFormError`.
|
||||
//
|
||||
// See `Configuration`.
|
||||
var WithEmptyFormError Configurator
|
||||
|
||||
// WithoutAutoFireStatusCode disables the AutoFireStatusCode setting.
|
||||
//
|
||||
// See `Configuration`.
|
||||
var WithoutAutoFireStatusCode Configurator
|
||||
|
||||
// WithPathEscape sets the EnablePathEscape setting to true.
|
||||
//
|
||||
// See `Configuration`.
|
||||
var WithPathEscape Configurator
|
||||
|
||||
// WithLowercaseRouting enables for lowercase routing by
|
||||
// setting the `ForceLowercaseRoutes` to true.
|
||||
//
|
||||
// See `Configuration`.
|
||||
var WithLowercaseRouting Configurator
|
||||
|
||||
// WithOptimizations can force the application to optimize for the best performance where is possible.
|
||||
//
|
||||
// See `Configuration`.
|
||||
var WithOptimizations Configurator
|
||||
|
||||
// WithFireMethodNotAllowed enables the FireMethodNotAllowed setting.
|
||||
//
|
||||
// See `Configuration`.
|
||||
func WithFireMethodNotAllowed Configurator
|
||||
|
||||
// WithTimeFormat sets the TimeFormat setting.
|
||||
//
|
||||
// See `Configuration`.
|
||||
func WithTimeFormat(timeformat string) Configurator
|
||||
|
||||
// WithCharset sets the Charset setting.
|
||||
//
|
||||
// See `Configuration`.
|
||||
func WithCharset(charset string) Configurator
|
||||
|
||||
// WithPostMaxMemory sets the maximum post data size
|
||||
// that a client can send to the server, this differs
|
||||
// from the overral request body size which can be modified
|
||||
// by the `context#SetMaxRequestBodySize` or `iris#LimitRequestBodySize`.
|
||||
//
|
||||
// Defaults to 32MB or 32 << 20 or 32*iris.MB if you prefer.
|
||||
func WithPostMaxMemory(limit int64) Configurator
|
||||
|
||||
// WithRemoteAddrHeader enables or adds a new or existing request header name
|
||||
// that can be used to validate the client's real IP.
|
||||
//
|
||||
// By-default no "X-" header is consired safe to be used for retrieving the
|
||||
// client's IP address, because those headers can manually change by
|
||||
// the client. But sometimes are useful e.g., when behind a proxy
|
||||
// you want to enable the "X-Forwarded-For" or when cloudflare
|
||||
// you want to enable the "CF-Connecting-IP", inneed you
|
||||
// can allow the `ctx.RemoteAddr()` to use any header
|
||||
// that the client may sent.
|
||||
//
|
||||
// Defaults to an empty map but an example usage is:
|
||||
// WithRemoteAddrHeader("X-Forwarded-For")
|
||||
//
|
||||
// Look `context.RemoteAddr()` for more.
|
||||
func WithRemoteAddrHeader(headerName string) Configurator
|
||||
|
||||
// WithoutRemoteAddrHeader disables an existing request header name
|
||||
// that can be used to validate and parse the client's real IP.
|
||||
//
|
||||
//
|
||||
// Keep note that RemoteAddrHeaders is already defaults to an empty map
|
||||
// so you don't have to call this Configurator if you didn't
|
||||
// add allowed headers via configuration or via `WithRemoteAddrHeader` before.
|
||||
//
|
||||
// Look `context.RemoteAddr()` for more.
|
||||
func WithoutRemoteAddrHeader(headerName string) Configurator
|
||||
|
||||
// WithRemoteAddrPrivateSubnet adds a new private sub-net to be excluded from `context.RemoteAddr`.
|
||||
// See `WithRemoteAddrHeader` too.
|
||||
func WithRemoteAddrPrivateSubnet(startIP, endIP string) Configurator
|
||||
|
||||
// WithOtherValue adds a value based on a key to the Other setting.
|
||||
//
|
||||
// See `Configuration.Other`.
|
||||
func WithOtherValue(key string, val interface{}) Configurator
|
||||
|
||||
// WithSitemap enables the sitemap generator.
|
||||
// Use the Route's `SetLastMod`, `SetChangeFreq` and `SetPriority` to modify
|
||||
// the sitemap's URL child element properties.
|
||||
//
|
||||
// It accepts a "startURL" input argument which
|
||||
// is the prefix for the registered routes that will be included in the sitemap.
|
||||
//
|
||||
// If more than 50,000 static routes are registered then sitemaps will be splitted and a sitemap index will be served in
|
||||
// /sitemap.xml.
|
||||
//
|
||||
// If `Application.I18n.Load/LoadAssets` is called then the sitemap will contain translated links for each static route.
|
||||
//
|
||||
// If the result does not complete your needs you can take control
|
||||
// and use the github.com/kataras/sitemap package to generate a customized one instead.
|
||||
//
|
||||
// Example: https://github.com/kataras/iris/tree/master/_examples/sitemap.
|
||||
func WithSitemap(startURL string) Configurator
|
||||
|
||||
// WithTunneling is the `iris.Configurator` for the `iris.Configuration.Tunneling` field.
|
||||
// It's used to enable http tunneling for an Iris Application, per registered host
|
||||
//
|
||||
// Alternatively use the `iris.WithConfiguration(iris.Configuration{Tunneling: iris.TunnelingConfiguration{ ...}}}`.
|
||||
var WithTunneling Configuartor
|
||||
```
|
||||
|
||||
## Custom values
|
||||
|
||||
The `iris.Configuration` contains a field called `Other map[string]interface{}` which accepts any custom `key:value` option, therefore you can use that field to pass specific values that your app expects based on the custom requirements.
|
||||
The `iris.Configuration` contains a field named `Other map[string]interface{}` which accepts any custom `key:value` option, therefore you can use that field to pass specific values that your app expects based on the custom requirements.
|
||||
|
||||
```go
|
||||
app.Listen(":8080",
|
||||
|
@ -99,15 +270,12 @@ app.Listen(":8080",
|
|||
|
||||
You can access those fields via `app.ConfigurationReadOnly`.
|
||||
|
||||
```go
|
||||
serverName := app.ConfigurationReadOnly().Other["MyServerName"]
|
||||
serverOwner := app.ConfigurationReadOnly().Other["ServerOwner"]
|
||||
```
|
||||
|
||||
## Access Configuration from Context
|
||||
|
||||
Inside a handler, retrieve those fields using the following:
|
||||
|
||||
```go
|
||||
ctx.Application().ConfigurationReadOnly()
|
||||
func (ctx iris.Context) {
|
||||
cfg := app.Application().ConfigurationReadOnly().GetOther()
|
||||
srvName := cfg["MyServerName"]
|
||||
srvOwner := cfg["ServerOwner"]
|
||||
}
|
||||
```
|
||||
|
|
|
@ -75,8 +75,7 @@ app.Get("/resource2", func(ctx iris.Context) {
|
|||
})
|
||||
```
|
||||
|
||||
[Read the full example](https://github.com/kataras/iris/blob/8ee0de51c593fe0483fbea38117c3c88e065f2ef/_examples/http_responsewriter/content-negotiation/main.go#L22).
|
||||
|
||||
[Read the full example](https://github.com/kataras/iris/blob/master/_examples/response-writer/content-negotiation/main.go#L22).
|
||||
|
||||
## Documentation
|
||||
|
||||
|
|
|
@ -4,9 +4,11 @@ However the Iris `Context` provides some helpers to make the most common use cas
|
|||
|
||||
## Set a Cookie
|
||||
|
||||
The `SetCookie` method adds a cookie.
|
||||
The `SetCookie` and `UpsertCookie` methods add or set (replaces if necessary) a cookie.
|
||||
|
||||
Use of the "options" is not required, they can be used to modify the "cookie". You'll see later on what the available options are, custom ones can be added depending on your web application requirements, this also helps to not repeat yourself in a codebase.
|
||||
The last argument of "options" is optional. a `CookieOption` can be used to modify the "cookie". You'll see later on what the available options are, custom ones can be added depending on your web application requirements, this also helps to not repeat yourself in a codebase.
|
||||
|
||||
Before we continue, the `Context` has a `SetSameSite(http.SameSite)` method too. It sets the ["SameSite"](https://web.dev/samesite-cookies-explained/) cookie field for all cookies to be sent.
|
||||
|
||||
```go
|
||||
SetCookie(cookie *http.Cookie, options ...CookieOption)
|
||||
|
|
2
Forms.md
2
Forms.md
|
@ -212,4 +212,4 @@ curl -X POST http://localhost:8080/upload \
|
|||
-H "Content-Type: multipart/form-data"
|
||||
```
|
||||
|
||||
More examples can be found at <https://github.com/kataras/iris/tree/master/_examples/http_request>.
|
||||
More examples can be found at <https://github.com/kataras/iris/tree/master/_examples/request-body> and <https://github.com/kataras/iris/tree/master/_examples/file-server>.
|
142
Grpc.md
Normal file
142
Grpc.md
Normal file
|
@ -0,0 +1,142 @@
|
|||
gRPC[*](https://grpc.io/) is a modern open source high performance Remote Procedure Call framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. It is also applicable in last mile of distributed computing to connect devices, mobile applications and browsers to backend services.
|
||||
|
||||
## gRPC
|
||||
|
||||
Iris and gRPC integration lives inside the [mvc](https://github.com/kataras/iris/tree/master/mvc) package.
|
||||
|
||||
Have you ever have difficulties converting your app or parts of it from HTTP to gGRPC or did you ever wish you had decent HTTP framework support as well for your gRPC services? Now, with Iris you have the best of two worlds. Without change a bit of your existing gRPC services code, you can register them as Iris HTTP routes through a Controller (your service struct value).
|
||||
|
||||
[[_assets/grpc-compatible-question.png]]
|
||||
> Learn more about our conversation at: https://github.com/kataras/iris/issues/1449#issuecomment-623260695
|
||||
|
||||
|
||||
## Step by step
|
||||
|
||||
We will follow the [official helloworld gRPC example](https://github.com/grpc/grpc-go/tree/master/examples/helloworld). If you had already work with gRPC services you can skip 1-5.
|
||||
|
||||
**1.** Let's write our proto schema for request and response.
|
||||
|
||||
```protobuf
|
||||
syntax = "proto3";
|
||||
|
||||
package helloworld;
|
||||
|
||||
// The greeting service definition.
|
||||
service Greeter {
|
||||
// Sends a greeting
|
||||
rpc SayHello (HelloRequest) returns (HelloReply) {}
|
||||
}
|
||||
|
||||
// The request message containing the user's name.
|
||||
message HelloRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
// The response message containing the greetings
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
||||
```
|
||||
|
||||
**2.** Install the protoc Go plugin
|
||||
|
||||
```sh
|
||||
$ go get -u github.com/golang/protobuf/protoc-gen-go
|
||||
```
|
||||
|
||||
**3.** Generate Go file from the helloworld.proto file above
|
||||
|
||||
```sh
|
||||
$ protoc -I helloworld/ helloworld/helloworld.proto --go_out=plugins=grpc:helloworld
|
||||
```
|
||||
|
||||
**4.** Implement a gRPC service as usually, with or without Iris
|
||||
|
||||
```go
|
||||
import (
|
||||
// [...]
|
||||
pb "myapp/helloworld"
|
||||
"context"
|
||||
)
|
||||
```
|
||||
|
||||
```go
|
||||
type Greeter struct { }
|
||||
|
||||
// SayHello implements helloworld.GreeterServer.
|
||||
func (c *Greeter) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
|
||||
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
|
||||
}
|
||||
```
|
||||
|
||||
Iris automatically binds the standard "context" `context.Context` to `iris.Context.Request().Context()`
|
||||
and any other structure that is not mapping to a registered dependency
|
||||
as a payload (depending on the request), e.g XML, YAML, Query, Form, JSON, Protobuf.
|
||||
|
||||
**5.** Register your service to the gRPC server
|
||||
|
||||
```go
|
||||
import (
|
||||
// [...]
|
||||
pb "myapp/helloworld"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
```
|
||||
|
||||
```go
|
||||
grpcServer := grpc.NewServer()
|
||||
|
||||
myService := &Greeter{}
|
||||
pb.RegisterGreeterServer(grpcServer, myService)
|
||||
```
|
||||
|
||||
**6.** Register this `myService` to Iris
|
||||
|
||||
The `mvc.New(party).Handle(ctrl, mvc.GRPC{...})` option allows to register gRPC services per-party (without the requirement of a full wrapper) and optionally strict access to gRPC-only clients.
|
||||
|
||||
Register MVC application controller for gRPC services.
|
||||
You can bind as many mvc gRpc services in the same Party or app,
|
||||
as the `ServiceName` differs.
|
||||
|
||||
```go
|
||||
import (
|
||||
// [...]
|
||||
"github.com/kataras/iris/v12"
|
||||
"github.com/kataras/iris/v12/mvc"
|
||||
)
|
||||
```
|
||||
|
||||
```go
|
||||
app := iris.New()
|
||||
|
||||
rootApp := mvc.New(app)
|
||||
rootApp.Handle(myService, mvc.GRPC{
|
||||
Server: grpcServer, // Required.
|
||||
ServiceName: "helloworld.Greeter", // Required.
|
||||
Strict: false,
|
||||
})
|
||||
```
|
||||
|
||||
**7.** Generate TLS Keys
|
||||
|
||||
The Iris server **should ran under TLS** (it's a gRPC requirement).
|
||||
|
||||
```sh
|
||||
$ openssl genrsa -out server.key 2048
|
||||
$ openssl req -new -x509 -sha256 -key server.key -out server.crt -days 3650
|
||||
```
|
||||
|
||||
**8.** Listen and Serve
|
||||
|
||||
```go
|
||||
app.Run(iris.TLS(":443", "server.crt", "server.key"))
|
||||
```
|
||||
|
||||
POST: `https://localhost:443/helloworld.Greeter/SayHello` with request data: `{"name": "John"}`
|
||||
xpected output: `{"message": "Hello John"}`.
|
||||
|
||||
Both HTTP Client and gRPC client will be able to communicate with our Iris+gRPC service.
|
||||
|
||||
### Exercise files
|
||||
|
||||
Full Server, Clients and Testing Code can be found at: <https://github.com/kataras/iris/tree/master/_examples/mvc/grpc-compatible>.
|
1
Home.md
1
Home.md
|
@ -40,6 +40,7 @@ This wiki is the main source of documentation for **developers** working with (o
|
|||
* [[Websockets]]
|
||||
* [[Dependency Injection|Dependency-Injection]]
|
||||
* [[MVC]]
|
||||
* [[gRPC]]
|
||||
* [[Sitemap]]
|
||||
* [[Localization]]
|
||||
* [[Testing]]
|
||||
|
|
28
Host.md
28
Host.md
|
@ -8,20 +8,30 @@ by passing a network address with form of "hostname:ip". With Iris
|
|||
we use the `iris.Addr` which is an `iris.Runner` type
|
||||
|
||||
```go
|
||||
import "github.com/kataras/iris/v12"
|
||||
```
|
||||
|
||||
```go
|
||||
app := iris.New()
|
||||
// Listening on tcp with network address 0.0.0.0:8080.
|
||||
//
|
||||
// Listen is a shortcut for app.Run(iris.Addr(":8080")).
|
||||
app.Listen(":8080")
|
||||
```
|
||||
|
||||
Sometimes you have created a standard net/http server somewhere else in your app and want to use that to serve the Iris web app
|
||||
Sometimes you choose to have full control over the `http.Server` instance.
|
||||
|
||||
```go
|
||||
import "net/http"
|
||||
```
|
||||
|
||||
```go
|
||||
// Same as before but using a custom http.Server which may being used somewhere else too
|
||||
app.Run(iris.Server(&http.Server{Addr:":8080"}))
|
||||
server := &http.Server{Addr:":8080" /* other fields here */}
|
||||
app.Run(iris.Server(server))
|
||||
```
|
||||
|
||||
The most advanced usage is to create a custom or a standard `net.Listener` and pass that to `app.Run`
|
||||
The most advanced usage is to create a custom `net.Listener` and pass that to `app.Run`.
|
||||
|
||||
```go
|
||||
// Using a custom net.Listener
|
||||
|
@ -32,7 +42,7 @@ if err != nil {
|
|||
app.Run(iris.Listener(l))
|
||||
```
|
||||
|
||||
A more complete example, using the unix-only socket files feature
|
||||
A more complete example, using the unix-only socket files feature.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
@ -66,7 +76,7 @@ func main() {
|
|||
}
|
||||
```
|
||||
|
||||
UNIX and BSD hosts can take advandage of the reuse port feature
|
||||
UNIX and BSD hosts can take advandage of the reuse port feature.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
@ -115,17 +125,17 @@ func main() {
|
|||
|
||||
### HTTP/2 and Secure
|
||||
|
||||
If you have signed file keys you can use the `iris.TLS` to serve `https` based on those certification keys
|
||||
If you have local certification and server key files you can use the `iris.TLS` to serve `https://`.
|
||||
|
||||
```go
|
||||
// TLS using files
|
||||
// TLS using files or raw contents.
|
||||
app.Run(iris.TLS("127.0.0.1:443", "mycert.cert", "mykey.key"))
|
||||
```
|
||||
|
||||
The method you should use when your app is ready for **production** is the `iris.AutoTLS` which starts a secure server with automated certifications provided by https://letsencrypt.org for **free**
|
||||
The method you should use when your app is ready for the outside world is the `iris.AutoTLS` which starts a secure server with certifications provided by https://letsencrypt.org for **free**.
|
||||
|
||||
```go
|
||||
// Automatic TLS
|
||||
// Automatic TLS.
|
||||
app.Run(iris.AutoTLS(":443", "example.com", "admin@example.com"))
|
||||
```
|
||||
|
||||
|
|
16
MVC.md
16
MVC.md
|
@ -16,6 +16,8 @@ with the fastest possible execution.
|
|||
|
||||
If you're new to back-end web development read about the MVC architectural pattern first, a good start is that [wikipedia article](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller).
|
||||
|
||||
**Note:** Read the [[Dependency Injection]] section before continue.
|
||||
|
||||
**Characteristics**
|
||||
|
||||
All HTTP Methods are supported, for example if want to serve `GET`
|
||||
|
@ -88,8 +90,7 @@ useful to call middlewares or when many methods use the same collection of data.
|
|||
|
||||
Optional `EndRequest(ctx)` function to perform any finalization after any method executed.
|
||||
|
||||
Inheritance, recursively, e.g. our [mvc session-controller example](https://github.com/kataras/iris/tree/master/_examples/mvc/session-controller), has the `Session *sessions.Session` as struct field which is filled by the sessions manager's `Start` as a dynamic dependency to the MVC Application:
|
||||
`mvcApp.Register(sessions.New(sessions.Config{Cookie: "iris_session_id"}).Start)`.
|
||||
Inheritance, recursively, e.g. our [mvc session-controller example](https://github.com/kataras/iris/tree/master/_examples/mvc/session-controller), has the `Session *sessions.Session` as struct field which is filled by the sessions manager.
|
||||
|
||||
Access to the dynamic path parameters via the controller's methods' input arguments, no binding is needed.
|
||||
When you use the Iris' default syntax to parse handlers from a controller, you need to suffix the methods
|
||||
|
@ -135,7 +136,7 @@ func(c *ExampleController) Get() string |
|
|||
mvc.Result or (mvc.Result, error)
|
||||
```
|
||||
|
||||
Where `mvc.Result` is a `hero.Result` type alias, which is this interface one:
|
||||
Where `mvc.Result` is just a type alias of `hero.Result`:
|
||||
|
||||
```go
|
||||
type Result interface {
|
||||
|
@ -146,8 +147,7 @@ type Result interface {
|
|||
|
||||
## Example
|
||||
|
||||
This example is equivalent to the
|
||||
https://github.com/kataras/iris/blob/master/_examples/hello-world/main.go
|
||||
This example is equivalent to a simple hello world application.
|
||||
|
||||
It seems that additional code you have to write doesn't worth it but remember that, this example
|
||||
does not make use of iris mvc features like
|
||||
|
@ -164,7 +164,7 @@ but you can choose
|
|||
what suits you best with Iris, low-level handlers: performance
|
||||
or high-level controllers: easier to maintain and smaller codebase on large applications.
|
||||
|
||||
**Read the comments very careful**
|
||||
**Read the comments carefully**
|
||||
|
||||
```go
|
||||
package main
|
||||
|
@ -312,6 +312,8 @@ The first comment states this is an [HTTP GET](https://www.w3schools.com/tags/re
|
|||
|
||||
Controller knows how to handle the "name" on `GetBy` or the "name" and "numTimes" at `GetWelcomeBy`, because of the `By` keyword, and builds the dynamic route without boilerplate; the third comment specifies an [HTTP GET](https://www.w3schools.com/tags/ref_httpmethods.asp) dynamic method that is invoked by any URL that starts with "/helloworld/welcome" and followed by two more path parts, the first one can accept any value and the second can accept only numbers, i,e: "http://localhost:8080/helloworld/welcome/golang/32719", otherwise a [404 Not Found HTTP Error](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5) will be sent to the client instead.
|
||||
|
||||
> The [_examples/mvc](https://github.com/kataras/iris/tree/master/_examples/mvc) and [mvc/controller_test.go](https://github.com/kataras/iris/blob/master/mvc/controller_test.go) files explain each feature with simple paradigms, they show how you can take advandage of the Iris MVC Binder, Iris MVC Models and many more...
|
||||
|
||||
> The [_examples/mvc](https://github.com/kataras/iris/tree/master/_examples/mvc) and [mvc/controller_test.go](https://github.com/kataras/iris/blob/master/mvc/controller_test.go) files explain each feature with simple paradigms, they show how you can take advandage of the Iris MVC Binder, Iris MVC Models and more...
|
||||
|
||||
> For websocket controller go ahead to the [[Websockets]] chapter instead.
|
||||
> For gRPC controller go ahead to the [[gRPC]] chapter instead.
|
|
@ -1,9 +1,9 @@
|
|||
Iris, wisely, not features a builtin data validation. However, you are not limited. In this example we will learn how to use the [**go-playground/validator/v10**](https://github.com/go-playground/validator) for request values validation.
|
||||
Iris, wisely, not features a builtin data validation. However, it does allow you to attach a validator which will automatically called on methods like `Context.ReadJSON, ReadXML...`. In this example we will learn how to use the [**go-playground/validator/v10**](https://github.com/go-playground/validator) for request body validation.
|
||||
|
||||
Check the full docs on tags usage [here](https://pkg.go.dev/github.com/go-playground/validator/v10@v10.2.0?tab=doc).
|
||||
Check the full docs and the struct tags usage [here](https://pkg.go.dev/github.com/go-playground/validator/v10@v10.2.0?tab=doc).
|
||||
|
||||
```sh
|
||||
$ go get github.com/go-playground/validator/v10
|
||||
$ go get github.com/go-playground/validator/v10@latest
|
||||
```
|
||||
|
||||
Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`.
|
||||
|
@ -37,29 +37,26 @@ type Address struct {
|
|||
Phone string `json:"phone" validate:"required"`
|
||||
}
|
||||
|
||||
// Use a single instance of Validate, it caches struct info.
|
||||
var validate *validator.Validate
|
||||
|
||||
func main() {
|
||||
validate = validator.New()
|
||||
// Use a single instance of Validate, it caches struct info.
|
||||
v := validator.New()
|
||||
|
||||
// Register validation for 'User'
|
||||
// Register a custom struct validation for 'User'
|
||||
// NOTE: only have to register a non-pointer type for 'User', validator
|
||||
// internally dereferences during it's type checks.
|
||||
validate.RegisterStructValidation(UserStructLevelValidation, User{})
|
||||
v.RegisterStructValidation(UserStructLevelValidation, User{})
|
||||
|
||||
app := iris.New()
|
||||
// Register the validator to the Iris Application.
|
||||
app.Validator = v
|
||||
|
||||
app.Post("/user", func(ctx iris.Context) {
|
||||
var user User
|
||||
if err := ctx.ReadJSON(&user); err != nil {
|
||||
// [handle error...]
|
||||
}
|
||||
|
||||
// Returns InvalidValidationError for bad validation input,
|
||||
// nil or ValidationErrors ( []FieldError )
|
||||
err := validate.Struct(user)
|
||||
err := vctx.ReadJSON(&user)
|
||||
if err != nil {
|
||||
|
||||
// This check is only needed when your code could produce
|
||||
// an invalid value for validation such as interface with nil
|
||||
// value most including myself do not usually have code like this.
|
||||
|
@ -122,4 +119,4 @@ Example request of JSON form:
|
|||
}
|
||||
```
|
||||
|
||||
Example can be found at: <https://github.com/kataras/iris/tree/master/_examples/http_request/read-json-struct-validation/main.go>.
|
||||
Example can be found at: <https://github.com/kataras/iris/tree/master/_examples/request-body/read-json-struct-validation/main.go>.
|
||||
|
|
|
@ -4,7 +4,11 @@ Simply edit this wiki page and add your own in a list-based form.
|
|||
|
||||
---------------
|
||||
|
||||
- https://www.cedato.com/
|
||||
- https://www.cedato.com
|
||||
- https://github.com/peterq/pan-light
|
||||
- https://mlog.club
|
||||
- https://elta.ee
|
||||
- https://wzd.dev
|
||||
- https://anuncia.do
|
||||
- PUT YOUR PROJECT OR COMPANY HERE
|
||||
https://github.com/eltaline/ctrl
|
|
@ -1,5 +1,6 @@
|
|||
Prepare a cup of coffee or tea, whatever pleases you the most, and read some articles we found for you.
|
||||
|
||||
* [Go lang: MongoDB, Iris API](https://bit.ly/2TTtbYx)
|
||||
* [Golang Iris Web Course 2019](https://bit.ly/web-course-2019)
|
||||
* [How to write a Go API Part 1: A Webserver With Iris](https://bit.ly/32xmf4Q)
|
||||
* [How to write a Go API Part 2: Database Integration With GORM](https://bit.ly/34PvKxR)
|
||||
|
@ -21,9 +22,8 @@ Prepare a cup of coffee or tea, whatever pleases you the most, and read some art
|
|||
|
||||
| Description | Link | Author | Year |
|
||||
| -----------|-------------|-------------|-----|
|
||||
| Web Course | https://bit.ly/web-course-2019 | TechMaster | **2019** |
|
||||
| Quick Start with Iris | https://bit.ly/2wQIrJw | J-Secur1ty | **2019** |
|
||||
| Installing Iris | https://bit.ly/2KhgB1J | WarnabiruTV | 2018 |
|
||||
| Web Course | https://bit.ly/web-course-2019 | TechMaster | 2019 |
|
||||
| Quick Start with Iris | https://bit.ly/2wQIrJw | J-Secur1ty | 2019 |
|
||||
| Iris & Mongo DB Complete | https://bit.ly/2IcXZOu | Musobar Media | 2018 |
|
||||
| Getting Started with Iris | https://bit.ly/2XGafMv | stephgdesign | 2018 |
|
||||
|
||||
|
|
|
@ -103,4 +103,4 @@ app.Get("/save", func(ctx iris.Context) {
|
|||
})
|
||||
```
|
||||
|
||||
In addition to that, Iris provides a comprehensive API for **Transactions**. Learn more about it by running an [example](https://github.com/kataras/iris/blob/master/_examples/http_responsewriter/transactions/main.go).
|
||||
In addition to that, Iris provides a comprehensive API for **Transactions**. Learn more about it by running an [example](https://github.com/kataras/iris/blob/master/_examples/response-writer/transactions/main.go).
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
# Error handlers
|
||||
|
||||
You can define your own handlers when a specific http error code occurs.
|
||||
You can define your own handlers when a specific http error code occurs. Error handlers can be registered per `Party`.
|
||||
|
||||
Error codes are the http status codes that are bigger than or equal to 400, like 404 not found and 500 internal server error.
|
||||
|
||||
|
@ -13,13 +13,15 @@ import "github.com/kataras/iris/v12"
|
|||
|
||||
func main(){
|
||||
app := iris.New()
|
||||
app.RegisterView(iris.HTML("./views", ".html"))
|
||||
|
||||
app.OnErrorCode(iris.StatusNotFound, notFound)
|
||||
app.OnErrorCode(iris.StatusInternalServerError, internalServerError)
|
||||
// to register a handler for all "error"
|
||||
// status codes(kataras/iris/context.StatusCodeNotSuccessful)
|
||||
// defaults to < 200 || >= 400:
|
||||
// to register a handler for all error codes:
|
||||
// app.OnAnyErrorCode(handler)
|
||||
|
||||
app.Get("/", index)
|
||||
|
||||
app.Listen(":8080")
|
||||
}
|
||||
|
||||
|
@ -54,6 +56,18 @@ func index(ctx iris.Context) {
|
|||
|
||||
> Learn more about [[View]].
|
||||
|
||||
Iris has the `EnablePathIntelligence` option which can be passed to `app.Run/Listen` method to auto-redirect a not found path to its closest match one, e.g `"http://localhost:8080/contac"` to `"http://localhost:8080/contact"`. Enable it:
|
||||
|
||||
```go
|
||||
app.Listen(":8080", iris.WithPathIntelligence)
|
||||
```
|
||||
|
||||
You can also force all paths to be lowercased by setting the `ForceLowercaseRouting` option:
|
||||
|
||||
```go
|
||||
app.Listen(":8080", iris.WithLowercaseRouting, iris.WithPathIntelligence)
|
||||
```
|
||||
|
||||
## The Problem type
|
||||
|
||||
Iris has builtin support for the [Problem Details for HTTP APIs](https://tools.ietf.org/html/rfc7807).
|
||||
|
|
|
@ -124,9 +124,9 @@ Iris, unlike others, is 100% compatible with the standards and that's why the ma
|
|||
|
||||
Any third-party middleware that written for `net/http` is compatible with Iris using the `iris.FromStd(aThirdPartyMiddleware)`. Remember, `ctx.ResponseWriter()` and `ctx.Request()` returns the same `net/http` input arguments of an [http.Handler](https://golang.org/pkg/net/http/#Handler).
|
||||
|
||||
- [From func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)](convert-handlers/negroni-like/main.go)
|
||||
- [From http.Handler or http.HandlerFunc](convert-handlers/nethttp/main.go)
|
||||
- [From func(http.HandlerFunc) http.HandlerFunc](convert-handlers/real-usecase-raven/writing-middleware/main.go)
|
||||
- [From func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)](https://github.com/kataras/iris/tree/master/_examples/convert-handlers/negroni-like/main.go)
|
||||
- [From http.Handler or http.HandlerFunc](https://github.com/kataras/iris/tree/master/_examplesconvert-handlers/nethttp/main.go)
|
||||
- [From func(http.HandlerFunc) http.HandlerFunc](https://github.com/kataras/iris/tree/master/_examplesconvert-handlers/real-usecase-raven/writing-middleware/main.go)
|
||||
---------------------
|
||||
|
||||
Here is a list of some handlers made specifically for Iris:
|
||||
|
@ -135,26 +135,50 @@ Here is a list of some handlers made specifically for Iris:
|
|||
|
||||
| Middleware | Example |
|
||||
| -----------|-------------|
|
||||
| [basic authentication](https://github.com/kataras/iris/tree/master/middleware/basicauth) | [iris/_examples/authentication/basicauth](https://github.com/kataras/iris/tree/master/_examples/authentication/basicauth) |
|
||||
| [request logger](https://github.com/kataras/iris/tree/master/middleware/logger) | [iris/_examples/http_request/request-logger](https://github.com/kataras/iris/tree/master/_examples/http_request/request-logger) |
|
||||
| [basic authentication](https://github.com/kataras/iris/tree/master/middleware/basicauth) | [iris/_examples/auth/basicauth](https://github.com/kataras/iris/tree/master/_examples/auth/basicauth) |
|
||||
| [request logger](https://github.com/kataras/iris/tree/master/middleware/logger) | [iris/_examples/logging/request-logger](https://github.com/kataras/iris/tree/master/_examples/logging/request-logger) |
|
||||
| [HTTP method override](https://github.com/kataras/iris/tree/master/middleware/methodoverride) | [iris/middleware/methodoverride/methodoverride_test.go](https://github.com/kataras/iris/blob/master/middleware/methodoverride/methodoverride_test.go) |
|
||||
| [profiling (pprof)](https://github.com/kataras/iris/tree/master/middleware/pprof) | [iris/_examples/miscellaneous/pprof](https://github.com/kataras/iris/tree/master/_examples/miscellaneous/pprof) |
|
||||
| [Google reCAPTCHA](https://github.com/kataras/iris/tree/master/middleware/recaptcha) | [iris/_examples/miscellaneous/recaptcha](https://github.com/kataras/iris/tree/master/_examples/miscellaneous/recaptcha) |
|
||||
| [recovery](https://github.com/kataras/iris/tree/master/middleware/recover) | [iris/_examples/miscellaneous/recover](https://github.com/kataras/iris/tree/master/_examples/miscellaneous/recover) |
|
||||
| [profiling (pprof)](https://github.com/kataras/iris/tree/master/middleware/pprof) | [iris/_examples/pprof](https://github.com/kataras/iris/tree/master/_examples/pprof) |
|
||||
| [Google reCAPTCHA](https://github.com/kataras/iris/tree/master/middleware/recaptcha) | [iris/_examples/auth/recaptcha](https://github.com/kataras/iris/tree/master/_examples/auth/recaptcha) |
|
||||
| [hCaptcha](https://github.com/kataras/iris/tree/master/middleware/hcaptcha) | [iris/_examples/auth/recaptcha](https://github.com/kataras/iris/tree/master/_examples/auth/hcaptcha) |
|
||||
| [recovery](https://github.com/kataras/iris/tree/master/middleware/recover) | [iris/_examples/recover](https://github.com/kataras/iris/tree/master/_examples/recover) |
|
||||
| [rate](https://github.com/kataras/iris/tree/master/middleware/rate) | [iris/_examples/request-ratelimit](https://github.com/kataras/iris/tree/master/_examples/request-ratelimit) |
|
||||
| [jwt](https://github.com/kataras/iris/tree/master/middleware/jwt) | [iris/_examples/auth/jwt](https://github.com/kataras/iris/tree/master/_examples/auth/jwt) |
|
||||
| [requestid](https://github.com/kataras/iris/tree/master/middleware/requestid) | [iris/middleware/requestid/requestid_test.go](https://github.com/kataras/iris/blob/master/_examples/middleware/requestid/requestid_test.go) |
|
||||
|
||||
## Community made
|
||||
|
||||
Most of the experimental handlers are ported to work with _iris_'s handler form, from third-party sources.
|
||||
## Community
|
||||
|
||||
| Middleware | Description | Example |
|
||||
| -----------|--------|-------------|
|
||||
| [jwt](https://github.com/iris-contrib/middleware/tree/master/jwt) | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it. | [iris-contrib/middleware/jwt/_example](https://github.com/iris-contrib/middleware/tree/master/jwt/_example) |
|
||||
| [cors](https://github.com/iris-contrib/middleware/tree/master/cors) | HTTP Access Control. | [iris-contrib/middleware/cors/_example](https://github.com/iris-contrib/middleware/tree/master/cors/_example) |
|
||||
| [secure](https://github.com/iris-contrib/middleware/tree/master/secure) | Middleware that implements a few quick security wins. | [iris-contrib/middleware/secure/_example](https://github.com/iris-contrib/middleware/tree/master/secure/_example/main.go) |
|
||||
| [tollbooth](https://github.com/iris-contrib/middleware/tree/master/tollboothic) | Generic middleware to rate-limit HTTP requests. | [iris-contrib/middleware/tollbooth/_examples/limit-handler](https://github.com/iris-contrib/middleware/tree/master/tollbooth/_examples/limit-handler) |
|
||||
| [cloudwatch](https://github.com/iris-contrib/middleware/tree/master/cloudwatch) | AWS cloudwatch metrics middleware. |[iris-contrib/middleware/cloudwatch/_example](https://github.com/iris-contrib/middleware/tree/master/cloudwatch/_example) |
|
||||
| [new relic](https://github.com/iris-contrib/middleware/tree/master/newrelic) | Official [New Relic Go Agent](https://github.com/newrelic/go-agent). | [iris-contrib/middleware/newrelic/_example](https://github.com/iris-contrib/middleware/tree/master/newrelic/_example) |
|
||||
| [jwt](https://github.com/iris-contrib/middleware/tree/master/jwt) | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it | [iris-contrib/middleware/jwt/_example](https://github.com/iris-contrib/middleware/tree/master/jwt/_example) |
|
||||
| [cors](https://github.com/iris-contrib/middleware/tree/master/cors) | HTTP Access Control | [iris-contrib/middleware/cors/_example](https://github.com/iris-contrib/middleware/tree/master/cors/_example) |
|
||||
| [secure](https://github.com/iris-contrib/middleware/tree/master/secure) | Middleware that implements a few quick security wins | [iris-contrib/middleware/secure/_example](https://github.com/iris-contrib/middleware/tree/master/secure/_example/main.go) |
|
||||
| [tollbooth](https://github.com/iris-contrib/middleware/tree/master/tollboothic) | Generic middleware to rate-limit HTTP requests | [iris-contrib/middleware/tollboothic/_examples/limit-handler](https://github.com/iris-contrib/middleware/tree/master/tollboothic/_examples/limit-handler) |
|
||||
| [cloudwatch](https://github.com/iris-contrib/middleware/tree/master/cloudwatch) | AWS cloudwatch metrics middleware |[iris-contrib/middleware/cloudwatch/_example](https://github.com/iris-contrib/middleware/tree/master/cloudwatch/_example) |
|
||||
| [new relic](https://github.com/iris-contrib/middleware/tree/master/newrelic) | Official [New Relic Go Agent](https://github.com/newrelic/go-agent) | [iris-contrib/middleware/newrelic/_example](https://github.com/iris-contrib/middleware/tree/master/newrelic/_example) |
|
||||
| [prometheus](https://github.com/iris-contrib/middleware/tree/master/prometheus)| Easily create metrics endpoint for the [prometheus](http://prometheus.io) instrumentation tool | [iris-contrib/middleware/prometheus/_example](https://github.com/iris-contrib/middleware/tree/master/prometheus/_example) |
|
||||
| [casbin](https://github.com/iris-contrib/middleware/tree/master/casbin)| An authorization library that supports access control models like ACL, RBAC, ABAC | [iris-contrib/middleware/casbin/_examples](https://github.com/iris-contrib/middleware/tree/master/casbin/_examples) |
|
||||
| [raven](https://github.com/iris-contrib/middleware/tree/master/raven)| Sentry client in Go | [iris-contrib/middleware/raven/_example](https://github.com/iris-contrib/middleware/blob/master/raven/_example/main.go) |
|
||||
| [csrf](https://github.com/iris-contrib/middleware/tree/master/csrf)| Cross-Site Request Forgery Protection | [iris-contrib/middleware/csrf/_example](https://github.com/iris-contrib/middleware/blob/master/csrf/_example/main.go) |
|
||||
| [go-i18n](https://github.com/iris-contrib/middleware/tree/master/go-i18n)| i18n Iris Loader for nicksnyder/go-i18n | [iris-contrib/middleware/go-i18n/_example](https://github.com/iris-contrib/middleware/blob/master/go-i18n/_example/main.go) |
|
||||
| [throttler](https://github.com/iris-contrib/middleware/tree/master/throttler)| Rate limiting access to HTTP endpoints | [iris-contrib/middleware/throttler/_example](https://github.com/iris-contrib/middleware/blob/master/throttler/_example/main.go) |
|
||||
|
||||
## Third-Party
|
||||
|
||||
Iris has its own middleware form of `func(ctx iris.Context)` but it's also compatible with all `net/http` middleware forms. See [here](https://github.com/kataras/iris/tree/master/_examples/convert-handlers).
|
||||
|
||||
Here's a small list of useful third-party handlers:
|
||||
|
||||
| Middleware | Description |
|
||||
| -----------|-------------|
|
||||
| [goth](https://github.com/markbates/goth) | OAuth, OAuth2 authentication. [Example](https://github.com/kataras/iris/tree/master/_examples/auth/goth) |
|
||||
| [permissions2](https://github.com/xyproto/permissions2) | Cookies, users and permissions. [Example](https://github.com/kataras/iris/tree/master/_examples/auth/permissions) |
|
||||
| [csp](https://github.com/awakenetworks/csp) | [Content Security Policy](https://www.w3.org/TR/CSP2/) (CSP) support |
|
||||
| [delay](https://github.com/jeffbmartinez/delay) | Add delays/latency to endpoints. Useful when testing effects of high latency |
|
||||
| [onthefly](https://github.com/xyproto/onthefly) | Generate TinySVG, HTML and CSS on the fly |
|
||||
| [RestGate](https://github.com/pjebs/restgate) | Secure authentication for REST API endpoints |
|
||||
| [stats](https://github.com/thoas/stats) | Store information about your web application (response time, etc.) |
|
||||
| [VanGoH](https://github.com/auroratechnologies/vangoh) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC authentication middleware |
|
||||
| [digits](https://github.com/bamarni/digits) | Middleware that handles [Twitter Digits](https://get.digits.com/) authentication |
|
||||
|
||||
> Feel free to put up your own middleware in this list!
|
|
@ -49,12 +49,12 @@ func newApp() *iris.Application {
|
|||
ctx.HTML("<b>Resource Not found</b>")
|
||||
})
|
||||
|
||||
app.HandleDir("/", "./public")
|
||||
|
||||
app.Get("/profile/{username}", func(ctx iris.Context) {
|
||||
ctx.Writef("Hello %s", ctx.Params().Get("username"))
|
||||
})
|
||||
|
||||
app.HandleDir("/", "./public")
|
||||
|
||||
myOtherHandler := func(ctx iris.Context) {
|
||||
ctx.Writef("inside a handler which is fired manually by our custom router wrapper")
|
||||
}
|
||||
|
@ -71,8 +71,8 @@ func newApp() *iris.Application {
|
|||
if strings.HasPrefix(path, "/other") {
|
||||
// acquire and release a context in order to use it to execute
|
||||
// our custom handler
|
||||
// remember: we use net/http.Handler because here
|
||||
// we are in the "low-level", before the router itself.
|
||||
// remember: if you are going to call just a net/http middleware
|
||||
// then you DONT have to acquire and release the context here.
|
||||
ctx := app.ContextPool.Acquire(w, r)
|
||||
myOtherHandler(ctx)
|
||||
app.ContextPool.Release(ctx)
|
||||
|
|
|
@ -17,7 +17,7 @@ app.Get("/home", handler).SetLastMod(time.Now()).SetChangeFreq("hourly").SetPrio
|
|||
|
||||
> A static route is exposed on GET HTTP Method and its path does not contain a dynamic parameter. e.g. /home, /about but not /user/{id:uint64} and e.t.c.
|
||||
|
||||
See it in action, download and run the **example** from: https://github.com/kataras/iris/tree/master/_examples/sitemap
|
||||
See it in action, download and run the **example** from: https://github.com/kataras/iris/tree/master/_examples/routing/sitemap
|
||||
|
||||
If the application **is localized** then `iris.WithSitemap` will add `xhtml:link` XML elements to the sitemap file for each translation language as recommended at: https://support.google.com/webmasters/answer/189077?hl=en. Read more about it at the [[Localization]] section.
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
| Project | Description | Stars | Author |
|
||||
| --------|-------------|-------|--------|
|
||||
| [peterq/pan-light](https://bit.ly/33qfKlt) | Baidu network disk unlimited speed client, golang + qt5, cross-platform graphical interface | 9936 | @peterq |
|
||||
| [peterq/pan-light](https://bit.ly/33qfKlt) | Baidu network disk unlimited speed client, golang + qt5, cross-platform graphical interface | 10460 | @peterq |
|
||||
| [eltaline/wzd](https://github.com/eltaline/wzd) | wZD is a powerful storage and database server, designed for big data storage systems with small and large files for mixed use and dramatically reduces count of small files for extend abilities any normal or clustered POSIX compatible file systems | 68 | @eltaline |
|
||||
| [eltaline/ctrl](https://github.com/eltaline/ctrl) | cTRL is a server for remote execution of pending tasks and commands in real time, supporting a queue with continuous thread limiting and throttling | 2 | @eltaline |
|
||||
| [mlogclub/bbs-go](https://bit.ly/2PXcgmp) | Golang-based community system | 527 | @mlogclub |
|
||||
| [snowlyg/IrisApiProject](https://bit.ly/2IaL1R6) | Iris + gorm + JWT + sqlite3 | 359 | @snowlyg |
|
||||
| [mohuishou/scuplus-go](https://bit.ly/34H6Jol) | WeChat applet Backend API | 62 | @mohuishou |
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[[Home]] *|* [[About]] *|*
|
||||
[[Project|Project-and-community]] *|*
|
||||
[[Getting Started]] *|*
|
||||
[Technical Docs](https://godoc.org/github.com/kataras/iris) *|* Copyright © 2019 Gerasimos Maropoulos. [[Documentation terms of use|Documentation-terms-and-conditions]].
|
||||
[Technical Docs](https://godoc.org/github.com/kataras/iris) *|* Copyright © 2019-2020 Gerasimos Maropoulos. [[Documentation terms of use|Documentation-terms-and-conditions]].
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
* [[Websockets]]
|
||||
* [[Dependency Injection|Dependency-Injection]]
|
||||
* [[MVC]]
|
||||
* [[gRPC]]
|
||||
* [[Sitemap]]
|
||||
* [[Localization]]
|
||||
* [[Testing]]
|
||||
|
|
BIN
_assets/grpc-compatible-question.png
Normal file
BIN
_assets/grpc-compatible-question.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
Binary file not shown.
Before Width: | Height: | Size: 73 KiB |
Binary file not shown.
Before Width: | Height: | Size: 208 KiB |
Binary file not shown.
Before Width: | Height: | Size: 257 KiB |
|
@ -1,46 +1,350 @@
|
|||
The subpackage [hero](https://github.com/kataras/iris/tree/master/hero) contains features for binding any object or function that handlers can accept on their input arguments, these are called dependencies.
|
||||
Iris provides first-class support for dependency injection through request handlers and server replies based on return value(s).
|
||||
|
||||
A dependency can be either `Static` for things like Services or `Dynamic` for values that depend on the incoming request.
|
||||
## Dependency Injection
|
||||
|
||||
With Iris you get truly safe bindings. It is blazing-fast, near to raw handlers performance because Iris tries to calculates everything before the server even goes online!
|
||||
With Iris you get truly safe bindings. It is blazing-fast, near to raw handlers performance because we pre-allocates necessary information before the server even goes online!
|
||||
|
||||
Iris provides built-in dependencies to match route's parameters with func input arguments that you can use right away.
|
||||
A dependency can be either a function or a static value. A function dependency can accept a previously registered dependency as its input argument too.
|
||||
|
||||
To use this feature you should import the hero subpackage:
|
||||
Example Code:
|
||||
|
||||
```go
|
||||
import (
|
||||
// [...]
|
||||
"github.com/kataras/iris/v12/hero"
|
||||
func printFromTo(from, to string) string { return "message" }
|
||||
|
||||
// [...]
|
||||
app.ConfigureContainer(func (api *iris.APIContainer){
|
||||
api.Get("/{from}/{to}", printFromTo)
|
||||
})
|
||||
```
|
||||
|
||||
As you've seen above the `iris.Context` input argument is totally optional. Iris is smart enough to bind it as well without any hassle.
|
||||
|
||||
### Overview
|
||||
|
||||
The most common scenario from a route to handle is to:
|
||||
- accept one or more path parameters and request data, a payload
|
||||
- send back a response, a payload (JSON, XML,...)
|
||||
|
||||
The new Iris Dependency Injection feature is about **33.2% faster** than its predecessor on the above case. This drops down even more the performance cost between native handlers and handlers with dependencies. This reason itself brings us, with safety and performance-wise, to the new `Party.ConfigureContainer(builder ...func(*iris.APIContainer)) *APIContainer` method which returns methods such as `Handle(method, relativePath string, handlersFn ...interface{}) *Route` and `RegisterDependency`.
|
||||
|
||||
Look how clean your codebase can be when using Iris':
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/kataras/iris/v12"
|
||||
|
||||
type (
|
||||
testInput struct {
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
testOutput struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
)
|
||||
|
||||
func handler(id int, in testInput) testOutput {
|
||||
return testOutput{
|
||||
ID: id,
|
||||
Name: in.Email,
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
app.ConfigureContainer(func(api *iris.APIContainer) {
|
||||
api.Post("/{id:int}", handler)
|
||||
})
|
||||
app.Listen(":5000", iris.WithOptimizations)
|
||||
}
|
||||
```
|
||||
|
||||
Your eyes don't lie you. You read well, no `ctx.ReadJSON(&v)` and `ctx.JSON(send)` neither `error` handling are presented. It is a huge relief but if you ever need, you still have the control over those, even errors from dependencies. Here is a quick list of the new `Party.ConfigureContainer`()'s fields and methods:
|
||||
|
||||
```go
|
||||
// Container holds the DI Container of this Party featured Dependency Injection.
|
||||
// Use it to manually convert functions or structs(controllers) to a Handler.
|
||||
Container *hero.Container
|
||||
```
|
||||
|
||||
```go
|
||||
// OnError adds an error handler for this Party's DI Hero Container and its handlers (or controllers).
|
||||
// The "errorHandler" handles any error may occurred and returned
|
||||
// during dependencies injection of the Party's hero handlers or from the handlers themselves.
|
||||
OnError(errorHandler func(iris.Context, error))
|
||||
```
|
||||
|
||||
```go
|
||||
// RegisterDependency adds a dependency.
|
||||
// The value can be a single struct value or a function.
|
||||
// Follow the rules:
|
||||
// * <T> {structValue}
|
||||
// * func(accepts <T>) returns <D> or (<D>, error)
|
||||
// * func(accepts iris.Context) returns <D> or (<D>, error)
|
||||
//
|
||||
// A Dependency can accept a previous registered dependency and return a new one or the same updated.
|
||||
// * func(accepts1 <D>, accepts2 <T>) returns <E> or (<E>, error) or error
|
||||
// * func(acceptsPathParameter1 string, id uint64) returns <T> or (<T>, error)
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// - RegisterDependency(loggerService{prefix: "dev"})
|
||||
// - RegisterDependency(func(ctx iris.Context) User {...})
|
||||
// - RegisterDependency(func(User) OtherResponse {...})
|
||||
RegisterDependency(dependency interface{})
|
||||
|
||||
// UseResultHandler adds a result handler to the Container.
|
||||
// A result handler can be used to inject the returned struct value
|
||||
// from a request handler or to replace the default renderer.
|
||||
UseResultHandler(handler func(next iris.ResultHandler) iris.ResultHandler)
|
||||
```
|
||||
|
||||
<details><summary>ResultHandler</summary>
|
||||
|
||||
```go
|
||||
type ResultHandler func(ctx iris.Context, v interface{}) error
|
||||
```
|
||||
</details>
|
||||
|
||||
```go
|
||||
// Use same as a common Party's "Use" but it accepts dynamic functions as its "handlersFn" input.
|
||||
Use(handlersFn ...interface{})
|
||||
// Done same as a common Party's but it accepts dynamic functions as its "handlersFn" input.
|
||||
Done(handlersFn ...interface{})
|
||||
```
|
||||
|
||||
```go
|
||||
// Handle same as a common Party's `Handle` but it accepts one or more "handlersFn" functions which each one of them
|
||||
// can accept any input arguments that match with the Party's registered Container's `Dependencies` and
|
||||
// any output result; like custom structs <T>, string, []byte, int, error,
|
||||
// a combination of the above, hero.Result(hero.View | hero.Response) and more.
|
||||
//
|
||||
// It's common from a hero handler to not even need to accept a `Context`, for that reason,
|
||||
// the "handlersFn" will call `ctx.Next()` automatically when not called manually.
|
||||
// To stop the execution and not continue to the next "handlersFn"
|
||||
// the end-developer should output an error and return `iris.ErrStopExecution`.
|
||||
Handle(method, relativePath string, handlersFn ...interface{}) *Route
|
||||
|
||||
// Get registers a GET route, same as `Handle("GET", relativePath, handlersFn....)`.
|
||||
Get(relativePath string, handlersFn ...interface{}) *Route
|
||||
// and so on...
|
||||
```
|
||||
|
||||
Here is a list of the built-in dependencies that can be used right away as input parameters:
|
||||
|
||||
| Type | Maps To |
|
||||
|------|:---------|
|
||||
| [*mvc.Application](https://pkg.go.dev/github.com/kataras/iris/v12/mvc?tab=doc#Application) | Current MVC Application |
|
||||
| [iris.Context](https://pkg.go.dev/github.com/kataras/iris/v12/context?tab=doc#Context) | Current Iris Context |
|
||||
| [*sessions.Session](https://pkg.go.dev/github.com/kataras/iris/v12/sessions?tab=doc#Session) | Current Iris Session |
|
||||
| [context.Context](https://golang.org/pkg/context/#Context) | [ctx.Request().Context()](https://golang.org/pkg/net/http/#Request.Context) |
|
||||
| [*http.Request](https://golang.org/pkg/net/http/#Request) | `ctx.Request()` |
|
||||
| [http.ResponseWriter](https://golang.org/pkg/net/http/#ResponseWriter) | `ctx.ResponseWriter()` |
|
||||
| [http.Header](https://golang.org/pkg/net/http/#Header) | `ctx.Request().Header` |
|
||||
| [time.Time](https://golang.org/pkg/time/#Time) | `time.Now()` |
|
||||
| `string`, | |
|
||||
| `int, int8, int16, int32, int64`, | |
|
||||
| `uint, uint8, uint16, uint32, uint64`, | |
|
||||
| `float, float32, float64`, | |
|
||||
| `bool`, | |
|
||||
| `slice` | [Path Parameter](https://github.com/kataras/iris/wiki/Routing-path-parameter-types) |
|
||||
| Struct | [Request Body](https://github.com/kataras/iris/tree/master/_examples/request-body) of `JSON`, `XML`, `YAML`, `Form`, `URL Query`, `Protobuf`, `MsgPack` |
|
||||
|
||||
### Request & Response & Path Parameters
|
||||
|
||||
**1.** Declare Go types for client's request body and a server's response.
|
||||
|
||||
```go
|
||||
type (
|
||||
request struct {
|
||||
Firstname string `json:"firstname"`
|
||||
Lastname string `json:"lastname"`
|
||||
}
|
||||
|
||||
response struct {
|
||||
ID uint64 `json:"id"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
And use its `hero.Handler` package-level function to build a handler from a function that can accept dependencies and send response from its output, like this:
|
||||
**2.** Create the route handler.
|
||||
|
||||
Path parameters and request body are binded automatically.
|
||||
- **id uint64** binds to "id:uint64"
|
||||
- **input request** binds to client request data such as JSON
|
||||
|
||||
```go
|
||||
func printFromTo(from, to string) string { /* [...]*/ }
|
||||
|
||||
// [...]
|
||||
app.Get("/{from}/{to}", hero.Handler(printFromTo))
|
||||
func updateUser(id uint64, input request) response {
|
||||
return response{
|
||||
ID: id,
|
||||
Message: "User updated successfully",
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As you've seen above the `iris.Context` input argument is totally optional. Of course you can still declare it as **first input argument** - Iris is smart enough to bind it as well without any hassle.
|
||||
**3.** Configure the container per group and register the route.
|
||||
|
||||
Below you will see some screenshots designed to facilitate your understanding:
|
||||
```go
|
||||
app.Party("/user").ConfigureContainer(container)
|
||||
|
||||
## 1. Path Parameters - Built-in Dependencies
|
||||
func container(api *iris.APIContainer) {
|
||||
api.Put("/{id:uint64}", updateUser)
|
||||
}
|
||||
```
|
||||
|
||||
[[_assets/hero-1-monokai.png]]
|
||||
**4.** Simulate a [client](https://curl.haxx.se/download.html) request which sends data to the server and displays the response.
|
||||
|
||||
## 2. Services - Static Dependencies
|
||||
```sh
|
||||
curl --request PUT -d '{"firstanme":"John","lastname":"Doe"}' http://localhost:8080/user/42
|
||||
```
|
||||
|
||||
[[_assets/hero-2-monokai.png]]
|
||||
```json
|
||||
{
|
||||
"id": 42,
|
||||
"message": "User updated successfully"
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Per-Request - Dynamic Dependencies
|
||||
### Custom Preflight
|
||||
|
||||
[[_assets/hero-3-monokai.png]]
|
||||
Before we continue to the next section, register dependencies, you may want to learn how a response can be customized through the `iris.Context` right before sent to the client.
|
||||
|
||||
In addition the hero subpackage adds support to send responses through the **output values** of a function, for example:
|
||||
The server will automatically execute the `Preflight(iris.Context) error` method of a function's output struct value right before send the response to the client.
|
||||
|
||||
Take for example that you want to fire different HTTP status codes depending on the custom logic inside your handler and also modify the value(response body) itself before sent to the client. Your response type should contain a `Preflight` method like below.
|
||||
|
||||
```go
|
||||
type response struct {
|
||||
ID uint64 `json:"id,omitempty"`
|
||||
Message string `json:"message"`
|
||||
Code int `json:"code"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
}
|
||||
|
||||
func (r *response) Preflight(ctx iris.Context) error {
|
||||
if r.ID > 0 {
|
||||
r.Timestamp = time.Now().Unix()
|
||||
}
|
||||
|
||||
ctx.StatusCode(r.Code)
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
Now, each handler that returns a `*response` value will call the `response.Preflight` method automatically.
|
||||
|
||||
```go
|
||||
func deleteUser(db *sql.DB, id uint64) *response {
|
||||
// [...custom logic]
|
||||
|
||||
return &response{
|
||||
Message: "User has been marked for deletion",
|
||||
Code: iris.StatusAccepted,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you register the route and fire a request you should see an output like this, the timestamp is filled and the HTTP status code of the response that the client will receive is 202 (Status Accepted).
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "User has been marked for deletion",
|
||||
"code": 202,
|
||||
"timestamp": 1583313026
|
||||
}
|
||||
```
|
||||
|
||||
### Register Dependencies
|
||||
|
||||
**1.** Import packages to interact with a database.
|
||||
The go-sqlite3 package is a database driver for [SQLite](https://www.sqlite.org/index.html).
|
||||
|
||||
```go
|
||||
import "database/sql"
|
||||
import _ "github.com/mattn/go-sqlite3"
|
||||
```
|
||||
|
||||
**2.** Configure the container ([see above](#request--response--path-parameters)), register your dependencies. Handler expects an *sql.DB instance.
|
||||
|
||||
```go
|
||||
localDB, _ := sql.Open("sqlite3", "./foo.db")
|
||||
api.RegisterDependency(localDB)
|
||||
```
|
||||
|
||||
**3.** Register a route to create a user.
|
||||
|
||||
```go
|
||||
api.Post("/{id:uint64}", createUser)
|
||||
```
|
||||
|
||||
**4.** The create user Handler.
|
||||
|
||||
The handler accepts a database and some client request data such as JSON, Protobuf, Form, URL Query and e.t.c. It Returns a response.
|
||||
|
||||
```go
|
||||
func createUser(db *sql.DB, user request) *response {
|
||||
// [custom logic using the db]
|
||||
userID, err := db.CreateUser(user)
|
||||
if err != nil {
|
||||
return &response{
|
||||
Message: err.Error(),
|
||||
Code: iris.StatusInternalServerError,
|
||||
}
|
||||
}
|
||||
|
||||
return &response{
|
||||
ID: userID,
|
||||
Message: "User created",
|
||||
Code: iris.StatusCreated,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**5.** Simulate a [client](https://curl.haxx.se/download.html) to create a user.
|
||||
|
||||
```sh
|
||||
# JSON
|
||||
curl --request POST -d '{"firstname":"John","lastname":"Doe"}' \
|
||||
--header 'Content-Type: application/json' \
|
||||
http://localhost:8080/user
|
||||
```
|
||||
|
||||
```sh
|
||||
# Form (multipart)
|
||||
curl --request POST 'http://localhost:8080/users' \
|
||||
--header 'Content-Type: multipart/form-data' \
|
||||
--form 'firstname=John' \
|
||||
--form 'lastname=Doe'
|
||||
```
|
||||
|
||||
```sh
|
||||
# Form (URL-encoded)
|
||||
curl --request POST 'http://localhost:8080/users' \
|
||||
--header 'Content-Type: application/x-www-form-urlencoded' \
|
||||
--data-urlencode 'firstname=John' \
|
||||
--data-urlencode 'lastname=Doe'
|
||||
```
|
||||
|
||||
```sh
|
||||
# URL Query
|
||||
curl --request POST 'http://localhost:8080/users?firstname=John&lastname=Doe'
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 42,
|
||||
"message": "User created",
|
||||
"code": 201,
|
||||
"timestamp": 1583313026
|
||||
}
|
||||
```
|
||||
|
||||
## Return values
|
||||
|
||||
- if the return value is `string` then it will send that string as the response's body.
|
||||
- If it's an `int` then it will send it as a status code.
|
||||
|
@ -49,34 +353,49 @@ In addition the hero subpackage adds support to send responses through the **out
|
|||
- If it's a custom `struct` then it sent as a JSON, when a Content-Type header is not already set.
|
||||
- If it's a custom `struct` and a `string` then the second output value, string, it will be the Content-Type and so on.
|
||||
|
||||
```go
|
||||
func myHandler(...dependencies) string |
|
||||
(string, string) |
|
||||
(string, int) |
|
||||
int |
|
||||
(int, string) |
|
||||
(string, error) |
|
||||
error |
|
||||
(int, error) |
|
||||
(any, bool) |
|
||||
(customStruct, error) |
|
||||
customStruct |
|
||||
(customStruct, int) |
|
||||
(customStruct, string) |
|
||||
hero.Result |
|
||||
(hero.Result, error) {
|
||||
return a_response
|
||||
}
|
||||
```
|
||||
| Type | Replies to |
|
||||
|------|:---------|
|
||||
| string | body |
|
||||
| string, string | content-type, body |
|
||||
| string, int | body, status code |
|
||||
| int | status code |
|
||||
| int, string | status code, body |
|
||||
| error | if not nil, bad request |
|
||||
| any, bool | if false then fires not found |
|
||||
| <Τ> | JSON body |
|
||||
| <Τ>, string | body, content-type |
|
||||
| <Τ>, error | JSON body or bad request |
|
||||
| <Τ>, int | JSON body, status code |
|
||||
| [Result](https://godoc.org/github.com/kataras/iris/hero#Result) | calls its `Dispatch` method |
|
||||
| [PreflightResult](https://godoc.org/github.com/kataras/iris/hero#PreflightResult) | calls its `Preflight` method |
|
||||
|
||||
The `hero.Result` is an interface which help custom structs to be rendered using custom logic through their `Dispatch(ctx iris.Context)`.
|
||||
> Where `<T>` means any struct value.
|
||||
|
||||
```go
|
||||
type Result interface {
|
||||
Dispatch(ctx iris.Context)
|
||||
type response struct {
|
||||
ID uint64 `json:"id,omitempty"`
|
||||
Message string `json:"message"`
|
||||
Code int `json:"code"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
}
|
||||
|
||||
func (r *response) Preflight(ctx iris.Context) error {
|
||||
if r.ID > 0 {
|
||||
r.Timestamp = time.Now().Unix()
|
||||
}
|
||||
|
||||
ctx.StatusCode(r.Code)
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteUser(db *sql.DB, id uint64) *response {
|
||||
// [...custom logic]
|
||||
|
||||
return &response{
|
||||
Message: "User has been marked for deletion",
|
||||
Code: iris.StatusAccepted,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Honestly, `hero funcs` are very easy to understand and when you start using them **you never go back**.
|
||||
|
||||
Later on you'll see how this knowledge will help you to craft an application using the MVC architectural pattern which Iris provides wonderful API for it.
|
||||
|
|
Loading…
Reference in New Issue
Block a user